diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/TypedTableGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/TypedTableGrid.java
index effed877c22de73ba4ff37f57590157b52a2020a..fcb4c744595d281c0320a5134aa95822ebd219de 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/TypedTableGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/TypedTableGrid.java
@@ -132,7 +132,7 @@ public abstract class TypedTableGrid<T extends ISerializable>
                 EntityTableCell entityTableCell = (EntityTableCell) value;
                 if (entityTableCell.isMissing())
                 {
-                    return null; 
+                    return null;
                 }
                 String permId = entityTableCell.getPermId();
                 if (entityTableCell.getEntityKind() == EntityKind.MATERIAL)
@@ -461,4 +461,15 @@ public abstract class TypedTableGrid<T extends ISerializable>
     {
         refreshGridSilently();
     }
+
+    protected List<T> getContainedGridElements()
+    {
+        List<TableModelRowWithObject<T>> wrappedElements = super.getGridElements();
+        List<T> elements = new ArrayList<T>();
+        for (TableModelRowWithObject<T> wrappedElement : wrappedElements)
+        {
+            elements.add(wrappedElement.getObjectOrNull());
+        }
+        return elements;
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
index 2db04b7e09e25d86b5a9bc90bb83bde5a7133e34..0fd0f1ff1a57a5f2154693721fdccad240abde7f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractBrowserGrid.java
@@ -435,9 +435,15 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
         grid.getSelectionModel().setSelectionMode(SelectionMode.MULTI);
     }
 
-    protected final List<M> getGridModels()
+    protected List<T> getGridElements()
     {
-        return grid.getStore().getModels();
+        List<M> models = grid.getStore().getModels();
+        List<T> elements = new ArrayList<T>();
+        for (M model : models)
+        {
+            elements.add(model.getBaseObject());
+        }
+        return elements;
     }
 
     private IDelegatedAction createApplyFiltersDelagator()
@@ -490,15 +496,23 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
         final LayoutContainer subContainer = new LayoutContainer();
         subContainer.setLayout(new RowLayout(Orientation.HORIZONTAL));
         subContainer.add(tree, new RowData(300, 1));
+        setHeader(headerOrNull);
+        subContainer.add(this, new RowData(1, 1));
+        container.add(subContainer, new RowData(1, 1));
+
+        return asDisposableEntityChooser(container, toolbar);
+    }
+
+    protected final void setHeader(String headerOrNull)
+    {
         if (headerOrNull != null)
         {
             this.contentPanel.setHeaderVisible(true);
             this.contentPanel.setHeading(headerOrNull);
+        } else
+        {
+            this.contentPanel.setHeaderVisible(false);
         }
-        subContainer.add(this, new RowData(1, 1));
-        container.add(subContainer, new RowData(1, 1));
-
-        return asDisposableEntityChooser(container, toolbar);
     }
 
     private DisposableEntityChooser<T> asDisposableEntityChooser(final Component mainComponent,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyTermGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyTermGrid.java
index c06f347ea69ecd5af5710099d79b5494b5699067..a24f82ddec373bd1898d70ee56ef8ab8baba6f50 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyTermGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyTermGrid.java
@@ -660,9 +660,9 @@ public class VocabularyTermGrid extends TypedTableGrid<VocabularyTermWithStats>
     private List<VocabularyTerm> getTerms()
     {
         List<VocabularyTerm> terms = new ArrayList<VocabularyTerm>();
-        for (BaseEntityModel<TableModelRowWithObject<VocabularyTermWithStats>> model : getGridModels())
+        for (VocabularyTermWithStats v : getContainedGridElements())
         {
-            terms.add(model.getBaseObject().getObjectOrNull().getTerm());
+            terms.add(v.getTerm());
         }
         return terms;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/MaterialGridColumnIDs.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/MaterialGridColumnIDs.java
new file mode 100644
index 0000000000000000000000000000000000000000..312596721fff11b908005d18f7f7839633a7ea53
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/MaterialGridColumnIDs.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011 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.dto;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
+
+/**
+ * Columns of a grid which shows {@link Material} rows.
+ * 
+ * @author Tomasz Pylak
+ */
+public class MaterialGridColumnIDs
+{
+    public static final String CODE = "CODE";
+
+    public static final String REGISTRATOR = "REGISTRATOR";
+
+    public static final String REGISTRATION_DATE = "REGISTRATION_DATE";
+
+    public static final String MATERIAL_TYPE = "MATERIAL_TYPE";
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/AbstractTableModelProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/AbstractTableModelProvider.java
index b6007c3616b2b65438abdedef7f0d1ff0cca95a8..4ef63c7d91b44e07a071d73a2903e8b0dfc0ee86 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/AbstractTableModelProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/AbstractTableModelProvider.java
@@ -33,9 +33,14 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TypedTableModel;
 public abstract class AbstractTableModelProvider<T extends ISerializable> implements
         ITableModelProvider<T>
 {
+
+    /**
+     * Creates the table model with the specified maximum number of rows. If
+     * {@link Integer#MAX_VALUE} is specified the complete table will be created.
+     */
     public TypedTableModel<T> getTableModel(int maxSize)
     {
-        TypedTableModel<T> tableModel = createTableModel(maxSize);
+        TypedTableModel<T> tableModel = createTableModel(Integer.MAX_VALUE);
         List<TableModelColumnHeader> headers = tableModel.getHeader();
         List<TableModelRowWithObject<T>> rows = tableModel.getRows();
         List<TableModelRowWithObject<T>> limitedRows = new ArrayList<TableModelRowWithObject<T>>();
@@ -51,8 +56,8 @@ public abstract class AbstractTableModelProvider<T extends ISerializable> implem
     }
 
     /**
-     * Creates the table model with the specified maximum number of rows. If
-     * {@link Integer#MAX_VALUE} is specified the complete table will be created.
+     * Creates the complete table model.
+     * @param maxSize TODO
      */
     protected abstract TypedTableModel<T> createTableModel(int maxSize);
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/MatchingEntitiesProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/MatchingEntitiesProvider.java
index 32e1cdc4cc1cd2d5b4c29702f141ce87e1ddca07..e3edc4415da5bfcf85638309a52cd175c5f701cd 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/MatchingEntitiesProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/MatchingEntitiesProvider.java
@@ -32,32 +32,38 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SearchableEntity;
 import ch.systemsx.cisd.openbis.generic.shared.util.TypedTableModelBuilder;
 
 /**
- * 
- *
  * @author Franz-Josef Elmer
  */
-public class MatchingEntitiesProvider extends AbstractCommonTableModelProvider<MatchingEntity>
+public class MatchingEntitiesProvider implements ITableModelProvider<MatchingEntity>
 {
+    private final ICommonServer commonServer;
+
+    private final String sessionToken;
+
     private final SearchableEntity[] matchingEntities;
+
     private final String queryText;
+
     private final boolean useWildcardSearchMode;
 
     public MatchingEntitiesProvider(ICommonServer commonServer, String sessionToken,
             SearchableEntity[] matchingEntities, String queryText, boolean useWildcardSearchMode)
     {
-        super(commonServer, sessionToken);
+        this.commonServer = commonServer;
+        this.sessionToken = sessionToken;
+
         this.matchingEntities = matchingEntities;
         this.queryText = queryText;
         this.useWildcardSearchMode = useWildcardSearchMode;
     }
 
-    @Override
-    protected TypedTableModel<MatchingEntity> createTableModel(int maxSize)
+    public TypedTableModel<MatchingEntity> getTableModel(int maxSize)
     {
         List<MatchingEntity> entities =
-            commonServer.listMatchingEntities(sessionToken, matchingEntities, queryText,
-                    useWildcardSearchMode, maxSize);
-        TypedTableModelBuilder<MatchingEntity> builder = new TypedTableModelBuilder<MatchingEntity>();
+                commonServer.listMatchingEntities(sessionToken, matchingEntities, queryText,
+                        useWildcardSearchMode, maxSize);
+        TypedTableModelBuilder<MatchingEntity> builder =
+                new TypedTableModelBuilder<MatchingEntity>();
         builder.addColumn(ENTITY_KIND);
         builder.addColumn(ENTITY_TYPE);
         builder.addColumn(IDENTIFIER).withDefaultWidth(140);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/MaterialProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/MaterialProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..8764597a1ebb357b22ad094ba63f7b0ae556bb39
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/MaterialProvider.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011 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.server.resultset;
+
+import static ch.systemsx.cisd.openbis.generic.client.web.client.dto.MaterialGridColumnIDs.CODE;
+import static ch.systemsx.cisd.openbis.generic.client.web.client.dto.MaterialGridColumnIDs.MATERIAL_TYPE;
+import static ch.systemsx.cisd.openbis.generic.client.web.client.dto.MaterialGridColumnIDs.REGISTRATION_DATE;
+import static ch.systemsx.cisd.openbis.generic.client.web.client.dto.MaterialGridColumnIDs.REGISTRATOR;
+
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TypedTableModel;
+import ch.systemsx.cisd.openbis.generic.shared.util.TypedTableModelBuilder;
+
+/**
+ * Table model provider of {@link Material} instances.
+ * 
+ * @author Tomasz Pylak
+ */
+public class MaterialProvider extends AbstractTableModelProvider<Material>
+{
+    private static final String PROPERTIES_GROUP = "property-";
+
+    private final List<Material> materials;
+
+    public MaterialProvider(List<Material> materials)
+    {
+        this.materials = materials;
+    }
+
+    @Override
+    protected TypedTableModel<Material> createTableModel(int maxSize)
+    {
+
+        TypedTableModelBuilder<Material> builder = new TypedTableModelBuilder<Material>();
+        addStandardColumns(builder);
+
+        for (Material material : materials)
+        {
+            addRow(builder, material);
+        }
+        return builder.getModel();
+    }
+
+    private void addStandardColumns(TypedTableModelBuilder<Material> builder)
+    {
+        builder.addColumn(CODE);
+        builder.addColumn(MATERIAL_TYPE);
+        builder.addColumn(REGISTRATION_DATE).withDefaultWidth(300).hideByDefault();
+        builder.addColumn(REGISTRATOR).withDefaultWidth(200).hideByDefault();
+    }
+
+    private void addRow(TypedTableModelBuilder<Material> builder, Material material)
+    {
+        builder.addRow(material);
+        builder.column(CODE).addString(material.getCode());
+        builder.column(MATERIAL_TYPE).addString(material.getEntityType().getCode());
+        builder.column(REGISTRATION_DATE).addDate(material.getRegistrationDate());
+        builder.column(REGISTRATOR).addPerson(material.getRegistrator());
+
+        builder.columnGroup(PROPERTIES_GROUP).addProperties(material.getProperties());
+    }
+}
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ProteinSequenceProviderTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ProteinSequenceProviderTest.java
index 04459e7915b657476a7efcc62cddaa8aa3c81fca..85c89b769570e3d0e527def7edbd4ee96c440691 100644
--- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ProteinSequenceProviderTest.java
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ProteinSequenceProviderTest.java
@@ -52,7 +52,7 @@ public class ProteinSequenceProviderTest extends AbstractProviderTest
         ProteinSequenceProvider provider =
                 new ProteinSequenceProvider(phosphonetxServer, SESSION_TOKEN, new TechId(42));
 
-        TypedTableModel<ProteinSequence> model = provider.createTableModel(10);
+        TypedTableModel<ProteinSequence> model = provider.createTableModel(Integer.MAX_VALUE);
 
         assertEquals("[SEQUENCE_SHORT_NAME, DATABASE_NAME_AND_VERSION, SEQUENCE]", getHeaderIDs(model).toString());
         assertEquals("[VARCHAR, VARCHAR, VARCHAR]", getHeaderDataTypes(model).toString());
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ProteinSummaryProviderTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ProteinSummaryProviderTest.java
index 7ea01c1ed4347cf7c2a6452a9bebfbb4b129d71c..e98a8c3b3ea92d793a5f2fb9a01e066d6333865b 100644
--- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ProteinSummaryProviderTest.java
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/client/web/server/resultset/ProteinSummaryProviderTest.java
@@ -51,7 +51,7 @@ public class ProteinSummaryProviderTest extends AbstractProviderTest
         ProteinSummaryProvider provider =
                 new ProteinSummaryProvider(phosphonetxServer, SESSION_TOKEN, new TechId(12));
 
-        TypedTableModel<ProteinSummary> model = provider.createTableModel(10);
+        TypedTableModel<ProteinSummary> model = provider.createTableModel(Integer.MAX_VALUE);
 
         assertEquals("[FDR, PROTEIN_COUNT, PEPTIDE_COUNT]", getHeaderIDs(model).toString());
         assertEquals("[REAL, INTEGER, INTEGER]", getHeaderDataTypes(model).toString());
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/IScreeningClientService.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/IScreeningClientService.java
index 6266ed1ab608141ad499dfd187d7dff00ee02816..18ac635f19f7a98c2785dfc975be70c2bc39ab13 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/IScreeningClientService.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/IScreeningClientService.java
@@ -100,10 +100,23 @@ public interface IScreeningClientService extends IClientService
             IResultSetConfig<String, TableModelRowWithObject<WellContent>> gridCriteria,
             WellSearchCriteria materialCriteria) throws UserFailureException;
 
-    public String prepareExportPlateLocations(
+    public String prepareExportPlateWells(
             TableExportCriteria<TableModelRowWithObject<WellContent>> criteria)
             throws UserFailureException;
 
+    /**
+     * @return materials with codes or properties matching to the query. If the experiment is
+     *         specified, only materials inside well locations connected through the plate to this
+     *         specified experiment(s) will be returned.
+     */
+    public TypedTableResultSet<Material> listMaterials(
+            IResultSetConfig<String, TableModelRowWithObject<Material>> gridCriteria,
+            WellSearchCriteria materialCriteria) throws UserFailureException;
+
+    public String prepareExportMaterials(
+            TableExportCriteria<TableModelRowWithObject<Material>> criteria)
+            throws UserFailureException;
+
     /**
      * Returns {@link TypedTableResultSet} containing plate metadata.
      */
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/IScreeningClientServiceAsync.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/IScreeningClientServiceAsync.java
index 356f115eb3abcc9771fc2ceaeac4ff3a2c6b1dff..0d7ce9d61d0c28d60941f0833a23432e901f2dc7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/IScreeningClientServiceAsync.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/IScreeningClientServiceAsync.java
@@ -84,12 +84,27 @@ public interface IScreeningClientServiceAsync extends IClientServiceAsync
             AsyncCallback<TypedTableResultSet<WellContent>> callback);
 
     /**
-     * @see IScreeningClientService#prepareExportPlateLocations(TableExportCriteria)
+     * @see IScreeningClientService#prepareExportPlateWells(TableExportCriteria)
      */
-    public void prepareExportPlateLocations(
+    public void prepareExportPlateWells(
             TableExportCriteria<TableModelRowWithObject<WellContent>> criteria,
             AsyncCallback<String> callback);
 
+    /**
+     * @see IScreeningClientService#listMaterials(IResultSetConfig, WellSearchCriteria)
+     */
+    public void listMaterials(
+            IResultSetConfig<String, TableModelRowWithObject<Material>> gridCriteria,
+            WellSearchCriteria materialCriteria,
+            AsyncCallback<TypedTableResultSet<Material>> callback);
+
+    /**
+     * @see IScreeningClientService#prepareExportMaterials(TableExportCriteria)
+     */
+    public void prepareExportMaterials(
+            TableExportCriteria<TableModelRowWithObject<Material>> criteria,
+            AsyncCallback<String> callback);
+
     /**
      * @see IScreeningClientService#listPlateMetadata(IResultSetConfig, TechId)
      */
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ClientPluginFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ClientPluginFactory.java
index 755242ec77e45a7370d2191f6c64cfcfb87801d2..907a7c6dfd2992ba7b3dc3f4a492bd60c029623f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ClientPluginFactory.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ClientPluginFactory.java
@@ -40,14 +40,12 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.plugin.ICl
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.plugin.IModule;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.AbstractViewer;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.framework.LinkExtractor;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IDisposableComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMessageProvider;
 import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.shared.basic.ICodeHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolderWithPermId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IIdAndCodeHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
-import ch.systemsx.cisd.openbis.generic.shared.basic.ViewMode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
@@ -56,11 +54,10 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sample.GenericSampleViewer;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.IScreeningClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.ImageSampleViewer;
-import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.MaterialDetailsComponent;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.ImagingMaterialViewer;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.MicroscopyDatasetViewer;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.PlateDatasetViewer;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.PlateSampleViewer;
-import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.ImagingMaterialViewer;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.sample.LibrarySampleBatchRegistrationForm;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.ExperimentSearchCriteria;
@@ -177,6 +174,9 @@ public final class ClientPluginFactory extends AbstractClientPluginFactory<Scree
     /**
      * opens material viewer showing wells in which the material is contained, with a selected
      * experiment
+     * 
+     * @param experimentCriteriaOrNull note that null does NOT mean searching in all experiments,
+     *            but that single experiment should be specified by the user.
      */
     public static final void openImagingMaterialViewer(
             final IEntityInformationHolderWithPermId material,
@@ -200,19 +200,10 @@ public final class ClientPluginFactory extends AbstractClientPluginFactory<Scree
                 public ITabItem create()
                 {
                     TechId materialTechId = TechId.create(material);
-                    if (viewContext.getModel().getViewMode() == ViewMode.EMBEDDED)
-                    {
-                        IDisposableComponent viewer =
-                                MaterialDetailsComponent.create(viewContext, materialTechId,
-                                        experimentCriteriaOrNull);
-                        return DefaultTabItem.create(getTabTitle(), viewer, viewContext);
-                    } else
-                    {
-                        final DatabaseModificationAwareComponent viewer =
-                                ImagingMaterialViewer.create(viewContext, materialTechId,
-                                        experimentCriteriaOrNull);
-                        return createViewerTab(viewer, getTabTitle(), viewContext);
-                    }
+                    final DatabaseModificationAwareComponent viewer =
+                            ImagingMaterialViewer.create(viewContext, materialTechId,
+                                    experimentCriteriaOrNull);
+                    return createViewerTab(viewer, getTabTitle(), viewContext);
                 }
 
                 @Override
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/Dict.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/Dict.java
index 53a427bf319bc9317fe5018af7c9889e41f2fa1c..d84a32fb764d79fdea2c6424ac75c956b19df525 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/Dict.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/Dict.java
@@ -81,6 +81,22 @@ public final class Dict extends ch.systemsx.cisd.openbis.generic.client.web.clie
 
     public static final String WELLS_SEARCH_MENU_ITEM = "WELLS_SEARCH";
 
+    public static final String WELLS_SEARCH_SHOW_COMBINED_RESULTS =
+            "WELLS_SEARCH_SHOW_COMBINED_RESULTS";
+
+    public static final String WELL_SEARCH_NO_RESULTS_IN_ANY_EXP_FOUND =
+            "WELL_SEARCH_NO_RESULTS_IN_ANY_EXP_FOUND";
+
+    public static final String WELL_SEARCH_NO_RESULTS_IN_SELECTED_EXP_FOUND =
+            "WELL_SEARCH_NO_RESULTS_IN_SELECTED_EXP_FOUND";
+
+    public static final String WELL_SEARCH_PERFORM_IN_ALL_EXP = "WELL_SEARCH_PERFORM_IN_ALL_EXP";
+
+    public static final String MATERIAL_DISAMBIGUATION_TITLE = "MATERIAL_DISAMBIGUATION_TITLE";
+
+    public static final String MATERIAL_DISAMBIGUATION_GRID_EXPLANATION =
+            "MATERIAL_DISAMBIGUATION_GRID_EXPLANATION";
+
     private Dict()
     {
         // Can not be instantiated.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ScreeningDisplayTypeIDGenerator.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ScreeningDisplayTypeIDGenerator.java
index 50c17bea5b31e0b956cab199d9cc8caf5dbd2c22..13af2c5c42c4f6770334de76844a40d72ec5b722 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ScreeningDisplayTypeIDGenerator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ScreeningDisplayTypeIDGenerator.java
@@ -25,8 +25,11 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.
  */
 public enum ScreeningDisplayTypeIDGenerator implements IDisplayTypeIDGenerator
 {
+    PLATE_METADATA_GRID("plate-metadata-grid"),
 
-    PLATE_METADATA_GRID("plate-metadata-grid"), EXPERIMENT_CHANNEL("experiment-channel"), ;
+    EXPERIMENT_CHANNEL("experiment-channel"),
+
+    MATERIAL_DISAMBIGUATION_GRID("material-disambiguation-grid");
 
     private final String genericNameOrPrefix;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ScreeningModule.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ScreeningModule.java
index 4a31efa682e809b7f11db7df4c0d9c79748de912..ca5faba7da4512ac6a6e49eef5b832114a49a4d7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ScreeningModule.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ScreeningModule.java
@@ -28,14 +28,15 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericCon
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.TabContent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.DatabaseModificationAwareComponent;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.ActionMenu;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.ITabActionMenuItemDefinition;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.TabActionMenuItemFactory;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.plugin.IModule;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolderWithIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.IScreeningClientServiceAsync;
-import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.ExperimentPlateLocationsSection;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.ExperimentWellMaterialsSection;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.WellSearchComponent;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.locator.GlobalWellSearchLocatorResolver;
 
 /**
@@ -57,34 +58,40 @@ public class ScreeningModule implements IModule
 
     public List<? extends MenuItem> getMenuItems()
     {
-        return Collections.singletonList(TabActionMenuItemFactory.createActionMenu(viewContext, ID,
-                new ITabActionMenuItemDefinition<IScreeningClientServiceAsync>()
-                    {
-
-                        public String getName()
-                        {
-                            return Dict.WELLS_SEARCH_MENU_ITEM;
-                        }
-
-                        public String getHelpPageTitle()
-                        {
-                            return "Global Well Search";
-                        }
-
-                        public DatabaseModificationAwareComponent createComponent(
-                                IViewContext<IScreeningClientServiceAsync> context)
-                        {
-                            TabContent wellSearchTab =
-                                    new ExperimentPlateLocationsSection(viewContext, null, null);
-                            return DatabaseModificationAwareComponent.wrapUnaware(wellSearchTab);
-                        }
-
-                        public String tryGetLink()
-                        {
-                            return GlobalWellSearchLocatorResolver.createQueryBrowserLink();
-                        }
-
-                    }));
+        ActionMenu globalWellSearch =
+                TabActionMenuItemFactory
+                        .createActionMenu(viewContext, ID, createGlobalWellSearch());
+        return Collections.singletonList(globalWellSearch);
+    }
+
+    private ITabActionMenuItemDefinition<IScreeningClientServiceAsync> createGlobalWellSearch()
+    {
+        return new ITabActionMenuItemDefinition<IScreeningClientServiceAsync>()
+            {
+                public String getName()
+                {
+                    return Dict.WELLS_SEARCH_MENU_ITEM;
+                }
+
+                public String getHelpPageTitle()
+                {
+                    return "Global Well Search";
+                }
+
+                public DatabaseModificationAwareComponent createComponent(
+                        IViewContext<IScreeningClientServiceAsync> context)
+                {
+                    TabContent wellSearchTab =
+                            new WellSearchComponent(viewContext, null, true, true);
+                    return DatabaseModificationAwareComponent.wrapUnaware(wellSearchTab);
+                }
+
+                public String tryGetLink()
+                {
+                    return GlobalWellSearchLocatorResolver.createQueryBrowserLink();
+                }
+
+            };
     }
 
     public String getName()
@@ -103,7 +110,7 @@ public class ScreeningModule implements IModule
         ArrayList<TabContent> sections = new ArrayList<TabContent>();
         if (entity.getEntityKind() == EntityKind.EXPERIMENT)
         {
-            sections.add(new ExperimentPlateLocationsSection(viewContext, entity));
+            sections.add(new WellSearchComponent(viewContext, entity));
             sections.add(new ExperimentWellMaterialsSection(viewContext, entity));
         }
         return sections;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ImagingMaterialViewer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ImagingMaterialViewer.java
index a8bdb63df19ea092efd2911dc170098ef2b12035..f351f2a7cb0ada303e8c25fb92d96acdb0d01ec4 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ImagingMaterialViewer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ImagingMaterialViewer.java
@@ -78,7 +78,7 @@ public class ImagingMaterialViewer extends GenericMaterialViewer
     {
 
         List<TabContent> sections = new ArrayList<TabContent>();
-        sections.add(new PlateLocationsMaterialSection(screeningViewContext, materialId,
+        sections.add(new WellSearchMaterialSection(screeningViewContext, materialId,
                 experimentCriteriaOrNull));
         return sections;
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialDetailsComponent.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialDetailsComponent.java
deleted file mode 100644
index f7da90df827b23ff5cb2ca26e267e1f45608d133..0000000000000000000000000000000000000000
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialDetailsComponent.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2011 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.screening.client.web.client.application.detailviewers;
-
-import java.util.Set;
-
-import com.extjs.gxt.ui.client.widget.Component;
-import com.extjs.gxt.ui.client.widget.ContentPanel;
-import com.extjs.gxt.ui.client.widget.layout.RowLayout;
-
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IDisposableComponent;
-import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind;
-import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.IScreeningClientServiceAsync;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.ExperimentSearchCriteria;
-
-/**
- * Shows details about one material (across all plates in one or all experiments). <br>
- * Can be used as a tab in {@link ImagingMaterialViewer} or independently.
- * 
- * @author Tomasz Pylak
- */
-// TODO 2011-03-23, Tomasz Pylak: this class will replace the Plate Locations tab on the material
-// detail view in future.
-// For now it is a prototype accessible only in embedded mode.
-public class MaterialDetailsComponent extends ContentPanel
-{
-    private final IViewContext<IScreeningClientServiceAsync> screeningViewContext;
-
-    private final ExperimentSearchCriteria experimentCriteriaOrNull;
-
-    private final TechId materialId;
-
-    public MaterialDetailsComponent(IViewContext<IScreeningClientServiceAsync> viewContext,
-            TechId materialId, ExperimentSearchCriteria experimentCriteriaOrNull)
-    {
-        this.screeningViewContext = viewContext;
-        this.materialId = materialId;
-        this.experimentCriteriaOrNull = experimentCriteriaOrNull;
-    }
-
-    private IDisposableComponent createWellSearchGrid()
-    {
-        return WellSearchGrid.create(screeningViewContext, experimentCriteriaOrNull, materialId);
-    }
-
-    public static IDisposableComponent create(
-            IViewContext<IScreeningClientServiceAsync> viewContext, TechId materialId,
-            ExperimentSearchCriteria experimentCriteriaOrNull)
-    {
-        MaterialDetailsComponent materialDetailsComponent =
-                new MaterialDetailsComponent(viewContext, materialId, experimentCriteriaOrNull);
-        ContentPanel view = new ContentPanel();
-        view.setLayout(new RowLayout());
-        view.setHeading("Gene ID: " + materialId);
-        IDisposableComponent wellSearchGrid = materialDetailsComponent.createWellSearchGrid();
-        view.add(wellSearchGrid.getComponent());
-        return new DisposableComponentWrapper(view, wellSearchGrid);
-    }
-
-    private static class DisposableComponentWrapper implements IDisposableComponent
-    {
-        private final Component component;
-
-        private final IDisposableComponent delegator;
-
-        public DisposableComponentWrapper(Component component, IDisposableComponent delegator)
-        {
-            this.component = component;
-            this.delegator = delegator;
-        }
-
-        public Component getComponent()
-        {
-            return component;
-        }
-
-        // --- delegate
-
-        public void update(Set<DatabaseModificationKind> observedModifications)
-        {
-            delegator.update(observedModifications);
-        }
-
-        public DatabaseModificationKind[] getRelevantModifications()
-        {
-            return delegator.getRelevantModifications();
-        }
-
-        public void dispose()
-        {
-            delegator.dispose();
-        }
-
-    }
-}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialDisambiguationGrid.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialDisambiguationGrid.java
new file mode 100644
index 0000000000000000000000000000000000000000..379bcb43e696c325fcde3366be55066da2a40110
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/MaterialDisambiguationGrid.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2011 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.screening.client.web.client.application.detailviewers;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import com.extjs.gxt.ui.client.widget.Component;
+import com.extjs.gxt.ui.client.widget.Text;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericConstants;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.AbstractTabItemFactory;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.DefaultTabItem;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.DispatcherHelper;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.ITabItem;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.help.HelpPageIdentifier;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.TypedTableGrid;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ICellListenerAndLinkGenerator;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.IDataRefreshCallback;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.MaterialGridColumnIDs;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TypedTableResultSet;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ISerializableComparable;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.IScreeningClientServiceAsync;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.ClientPluginFactory;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.Dict;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.ScreeningDisplayTypeIDGenerator;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.ui.columns.specific.ScreeningLinkExtractor;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.SingleExperimentSearchCriteria;
+
+/**
+ * Displays a list of well content materials matching the search criteria and allows to go to their
+ * details.
+ * 
+ * @author Tomasz Pylak
+ */
+public class MaterialDisambiguationGrid extends TypedTableGrid<Material>
+{
+    private static final String BROWSER_ID = GenericConstants.ID_PREFIX
+            + "material-disambiguation-grid";
+
+    public static void openTab(final IViewContext<IScreeningClientServiceAsync> viewContext,
+            final WellSearchCriteria searchCriteria)
+    {
+        boolean refreshAutomatically = false;
+        final MaterialDisambiguationGrid grid =
+                new MaterialDisambiguationGrid(viewContext, searchCriteria, refreshAutomatically);
+        final AbstractTabItemFactory disambiguationTabFactory =
+                createDisambiguationTab(viewContext, searchCriteria, grid);
+        grid.refresh(new IDataRefreshCallback()
+            {
+                public void postRefresh(boolean wasSuccessful)
+                {
+                    if (grid.getRowNumber() == 0)
+                    {
+                        AbstractTabItemFactory tabFactory =
+                                createNoResultsTab(viewContext, searchCriteria);
+                        DispatcherHelper.dispatchNaviEvent(tabFactory);
+                    } else if (grid.getRowNumber() == 1)
+                    {
+                        List<Material> materials = grid.getContainedGridElements();
+                        Material material = materials.get(0);
+                        grid.openImagingMaterialViewer(material);
+                    } else
+                    {
+                        DispatcherHelper.dispatchNaviEvent(disambiguationTabFactory);
+                    }
+                }
+            }, false);
+    }
+
+    private static AbstractTabItemFactory createNoResultsTab(
+            IViewContext<IScreeningClientServiceAsync> viewContext,
+            WellSearchCriteria searchCriteria)
+    {
+        boolean searchAllExperiments =
+                searchCriteria.getExperimentCriteria().tryGetExperiment() == null;
+        String msgDictKey =
+                searchAllExperiments ? Dict.WELL_SEARCH_NO_RESULTS_IN_ANY_EXP_FOUND
+                        : Dict.WELL_SEARCH_NO_RESULTS_IN_SELECTED_EXP_FOUND;
+        Component component = new Text(viewContext.getMessage(msgDictKey));
+        return createSimpleTab(viewContext, component, Dict.MATERIAL_DISAMBIGUATION_TITLE,
+                "well-search-no-results");
+    }
+
+    private static AbstractTabItemFactory createSimpleTab(final IViewContext<?> viewContext,
+            final Component component, final String titleDictKey, final String idSuffix)
+    {
+        return new AbstractTabItemFactory()
+            {
+                @Override
+                public ITabItem create()
+                {
+                    return DefaultTabItem.createUnaware(getTabTitle(), component, false,
+                            viewContext);
+                }
+
+                @Override
+                public String getId()
+                {
+                    return GenericConstants.ID_PREFIX + idSuffix;
+                }
+
+                @Override
+                public HelpPageIdentifier getHelpPageIdentifier()
+                {
+                    return null;
+                }
+
+                @Override
+                public String getTabTitle()
+                {
+                    return viewContext.getMessage(titleDictKey);
+                }
+
+                @Override
+                public String tryGetLink()
+                {
+                    return null;
+                }
+            };
+    }
+
+    private static AbstractTabItemFactory createDisambiguationTab(
+            final IViewContext<IScreeningClientServiceAsync> viewContext,
+            final WellSearchCriteria searchCriteria, final MaterialDisambiguationGrid grid)
+    {
+        return new AbstractTabItemFactory()
+            {
+                @Override
+                public ITabItem create()
+                {
+                    return DefaultTabItem.create(getTabTitle(), grid.asDisposableWithoutToolbar(),
+                            viewContext);
+                }
+
+                @Override
+                public String getId()
+                {
+                    final String reportDate =
+                            DateTimeFormat.getMediumTimeFormat().format(new Date());
+                    return GenericConstants.ID_PREFIX + "-MaterialDisambiguationGrid-" + reportDate;
+                }
+
+                @Override
+                public HelpPageIdentifier getHelpPageIdentifier()
+                {
+                    return HelpPageIdentifier.createSpecific("Material Disambiguation");
+                }
+
+                @Override
+                public String getTabTitle()
+                {
+                    return viewContext.getMessage(Dict.MATERIAL_DISAMBIGUATION_TITLE);
+                }
+
+                @Override
+                public String tryGetLink()
+                {
+                    return ScreeningLinkExtractor.createWellsSearchLink(searchCriteria, false);
+                }
+
+            };
+    }
+
+    // ----------------
+
+    private final WellSearchCriteria searchCriteria;
+
+    private final IViewContext<IScreeningClientServiceAsync> screeningViewContext;
+
+    private MaterialDisambiguationGrid(IViewContext<IScreeningClientServiceAsync> viewContext,
+            WellSearchCriteria searchCriteria, boolean refreshAutomatically)
+    {
+        super(viewContext.getCommonViewContext(), BROWSER_ID, refreshAutomatically,
+                ScreeningDisplayTypeIDGenerator.MATERIAL_DISAMBIGUATION_GRID);
+        this.screeningViewContext = viewContext;
+        this.searchCriteria = searchCriteria;
+
+        setHeader(viewContext.getMessage(Dict.MATERIAL_DISAMBIGUATION_GRID_EXPLANATION));
+        linkToMaterialDetails();
+    }
+
+    private void linkToMaterialDetails()
+    {
+        registerListenerAndLinkGenerator(MaterialGridColumnIDs.CODE,
+                new ICellListenerAndLinkGenerator<Material>()
+                    {
+                        public String tryGetLink(Material material, ISerializableComparable value)
+                        {
+                            SingleExperimentSearchCriteria experiment =
+                                    searchCriteria.getExperimentCriteria().tryGetExperiment();
+                            String experimentIdentifier =
+                                    (experiment != null ? experiment.getExperimentIdentifier()
+                                            : null);
+                            return ScreeningLinkExtractor.tryExtractMaterialWithExperiment(
+                                    material, experimentIdentifier);
+                        }
+
+                        public void handle(TableModelRowWithObject<Material> row,
+                                boolean specialKeyPressed)
+                        {
+                            openImagingMaterialViewer(row.getObjectOrNull());
+                        }
+                    });
+    }
+
+    private void openImagingMaterialViewer(Material material)
+    {
+        ClientPluginFactory.openImagingMaterialViewer(material,
+                searchCriteria.getExperimentCriteria(), screeningViewContext);
+    }
+
+    @Override
+    protected void listTableRows(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Material>> resultSetConfig,
+            AsyncCallback<TypedTableResultSet<Material>> callback)
+    {
+        screeningViewContext.getService().listMaterials(resultSetConfig, searchCriteria, callback);
+
+    }
+
+    @Override
+    protected void prepareExportEntities(
+            TableExportCriteria<TableModelRowWithObject<Material>> exportCriteria,
+            AbstractAsyncCallback<String> callback)
+    {
+        screeningViewContext.getService().prepareExportMaterials(exportCriteria, callback);
+    }
+
+    @Override
+    protected String translateColumnIdToDictionaryKey(String columnID)
+    {
+        return columnID.toLowerCase();
+    }
+
+    @Override
+    protected List<String> getColumnIdsOfFilters()
+    {
+        return Arrays.asList(MaterialGridColumnIDs.CODE);
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateMetadataBrowser.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateMetadataBrowser.java
index 347e2cab3e1f8ee9c402435ba58972043f1f9ddb..3c55b109364f3e21e35769a665a35835aa7bb8b4 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateMetadataBrowser.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateMetadataBrowser.java
@@ -43,8 +43,8 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.IScreeningClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.ScreeningDisplayTypeIDGenerator;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.ui.columns.specific.ScreeningLinkExtractor;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMetadataGridIDs;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellMetadata;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.PlateMetadataGridColumnIDs;
 
 /**
  * Allows to create a table containing metadata of selected plate.
@@ -145,7 +145,7 @@ public class PlateMetadataBrowser extends TypedTableGrid<WellMetadata>
 
     private void linkWellSample()
     {
-        registerListenerAndLinkGenerator(PlateMetadataGridIDs.CODE,
+        registerListenerAndLinkGenerator(PlateMetadataGridColumnIDs.CODE,
                 new ICellListenerAndLinkGenerator<WellMetadata>()
                     {
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ExperimentPlateLocationsSection.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchComponent.java
similarity index 76%
rename from screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ExperimentPlateLocationsSection.java
rename to screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchComponent.java
index 395f1cd96911e3dd88406e13a870fac8fe64325b..6b0442ecc6d0c28f5bdad4b5a64c24602687d988 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/ExperimentPlateLocationsSection.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchComponent.java
@@ -5,6 +5,7 @@ import java.util.List;
 import com.extjs.gxt.ui.client.Style.Scroll;
 import com.extjs.gxt.ui.client.widget.LayoutContainer;
 import com.extjs.gxt.ui.client.widget.button.Button;
+import com.extjs.gxt.ui.client.widget.form.CheckBoxGroup;
 import com.extjs.gxt.ui.client.widget.layout.MarginData;
 import com.extjs.gxt.ui.client.widget.layout.RowLayout;
 import com.google.gwt.user.client.ui.Widget;
@@ -18,6 +19,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.renderer.L
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.field.CheckBoxField;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.field.MultilineItemsField;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedAction;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMessageProvider;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolderWithIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Code;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialType;
@@ -30,11 +32,12 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCrit
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.MaterialSearchCriteria;
 
 /**
- * Experiment section panel which allows to find wells were selected genes have been inhibited.
+ * Allows to find wells were selected materials are contained. Used in experiment section panel or
+ * as a standalone module.
  * 
  * @author Tomasz Pylak
  */
-public class ExperimentPlateLocationsSection extends TabContent
+public class WellSearchComponent extends TabContent
 {
     public static final String ID_SUFFIX = "ExperimentPlateLocationsSection";
 
@@ -42,12 +45,15 @@ public class ExperimentPlateLocationsSection extends TabContent
 
     private final IViewContext<IScreeningClientServiceAsync> screeningViewContext;
 
+    // null means that we search in all experiments
     private final IEntityInformationHolderWithIdentifier experimentOrNull;
 
     private final MultilineItemsField materialListField;
 
     private final CheckBoxField exactMatchOnly;
 
+    private final CheckBoxField showCombinedResults;
+
     private List<MaterialType> materialTypesOrNull;
 
     public static String getTabTitle(IViewContext<IScreeningClientServiceAsync> viewContext)
@@ -55,9 +61,8 @@ public class ExperimentPlateLocationsSection extends TabContent
         return viewContext.getMessage(Dict.EXPERIMENT_PLATE_MATERIAL_REVIEWER_SECTION);
     }
 
-    public ExperimentPlateLocationsSection(
-            IViewContext<IScreeningClientServiceAsync> screeningViewContext, String materialListOrNull,
-            Boolean isExactMatchOrNull)
+    public WellSearchComponent(IViewContext<IScreeningClientServiceAsync> screeningViewContext,
+            String materialListOrNull, Boolean isExactMatchOrNull, Boolean showCombinedResultsOrNull)
     {
         this(screeningViewContext, null);
 
@@ -69,23 +74,27 @@ public class ExperimentPlateLocationsSection extends TabContent
         {
             exactMatchOnly.setValue(isExactMatchOrNull);
         }
+        if (showCombinedResultsOrNull != null)
+        {
+            showCombinedResults.setValue(showCombinedResultsOrNull);
+        }
 
         setContentVisible(true);
     }
 
-    public ExperimentPlateLocationsSection(
-            IViewContext<IScreeningClientServiceAsync> screeningViewContext,
+    public WellSearchComponent(IViewContext<IScreeningClientServiceAsync> screeningViewContext,
             IEntityInformationHolderWithIdentifier experimentOrNull)
     {
-        super(getTabTitle(screeningViewContext),
-                screeningViewContext, experimentOrNull);
+        super(getTabTitle(screeningViewContext), screeningViewContext, experimentOrNull);
         this.screeningViewContext = screeningViewContext;
         this.experimentOrNull = experimentOrNull;
         this.materialListField = createMaterialListArea();
-        this.exactMatchOnly =
-                new CheckBoxField(screeningViewContext.getMessage(Dict.EXACT_MATCH_ONLY), false);
-        exactMatchOnly.setBoxLabel(screeningViewContext.getMessage(Dict.EXACT_MATCH_ONLY));
-        exactMatchOnly.setValue(true);
+        this.exactMatchOnly = createCheckBox(Dict.EXACT_MATCH_ONLY, true, screeningViewContext);
+        this.showCombinedResults =
+                createCheckBox(Dict.WELLS_SEARCH_SHOW_COMBINED_RESULTS,
+                        ScreeningLinkExtractor.WELL_SEARCH_SHOW_COMBINED_RESULTS_DEFAULT,
+                        screeningViewContext);
+
         setIds(DisplayTypeIDGenerator.EXPERIMENT_PLATE_LOCATIONS_SECTION);
         screeningViewContext.getCommonService().listMaterialTypes(
                 new AbstractAsyncCallback<List<MaterialType>>(screeningViewContext)
@@ -98,6 +107,16 @@ public class ExperimentPlateLocationsSection extends TabContent
                     });
     }
 
+    private static CheckBoxField createCheckBox(String labelDictKey, Boolean value,
+            IMessageProvider messageProvider)
+    {
+        String label = messageProvider.getMessage(labelDictKey);
+        CheckBoxField checkbox = new CheckBoxField(label, false);
+        checkbox.setBoxLabel(label);
+        checkbox.setValue(value);
+        return checkbox;
+    }
+
     private MultilineItemsField createMaterialListArea()
     {
         MultilineItemsField area = new MultilineItemsField("", true, 10);
@@ -114,7 +133,11 @@ public class ExperimentPlateLocationsSection extends TabContent
     {
         LayoutContainer container = new LayoutContainer(new RowLayout());
 
-        container.add(exactMatchOnly);
+        CheckBoxGroup checkBoxGroup = new CheckBoxGroup();
+        checkBoxGroup.add(exactMatchOnly);
+        checkBoxGroup.add(showCombinedResults);
+        container.add(checkBoxGroup);
+
         container.add(materialListField);
         container.add(createSearchLink());
 
@@ -143,9 +166,10 @@ public class ExperimentPlateLocationsSection extends TabContent
                     {
                         return null;
                     }
-                    String experimentPermId = (experimentOrNull != null) ? experimentOrNull.getPermId() : null;
+                    String experimentPermId =
+                            (experimentOrNull != null) ? experimentOrNull.getPermId() : null;
                     return ScreeningLinkExtractor.createWellsSearchLink(experimentPermId,
-                            materialCriteria);
+                            materialCriteria, showCombinedResults.getValue());
                 }
             };
         return LinkRenderer.createButtonLink(searchButton, normalModeAction, urlProvider);
@@ -160,7 +184,7 @@ public class ExperimentPlateLocationsSection extends TabContent
         }
         ExperimentSearchCriteria experimentCriteria = getExperimentSearchCriteria();
         WellSearchGrid.openTab(screeningViewContext, experimentCriteria,
-                MaterialSearchCriteria.create(materialCriteria));
+                MaterialSearchCriteria.create(materialCriteria), showCombinedResults.getValue());
     }
 
     private ExperimentSearchCriteria getExperimentSearchCriteria()
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchGrid.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchGrid.java
index 49f3de124854b7c9191f38e550465bfe7c983067..5885ad350d2da2dc8f3c8417fc2b9084a3de4c84 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchGrid.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchGrid.java
@@ -16,8 +16,8 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers;
 
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.WELL;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.WELL_CONTENT_MATERIAL;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.WELL;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.WELL_CONTENT_MATERIAL;
 
 import java.util.Arrays;
 import java.util.Date;
@@ -88,7 +88,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCrit
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.ExperimentSearchCriteria;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.MaterialSearchCriteria;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.SingleExperimentSearchCriteria;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds;
 
 /**
  * @author Franz-Josef Elmer
@@ -113,7 +113,8 @@ public class WellSearchGrid extends TypedTableGrid<WellContent>
     // by experiment perm id
     public static void openTab(
             final IViewContext<IScreeningClientServiceAsync> screeningViewContext,
-            final String experimentPermId, final MaterialSearchCriteria materialSearchCriteria)
+            final String experimentPermId, final MaterialSearchCriteria materialSearchCriteria,
+            final boolean showCombinedResults)
     {
         screeningViewContext.getCommonService().getEntityInformationHolder(EntityKind.EXPERIMENT,
                 experimentPermId,
@@ -125,7 +126,7 @@ public class WellSearchGrid extends TypedTableGrid<WellContent>
                         {
                             TechId experimentId = new TechId(experimentIdentifier.getId());
                             WellSearchGrid.openTab(screeningViewContext, experimentId,
-                                    materialSearchCriteria);
+                                    materialSearchCriteria, showCombinedResults);
                         }
                     });
     }
@@ -133,7 +134,8 @@ public class WellSearchGrid extends TypedTableGrid<WellContent>
     // by experiment tech id
     private static void openTab(
             final IViewContext<IScreeningClientServiceAsync> screeningViewContext,
-            TechId experimentId, final MaterialSearchCriteria materialSearchCriteria)
+            TechId experimentId, final MaterialSearchCriteria materialSearchCriteria,
+            final boolean showCombinedResults)
     {
         screeningViewContext.getCommonService().getExperimentInfo(experimentId,
                 new AbstractAsyncCallback<Experiment>(screeningViewContext)
@@ -145,24 +147,40 @@ public class WellSearchGrid extends TypedTableGrid<WellContent>
                                     ExperimentSearchCriteria.createExperiment(experiment.getId(),
                                             experiment.getPermId(), experiment.getIdentifier());
                             WellSearchGrid.openTab(screeningViewContext, experimentCriteria,
-                                    materialSearchCriteria);
+                                    materialSearchCriteria, showCombinedResults);
                         }
                     });
     }
 
     public static void openTab(final IViewContext<IScreeningClientServiceAsync> viewContext,
             final ExperimentSearchCriteria experimentCriteria,
-            final MaterialSearchCriteria materialCriteria)
+            final MaterialSearchCriteria materialCriteria, final boolean showCombinedResults)
     {
-        final AbstractTabItemFactory tabFactory = new AbstractTabItemFactory()
+        WellSearchCriteria searchCriteria =
+                new WellSearchCriteria(experimentCriteria, materialCriteria);
+        if (showCombinedResults)
+        {
+            openWellSearchTab(viewContext, searchCriteria);
+        } else
+        {
+            MaterialDisambiguationGrid.openTab(viewContext, searchCriteria);
+        }
+    }
+
+    private static void openWellSearchTab(
+            final IViewContext<IScreeningClientServiceAsync> viewContext,
+            final WellSearchCriteria searchCriteria)
+    {
+        DispatcherHelper.dispatchNaviEvent(new AbstractTabItemFactory()
             {
                 @Override
                 public ITabItem create()
                 {
-                    IDisposableComponent reviewer =
-                            WellSearchGrid
-                                    .create(viewContext, experimentCriteria, materialCriteria);
-                    return DefaultTabItem.create(getTabTitle(), reviewer, viewContext);
+                    IDisposableComponent grid =
+                            WellSearchGrid.create(viewContext,
+                                    searchCriteria.getExperimentCriteria(),
+                                    searchCriteria.getMaterialSearchCriteria());
+                    return DefaultTabItem.create(getTabTitle(), grid, viewContext);
                 }
 
                 @Override
@@ -188,15 +206,9 @@ public class WellSearchGrid extends TypedTableGrid<WellContent>
                 @Override
                 public String tryGetLink()
                 {
-                    SingleExperimentSearchCriteria experimentCriteriaOrNull =
-                            experimentCriteria.tryGetExperiment();
-                    return ScreeningLinkExtractor.createWellsSearchLink(
-                            (experimentCriteriaOrNull != null ? experimentCriteriaOrNull
-                                    .getExperimentPermId() : null), materialCriteria
-                                    .tryGetMaterialCodesOrProperties());
+                    return ScreeningLinkExtractor.createWellsSearchLink(searchCriteria, true);
                 }
-            };
-        DispatcherHelper.dispatchNaviEvent(tabFactory);
+            });
     }
 
     public static IDisposableComponent create(
@@ -220,17 +232,17 @@ public class WellSearchGrid extends TypedTableGrid<WellContent>
                 public void update(Set<DatabaseModificationKind> observedModifications)
                 {
                 }
-                
+
                 public DatabaseModificationKind[] getRelevantModifications()
                 {
                     return null;
                 }
-                
+
                 public Component getComponent()
                 {
                     return toolbar;
                 }
-                
+
                 public void dispose()
                 {
                 }
@@ -488,6 +500,7 @@ public class WellSearchGrid extends TypedTableGrid<WellContent>
         chooserField.setEditable(false);
         if (experimentCriteriaOrNull != null && experimentCriteriaOrNull.tryGetExperiment() != null)
         {
+            // we search in a single experiment
             updateSingleExperimentChooser(chooserField, experimentCriteriaOrNull.tryGetExperiment());
         } else
         {
@@ -661,7 +674,7 @@ public class WellSearchGrid extends TypedTableGrid<WellContent>
             TableExportCriteria<TableModelRowWithObject<WellContent>> exportCriteria,
             AbstractAsyncCallback<String> callback)
     {
-        viewContext.getService().prepareExportPlateLocations(exportCriteria, callback);
+        viewContext.getService().prepareExportPlateWells(exportCriteria, callback);
     }
 
     @Override
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateLocationsMaterialSection.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchMaterialSection.java
similarity index 91%
rename from screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateLocationsMaterialSection.java
rename to screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchMaterialSection.java
index b151fb286dd72f734f113381620ee89ef0080409..83dd89866825b5fce2e12820fe8d6562e45b4419 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/PlateLocationsMaterialSection.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellSearchMaterialSection.java
@@ -15,12 +15,12 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCrit
  * @author Tomasz Pylak
  * @author Izabela Adamczyk
  */
-class PlateLocationsMaterialSection extends TabContent
+class WellSearchMaterialSection extends TabContent
 {
 
     private final IDisposableComponent reviewer;
 
-    public PlateLocationsMaterialSection(
+    public WellSearchMaterialSection(
             IViewContext<IScreeningClientServiceAsync> screeningViewContext,
             final TechId materialId, ExperimentSearchCriteria experimentCriteriaOrNull)
     {
@@ -30,8 +30,7 @@ class PlateLocationsMaterialSection extends TabContent
                 screeningViewContext, materialId);
         setHeaderVisible(false);
         this.reviewer =
-                WellSearchGrid.create(screeningViewContext, experimentCriteriaOrNull,
-                        materialId);
+                WellSearchGrid.create(screeningViewContext, experimentCriteriaOrNull, materialId);
         setIds(DisplayTypeIDGenerator.PLATE_LOCATIONS_MATERIAL_SECTION);
     }
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/locator/GlobalWellSearchLocatorResolver.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/locator/GlobalWellSearchLocatorResolver.java
index f8808be0af15ac83e1db18c787294e7fdee9b031..9d8c7d0042e0a8edccaa1af01d0db1ff3b2050d0 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/locator/GlobalWellSearchLocatorResolver.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/locator/GlobalWellSearchLocatorResolver.java
@@ -13,7 +13,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureE
 import ch.systemsx.cisd.openbis.generic.shared.basic.URLMethodWithParameters;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.IScreeningClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.ScreeningModule;
-import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.ExperimentPlateLocationsSection;
+import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.WellSearchComponent;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.ui.columns.specific.ScreeningLinkExtractor;
 
 /**
@@ -51,9 +51,14 @@ public class GlobalWellSearchLocatorResolver extends AbstractViewLocatorResolver
                     Boolean exactMatchOnly =
                             getOptionalBooleanParameter(locator,
                                     ScreeningLinkExtractor.WELL_SEARCH_IS_EXACT_PARAMETER_KEY);
+                    boolean showCombinedResults =
+                            getOptionalBooleanParameter(
+                                    locator,
+                                    ScreeningLinkExtractor.WELL_SEARCH_SHOW_COMBINED_RESULTS_PARAMETER_KEY,
+                                    ScreeningLinkExtractor.WELL_SEARCH_SHOW_COMBINED_RESULTS_DEFAULT);
                     TabContent wellSearchTab =
-                            new ExperimentPlateLocationsSection(viewContext, materialsList,
-                                    exactMatchOnly);
+                            new WellSearchComponent(viewContext, materialsList, exactMatchOnly,
+                                    showCombinedResults);
                     return DefaultTabItem.createUnaware(wellSearchTab, false, viewContext);
                 }
 
@@ -66,7 +71,7 @@ public class GlobalWellSearchLocatorResolver extends AbstractViewLocatorResolver
                 @Override
                 public String getTabTitle()
                 {
-                    return ExperimentPlateLocationsSection.getTabTitle(viewContext);
+                    return WellSearchComponent.getTabTitle(viewContext);
                 }
 
                 @Override
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/locator/WellSearchLocatorResolver.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/locator/WellSearchLocatorResolver.java
index 9b3f64de6dd0cfa3344f8e3128d164f10cabbcde..41cf0639aeb80f381437f5e0b479e7763be2da43 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/locator/WellSearchLocatorResolver.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/locator/WellSearchLocatorResolver.java
@@ -43,6 +43,10 @@ public class WellSearchLocatorResolver extends AbstractViewLocatorResolver
         boolean exactMatchOnly =
                 getMandatoryBooleanParameter(locator,
                         ScreeningLinkExtractor.WELL_SEARCH_IS_EXACT_PARAMETER_KEY);
+        boolean showCombinedResults =
+                getOptionalBooleanParameter(locator,
+                        ScreeningLinkExtractor.WELL_SEARCH_SHOW_COMBINED_RESULTS_PARAMETER_KEY,
+                        ScreeningLinkExtractor.WELL_SEARCH_SHOW_COMBINED_RESULTS_DEFAULT);
 
         MaterialSearchCodesCriteria materialCodesCriteria =
                 new MaterialSearchCodesCriteria(decodeList(materialCodesOrProperties),
@@ -53,10 +57,11 @@ public class WellSearchLocatorResolver extends AbstractViewLocatorResolver
         if (StringUtils.isBlank(experimentPermId))
         {
             WellSearchGrid.openTab(viewContext, ExperimentSearchCriteria.createAllExperiments(),
-                    materialSearchCriteria);
+                    materialSearchCriteria, showCombinedResults);
         } else
         {
-            WellSearchGrid.openTab(viewContext, experimentPermId, materialSearchCriteria);
+            WellSearchGrid.openTab(viewContext, experimentPermId, materialSearchCriteria,
+                    showCombinedResults);
         }
 
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ui/columns/specific/ScreeningLinkExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ui/columns/specific/ScreeningLinkExtractor.java
index ff7d8d9e9d1c0dd7fdb5f7aa6224889ff94fbcaf..b9fc056943b526a72bd47d0f1743f081b21f46c0 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ui/columns/specific/ScreeningLinkExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/ui/columns/specific/ScreeningLinkExtractor.java
@@ -24,7 +24,9 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.PermlinkUtilities;
 import ch.systemsx.cisd.openbis.generic.shared.basic.URLMethodWithParameters;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.MaterialSearchCodesCriteria;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.SingleExperimentSearchCriteria;
 
 /**
  * Defines the ways simple view mode links for screening specific views are created.
@@ -49,6 +51,12 @@ public class ScreeningLinkExtractor extends LinkExtractor
 
     public final static String WELL_SEARCH_MATERIAL_ITEMS_PARAMETER_KEY = "items";
 
+    /** should we show disambiguation pge if more than one material matchs the query? */
+    public final static String WELL_SEARCH_SHOW_COMBINED_RESULTS_PARAMETER_KEY =
+            "showCombinedResults";
+
+    public final static boolean WELL_SEARCH_SHOW_COMBINED_RESULTS_DEFAULT = true;
+
     public static final String createPlateMetadataBrowserLink(String platePermId)
     {
         URLMethodWithParameters url = new URLMethodWithParameters("");
@@ -57,15 +65,27 @@ public class ScreeningLinkExtractor extends LinkExtractor
         return tryPrint(url);
     }
 
-    // action=WELL_SEARCH&experimentPermId=8127361723172863&isExactSearch=true&types=typeCode1,typeCode2&items=code1,property2"
-    public static String createWellsSearchLink(final String experimentPermId,
-            final MaterialSearchCodesCriteria materialCodesCriteria)
+    // action=WELL_SEARCH&experimentPermId=8127361723172863&isExactSearch=true&types=typeCode1,typeCode2&items=code1,property2&showCombinedResults=false"
+    public static String createWellsSearchLink(WellSearchCriteria searchCriteria,
+            boolean showCombinedResults)
+    {
+        SingleExperimentSearchCriteria expOrNull =
+                searchCriteria.getExperimentCriteria().tryGetExperiment();
+        String experimentPermIdOrNull =
+                (expOrNull == null ? null : expOrNull.getExperimentPermId());
+        MaterialSearchCodesCriteria codesOrProperties =
+                searchCriteria.getMaterialSearchCriteria().tryGetMaterialCodesOrProperties();
+        return createWellsSearchLink(experimentPermIdOrNull, codesOrProperties, showCombinedResults);
+    }
+
+    public static String createWellsSearchLink(final String experimentPermIdOrNull,
+            final MaterialSearchCodesCriteria materialCodesCriteria, boolean showCombinedResults)
     {
         URLMethodWithParameters url = new URLMethodWithParameters("");
         url.addParameter(BasicConstant.LOCATOR_ACTION_PARAMETER, WELL_SEARCH_ACTION);
-        if (false == StringUtils.isBlank(experimentPermId))
+        if (false == StringUtils.isBlank(experimentPermIdOrNull))
         {
-            url.addParameter(EXPERIMENT_PERM_ID_PARAMETER_KEY, experimentPermId);
+            url.addParameter(EXPERIMENT_PERM_ID_PARAMETER_KEY, experimentPermIdOrNull);
         }
         url.addParameter(WELL_SEARCH_IS_EXACT_PARAMETER_KEY,
                 materialCodesCriteria.isExactMatchOnly());
@@ -73,31 +93,37 @@ public class ScreeningLinkExtractor extends LinkExtractor
                 URLListEncoder.encodeItemList(materialCodesCriteria.getMaterialTypeCodes()));
         url.addParameterWithoutEncoding(WELL_SEARCH_MATERIAL_ITEMS_PARAMETER_KEY,
                 URLListEncoder.encodeItemList(materialCodesCriteria.getMaterialCodesOrProperties()));
+        url.addParameterWithoutEncoding(WELL_SEARCH_SHOW_COMBINED_RESULTS_PARAMETER_KEY,
+                showCombinedResults);
+
         return tryPrint(url);
     }
 
     public static final String tryExtractMaterialWithExperiment(IEntityInformationHolder material,
-            String experimentIdentifier)
+            String experimentIdentifierorNull)
     {
         URLMethodWithParameters url =
                 tryCreateMaterialWithExperimentLink(material.getCode(), material.getEntityType()
-                        .getCode(), experimentIdentifier);
+                        .getCode(), experimentIdentifierorNull);
         return tryPrint(url);
     }
 
     private static final URLMethodWithParameters tryCreateMaterialWithExperimentLink(
-            String materialCode, String materialTypeCode, String experimentIdentifier)
+            String materialCode, String materialTypeCode, String experimentIdentifierOrNull)
     {
-        if (materialCode == null || materialTypeCode == null || experimentIdentifier == null)
+        if (materialCode == null || materialTypeCode == null)
         {
             return null;
         }
         URLMethodWithParameters url = tryCreateMaterialLink(materialCode, materialTypeCode);
-        // We know that experiment identifier cannot contain characters that should be encoded
-        // apart from '/'. Encoding '/' makes the URL less readable and on the other hand
-        // leaving it as it is doesn't cause us any problems.
-        url.addParameterWithoutEncoding(EXPERIMENT_PARAMETER_KEY,
-                StringEscapeUtils.unescapeHtml(experimentIdentifier));
+        if (experimentIdentifierOrNull != null)
+        {
+            // We know that experiment identifier cannot contain characters that should be encoded
+            // apart from '/'. Encoding '/' makes the URL less readable and on the other hand
+            // leaving it as it is doesn't cause us any problems.
+            url.addParameterWithoutEncoding(EXPERIMENT_PARAMETER_KEY,
+                    StringEscapeUtils.unescapeHtml(experimentIdentifierOrNull));
+        }
         return url;
     }
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/public/screening-dictionary.js b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/public/screening-dictionary.js
index bd351a49dbafc594c7c09ee3d67e37d15981a38b..70815e480311fa7d5c8612a546fcc5d9c11849ec 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/public/screening-dictionary.js
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/public/screening-dictionary.js
@@ -1,93 +1,101 @@
 // screening dictionary
 var screening = {
-	
-	// If a dictionary contains 'is_default_dictionary' key and the value is 'true', 
-	// that dictionary will be treated as a 'default' one. This means that values 
-	// from that dictionary will override entries with the same keys defined in other dictionaries. 
-	// There should be at most one default dictionary, otherwise the behavior is undefined.  
-	is_default_dictionary: "true",
-
-
-  GENE_LIBRARY_URL: "http://www.genecards.org/cgi-bin/carddisp.pl?gene={0}",
-  GENE_LIBRARY_SEARCH_URL: "http://www.genecards.org//index.php?path=/Search/keyword/{0}",
-  
-  // 
-  // General
-  // 
-  PLATE: "Plate",
-  WELL_ROW: "Well Row",
-  WELL_COLUMN: "Well Column",
-  WELL: "Well",
-  WELL_IMAGES: "Well Images",
-  PREVIEW: "Preview",
-  PLATE_VIEWER_TITLE: "Plate {0}",
-
-  //
-  // Menu items
-  //
-  WELLS_SEARCH_menu_item: "Wells Search",  
-  WELLS_SEARCH_tab_label: "Wells Search",  
     
-  //
-  // Experiment Viewer
-  //
-  experiment_samples_selction_title: "Plates",
-  no_samples_found: "There are no plates in this experiment",
-  
-  //
-  // Sample Viewer
-  //
-
-	sample_properties_panel_sample_identifier: "ID",  
-  sample: "Sample",
-  sample_type: "Sample Type",
-  generated_samples: "Children Samples",
-  openbis_plate_metadata_browser_CODE: "Code",
-  openbis_plate_metadata_browser_TYPE: "Type",
-  openbis_plate_metadata_browser_THUMBNAIL: "Thumbnail",
-  
-  
-  sample_properties_heading: "Properties",
-  part_of_heading: "Components",
-  derived_samples_heading: "Derived Samples",
-  parent_samples_heading: "Parent Samples",
-  derived_sample: "Derived Sample",
-  external_data_heading: "Data Sets",
-  show_only_directly_connected: "directly connected",
-
-	//
-	// Sample import
-	//
-  import_scheduled: "Import has started successfully. Notification will be sent to '{0}' upon completion.",
-	register: "Register",
-	separator: "Separator",
-	
-	//
-	// Gene Viewer
-	//
-	plate_locations: "Plate Locations",
-  
-	//
-	// Plate Material Reviewer 
-	//    
-    SCREENING_MODULE_TITLE: "Screening",
-    
-    WELL_CONTENT_MATERIAL: "Content",
-    WELL_CONTENT_MATERIAL_TYPE: "Content Type",
-    WELL_CONTENT_PROPERTIES: "Content Properties",
-    WELL_CONTENT_FEATURE_VECTORS: "Feature Vector",
-    IMAGE_ANALYSIS_DATA_SET: "Image Analysis Dataset",
-    IMAGE_DATA_SET: "Image Dataset",
-    
-    PLATE_MATERIAL_REVIEWER_TITLE: "Wells Search Results",
-    PLATE_MATERIAL_REVIEWER_SPECIFY_METERIAL_ITEMS: "E.g. gene symbols, gene ids, gene descriptions, control names or compound names. Separate items with commas (\",\") or specify one item per line.",
-
-    EXPERIMENT_PLATE_MATERIAL_REVIEWER_SECTION: "Wells Search",
-    EXPERIMENT_PLATE_MATERIAL_BROWSER_SECTION: "Library Index",
-		EXACT_MATCH_ONLY: "Exact Matches Only",
-	
-  image_viewer_button: "Adjust Colors",
-  
-  // LAST LINE: KEEP IT AT THE END
-  lastline: "" // we need a line without a comma
+// If a dictionary contains 'is_default_dictionary' key and the value is 'true', 
+// that dictionary will be treated as a 'default' one. This means that values 
+// from that dictionary will override entries with the same keys defined in other dictionaries. 
+// There should be at most one default dictionary, otherwise the behavior is undefined.  
+is_default_dictionary: "true",
+
+
+GENE_LIBRARY_URL: "http://www.genecards.org/cgi-bin/carddisp.pl?gene={0}",
+GENE_LIBRARY_SEARCH_URL: "http://www.genecards.org//index.php?path=/Search/keyword/{0}",
+
+// 
+// General
+// 
+PLATE: "Plate",
+WELL_ROW: "Well Row",
+WELL_COLUMN: "Well Column",
+WELL: "Well",
+WELL_IMAGES: "Well Images",
+PREVIEW: "Preview",
+PLATE_VIEWER_TITLE: "Plate {0}",
+
+//
+// Menu items
+//
+WELLS_SEARCH_menu_item: "Wells Search",  
+WELLS_SEARCH_tab_label: "Wells Search",  
+
+//
+// Experiment Viewer
+//
+experiment_samples_selction_title: "Plates",
+no_samples_found: "There are no plates in this assay",
+
+//
+// Sample Viewer
+//
+
+sample_properties_panel_sample_identifier: "ID",  
+sample: "Sample",
+sample_type: "Sample Type",
+generated_samples: "Children Samples",
+openbis_plate_metadata_browser_CODE: "Code",
+openbis_plate_metadata_browser_TYPE: "Type",
+openbis_plate_metadata_browser_THUMBNAIL: "Thumbnail",
+
+
+sample_properties_heading: "Properties",
+part_of_heading: "Components",
+derived_samples_heading: "Derived Samples",
+parent_samples_heading: "Parent Samples",
+derived_sample: "Derived Sample",
+external_data_heading: "Data Sets",
+show_only_directly_connected: "directly connected",
+
+//
+// Sample import
+//
+import_scheduled: "Import has started successfully. Notification will be sent to '{0}' upon completion.",
+register: "Register",
+separator: "Separator",
+
+//
+// Gene Viewer
+//
+plate_locations: "Plate Locations",
+
+//
+// Plate Material Reviewer 
+//    
+SCREENING_MODULE_TITLE: "Screening",
+
+WELL_CONTENT_MATERIAL: "Content",
+WELL_CONTENT_MATERIAL_TYPE: "Content Type",
+WELL_CONTENT_PROPERTIES: "Content Properties",
+WELL_CONTENT_FEATURE_VECTORS: "Feature Vector",
+IMAGE_ANALYSIS_DATA_SET: "Image Analysis Dataset",
+IMAGE_DATA_SET: "Image Dataset",
+
+PLATE_MATERIAL_REVIEWER_TITLE: "Wells Search Results",
+PLATE_MATERIAL_REVIEWER_SPECIFY_METERIAL_ITEMS: "E.g. gene symbols, gene ids, gene descriptions, control names or compound names. Separate items with commas (\",\") or specify one item per line.",
+
+EXPERIMENT_PLATE_MATERIAL_REVIEWER_SECTION: "Wells Search",
+EXPERIMENT_PLATE_MATERIAL_BROWSER_SECTION: "Library Index",
+
+EXACT_MATCH_ONLY: "Exact Matches Only",
+WELLS_SEARCH_SHOW_COMBINED_RESULTS: "Show all matching results combined",
+WELL_SEARCH_NO_RESULTS_IN_ANY_EXP_FOUND: "All assays have been searched and no results match the query. Please check the spelling.",
+WELL_SEARCH_NO_RESULTS_IN_SELECTED_EXP_FOUND: "No results match the query in the selected assay.",
+WELL_SEARCH_PERFORM_IN_ALL_EXP: "Search in all assays",
+
+MATERIAL_DISAMBIGUATION_TITLE: "Material Disambiguation",
+MATERIAL_DISAMBIGUATION_GRID_EXPLANATION: "More than one result has been found. Click on it to see the details.",
+
+image_viewer_button: "Adjust Colors",
+
+// LAST LINE: KEEP IT AT THE END
+lastline: "" // we need a line without a comma
 };
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/PlateMetadataProvider.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/PlateMetadataProvider.java
index a92c2f44831c53c7ddb80cfdc6ae95c865e3363f..b867e8f8a1179331a6caa73ca2b7f5fcad071539 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/PlateMetadataProvider.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/PlateMetadataProvider.java
@@ -16,8 +16,8 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening.client.web.server;
 
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMetadataGridIDs.CODE;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMetadataGridIDs.TYPE;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.PlateMetadataGridColumnIDs.CODE;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.PlateMetadataGridColumnIDs.TYPE;
 
 import java.util.List;
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/ScreeningClientService.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/ScreeningClientService.java
index 35fd3fca1203b2a85d9a3dc7e1fdd8fe8ef8763a..ab11777570f552c2b0099bceb47ddefddd4398f2 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/ScreeningClientService.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/ScreeningClientService.java
@@ -37,6 +37,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.server.AbstractOriginalDataPr
 import ch.systemsx.cisd.openbis.generic.client.web.server.UploadedFilesBean;
 import ch.systemsx.cisd.openbis.generic.client.web.server.resultset.DataProviderAdapter;
 import ch.systemsx.cisd.openbis.generic.client.web.server.resultset.ITableModelProvider;
+import ch.systemsx.cisd.openbis.generic.client.web.server.resultset.MaterialProvider;
 import ch.systemsx.cisd.openbis.generic.client.web.server.translator.UserFailureExceptionTranslator;
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
@@ -192,12 +193,29 @@ public final class ScreeningClientService extends AbstractClientService implemen
         return new TypedTableResultSet<WellContent>(resultSet);
     }
 
-    public String prepareExportPlateLocations(
+    public String prepareExportPlateWells(
             TableExportCriteria<TableModelRowWithObject<WellContent>> criteria)
     {
         return prepareExportEntities(criteria);
     }
 
+    public TypedTableResultSet<Material> listMaterials(
+            IResultSetConfig<String, TableModelRowWithObject<Material>> gridCriteria,
+            WellSearchCriteria materialCriteria)
+    {
+        List<Material> materials = server.listMaterials(getSessionToken(), materialCriteria);
+        final ITableModelProvider<Material> provider = new MaterialProvider(materials);
+        ResultSet<TableModelRowWithObject<Material>> resultSet =
+                listEntities(gridCriteria, new DataProviderAdapter<Material>(provider));
+        return new TypedTableResultSet<Material>(resultSet);
+    }
+
+    public String prepareExportMaterials(
+            TableExportCriteria<TableModelRowWithObject<Material>> criteria)
+    {
+        return prepareExportEntities(criteria);
+    }
+
     public TypedTableResultSet<WellMetadata> listPlateMetadata(
             IResultSetConfig<String, TableModelRowWithObject<WellMetadata>> criteria,
             TechId sampleId)
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/WellContentProvider.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/WellContentProvider.java
index cfe14c6ed71e93ace08c7aa3a4b349c6c609b081..5a9bd70879c5a3ebd7ec7ac3b121dd0e4f1b1156 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/WellContentProvider.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/WellContentProvider.java
@@ -16,27 +16,23 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening.client.web.server;
 
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.EXPERIMENT;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.FILE_FORMAT_TYPE;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.IMAGE_ANALYSIS_DATA_SET;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.IMAGE_DATA_SET;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.PLATE;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.WELL;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.WELL_COLUMN;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.WELL_CONTENT_MATERIAL;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.WELL_CONTENT_MATERIAL_TYPE;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.WELL_IMAGES;
-import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchGridColumnIds.WELL_ROW;
-
-import java.util.HashSet;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.EXPERIMENT;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.FILE_FORMAT_TYPE;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.IMAGE_ANALYSIS_DATA_SET;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.IMAGE_DATA_SET;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.PLATE;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.WELL;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.WELL_COLUMN;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.WELL_CONTENT_MATERIAL;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.WELL_CONTENT_MATERIAL_TYPE;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.WELL_IMAGES;
+import static ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.WellSearchGridColumnIds.WELL_ROW;
+
 import java.util.List;
-import java.util.Set;
 
 import ch.systemsx.cisd.openbis.generic.client.web.server.resultset.AbstractTableModelProvider;
 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.Material;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TypedTableModel;
 import ch.systemsx.cisd.openbis.generic.shared.util.IColumn;
 import ch.systemsx.cisd.openbis.generic.shared.util.TypedTableModelBuilder;
@@ -54,6 +50,8 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCrit
  */
 public class WellContentProvider extends AbstractTableModelProvider<WellContent>
 {
+    static final String WELL_PROPERTY_ID_PREFIX = "WELL_PROPERTY-";
+
     static final String WELL_CONTENT_PROPERTY_ID_PREFIX = "WELL_CONTENT_PROPERTY-";
 
     static final String WELL_CONTENT_FEATURE_VECTOR_PREFIX = "WELL_CONTENT_FEATURE_VECTOR-";
@@ -78,8 +76,6 @@ public class WellContentProvider extends AbstractTableModelProvider<WellContent>
         TypedTableModelBuilder<WellContent> builder = new TypedTableModelBuilder<WellContent>();
         addStandardWellColumns(builder);
         List<WellContent> wells = server.listPlateWells(sessionToken, materialCriteria);
-        addWellPropertiesColumns(builder, wells);
-
         for (WellContent well : wells)
         {
             addRow(builder, well);
@@ -102,25 +98,6 @@ public class WellContentProvider extends AbstractTableModelProvider<WellContent>
         builder.addColumn(WELL_IMAGES).withDefaultWidth(500);
     }
 
-    private void addWellPropertiesColumns(TypedTableModelBuilder<WellContent> builder,
-            List<WellContent> wells)
-    {
-        Set<String> columnNames = new HashSet<String>();
-        for (WellContent well : wells)
-        {
-            for (IEntityProperty property : well.getWellProperties())
-            {
-                String columnName = property.getPropertyType().getCode();
-                columnNames.add(columnName);
-            }
-        }
-
-        for (String columnName : columnNames)
-        {
-            builder.addColumn(columnName).withTitle(columnName);
-        }
-    }
-
     private void addRow(TypedTableModelBuilder<WellContent> builder, WellContent well)
     {
         builder.addRow(well);
@@ -152,7 +129,10 @@ public class WellContentProvider extends AbstractTableModelProvider<WellContent>
                 imageDataset == null ? null : imageDataset.getDatasetReference().getFileTypeCode());
         builder.column(WELL_IMAGES).addString(well.tryGetImageDataset() == null ? "" : "[images]");
 
-        addWellProperties(builder, well);
+        if (well.getWellProperties() != null)
+        {
+            builder.columnGroup(WELL_PROPERTY_ID_PREFIX).addProperties(well.getWellProperties());
+        }
     }
 
     private void addFeatureColumns(TypedTableModelBuilder<WellContent> builder,
@@ -176,42 +156,4 @@ public class WellContentProvider extends AbstractTableModelProvider<WellContent>
             }
         }
     }
-
-    private void addWellProperties(TypedTableModelBuilder<WellContent> builder, WellContent well)
-    {
-        for (IEntityProperty property : well.getWellProperties())
-        {
-            PropertyType propertyType = property.getPropertyType();
-            String columnCode = propertyType.getCode();
-            String columnLabel = propertyType.getLabel();
-
-            IColumn column = builder.column(columnCode).withTitle(columnLabel);
-            DataTypeCode dataTypeCode = propertyType.getDataType().getCode();
-            String value = property.tryGetAsString();
-            if (dataTypeCode == DataTypeCode.INTEGER)
-            {
-                try
-                {
-                    column.addInteger(Long.parseLong(value));
-                } catch (NumberFormatException ex)
-                {
-                    column.addString(value);
-                }
-            } else if (dataTypeCode == DataTypeCode.REAL)
-            {
-                try
-                {
-                    column.addDouble(Double.parseDouble(value));
-                } catch (NumberFormatException ex)
-                {
-                    column.addString(value);
-                }
-            } else
-            {
-                column.addString(value);
-            }
-
-        }
-    }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
index ae96cb195703557056857e51e545a07ab3328404..ba3c28560d09201e0a18777bfdeb44dd40e01104 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java
@@ -195,6 +195,13 @@ public final class ScreeningServer extends AbstractServer<IScreeningServer> impl
                 materialCriteria);
     }
 
+    public List<Material> listMaterials(String sessionToken, WellSearchCriteria materialCriteria)
+    {
+        Session session = getSession(sessionToken);
+        return WellContentLoader.loadMaterials(session, businessObjectFactory, getDAOFactory(),
+                materialCriteria);
+    }
+
     public FeatureVectorValues getWellFeatureVectorValues(String sessionToken, String datasetCode,
             String datastoreCode, WellLocation wellLocation)
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServerLogger.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServerLogger.java
index ee158d6f778a764ac4f081adb683db6fdbdf5ca7..d9e5f93177caf9313702d651ac5004902ccbba6f 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServerLogger.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServerLogger.java
@@ -112,7 +112,13 @@ final class ScreeningServerLogger extends AbstractServerLogger implements IScree
 
     public List<WellContent> listPlateWells(String sessionToken, WellSearchCriteria materialCriteria)
     {
-        logAccess(sessionToken, "getPlateLocations", "criteria(%s)", materialCriteria);
+        logAccess(sessionToken, "listPlateWells", "criteria(%s)", materialCriteria);
+        return null;
+    }
+
+    public List<Material> listMaterials(String sessionToken, WellSearchCriteria materialCriteria)
+    {
+        logAccess(sessionToken, "listMaterials", "criteria(%s)", materialCriteria);
         return null;
     }
 
@@ -315,5 +321,4 @@ final class ScreeningServerLogger extends AbstractServerLogger implements IScree
                 "userEmail(%s), newGenesOrNull(%s), newOligosOrNull(%s), newSamplesWithType(%s)",
                 userEmail, newGenesOrNull, newOligosOrNull, newSamplesWithType);
     }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoader.java
index c2c9485bfbb2d92df56ee38e7f6a0987d490e035..7b982c6e84a8d2625d80214eb9a80e94f45ad51c 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoader.java
@@ -134,6 +134,32 @@ public class WellContentLoader
                 .getFeatureVectorValues(datasetCode, datastoreCode, wellLocation);
     }
 
+    /**
+     * @return list of unique materials with codes or properties matching to the query. If the
+     *         experiment is specified, only materials inside well locations connected through the
+     *         plate to this specified experiment(s) will be returned.
+     */
+    public static List<Material> loadMaterials(Session session,
+            IScreeningBusinessObjectFactory businessObjectFactory, IDAOFactory daoFactory,
+            WellSearchCriteria materialCriteria)
+    {
+        List<WellContent> locations =
+                new WellContentLoader(session, businessObjectFactory, daoFactory)
+                        .loadLocations(materialCriteria);
+        Set<Material> materials = extractMaterials(locations);
+        return new ArrayList<Material>(materials);
+    }
+
+    private static Set<Material> extractMaterials(List<WellContent> locations)
+    {
+        Set<Material> materials = new HashSet<Material>();
+        for (WellContent location : locations)
+        {
+            materials.add(location.getMaterialContent());
+        }
+        return materials;
+    }
+
     private final Session session;
 
     private final IScreeningBusinessObjectFactory businessObjectFactory;
@@ -162,8 +188,9 @@ public class WellContentLoader
         List<FeatureVectorValues> features = featureVectors.getFeatures();
         if (features.size() == 0)
         {
-            // TODO throw exception?
-            // shouldn't happen
+            // Because of the way we are storing the features it can happen only if dataset contains
+            // no features (NaN are stored in the plate matrix for the wells which have no value
+            // specified).
             return null;
         } else
         {
@@ -610,16 +637,16 @@ public class WellContentLoader
                     materialSearchCriteria.tryGetMaterialCodesOrProperties();
 
             Long expId = tryGetExperimentId(experiment);
-            long[] ids = findMaterialIds(codesCriteria);
+            long[] materialIds = findMaterialIds(codesCriteria);
             if (expId == null)
             {
                 locations =
-                        dao.getPlateLocationsForMaterialCodes(ids,
+                        dao.getPlateLocationsForMaterialCodes(materialIds,
                                 codesCriteria.getMaterialTypeCodes());
             } else
             {
                 locations =
-                        dao.getPlateLocationsForMaterialCodes(ids,
+                        dao.getPlateLocationsForMaterialCodes(materialIds,
                                 codesCriteria.getMaterialTypeCodes(), expId);
             }
 
@@ -804,5 +831,4 @@ public class WellContentLoader
         }
         return experiment.getId();
     }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/IScreeningServer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/IScreeningServer.java
index 6c69751fda003d5a920114f50eb034a10758fc57..d4a9f4c2ef0551cc3e14377350508eaec9a3fbb9 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/IScreeningServer.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/IScreeningServer.java
@@ -111,6 +111,17 @@ public interface IScreeningServer extends IServer
             String sessionToken,
             @AuthorizationGuard(guardClass = WellSearchCriteriaPredicate.class) WellSearchCriteria materialCriteria);
 
+    /**
+     * @return materials with codes or properties matching to the query. If the experiment is
+     *         specified, only materials inside well locations connected through the plate to this
+     *         specified experiment(s) will be returned.
+     */
+    @Transactional(readOnly = true)
+    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    public List<Material> listMaterials(
+            String sessionToken,
+            @AuthorizationGuard(guardClass = WellSearchCriteriaPredicate.class) WellSearchCriteria materialCriteria);
+
     /**
      * Loads all materials of specified type connected with the specified experiment.
      * 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateMetadataGridIDs.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/grids/PlateMetadataGridColumnIDs.java
similarity index 85%
rename from screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateMetadataGridIDs.java
rename to screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/grids/PlateMetadataGridColumnIDs.java
index 87119b5ba9c712909bb5856c7221ef23322a5d3e..16209efb7eae374b7b08607425db0a4bfca3bea7 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateMetadataGridIDs.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/grids/PlateMetadataGridColumnIDs.java
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto;
+package ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids;
 
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.PlateMetadataBrowser;
 
 /**
  * Defines IDs of {@link PlateMetadataBrowser}.
  */
-public class PlateMetadataGridIDs
+public class PlateMetadataGridColumnIDs
 {
-    public static final String CODE = "CODE"; 
-    public static final String TYPE = "TYPE"; 
+    public static final String CODE = "CODE";
+
+    public static final String TYPE = "TYPE";
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/WellSearchGridColumnIds.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/grids/WellSearchGridColumnIds.java
similarity index 99%
rename from screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/WellSearchGridColumnIds.java
rename to screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/grids/WellSearchGridColumnIds.java
index 03e27d0aba7cc7c9609e415a6bdf9275ee71e13e..e0951691c61d2868edec3c42db771ba1d0e158c5 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/WellSearchGridColumnIds.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/grids/WellSearchGridColumnIds.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto;
+package ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids;
 
 
 /**
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/PlateMetadataProviderTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/PlateMetadataProviderTest.java
index ebce0f8b652e72157bb8b3715e8a3f6a11041c04..10cb83fbe3b324eabe3772c53882e4c6bb14cc11 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/PlateMetadataProviderTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/server/PlateMetadataProviderTest.java
@@ -39,8 +39,8 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.IScreeningServer;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.ObjectCreationUtilForTests;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateContent;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMetadata;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMetadataGridIDs;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellMetadata;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.grids.PlateMetadataGridColumnIDs;
 
 /**
  * @author Franz-Josef Elmer
@@ -89,11 +89,11 @@ public class PlateMetadataProviderTest extends AbstractServerTestCase
 
         List<TableModelColumnHeader> headers = tableModel.getHeader();
         assertEquals(null, headers.get(0).getTitle());
-        assertEquals(PlateMetadataGridIDs.CODE, headers.get(0).getId());
+        assertEquals(PlateMetadataGridColumnIDs.CODE, headers.get(0).getId());
         assertEquals(0, headers.get(0).getIndex());
         assertEquals(DataTypeCode.VARCHAR, headers.get(0).getDataType());
         assertEquals(null, headers.get(1).getTitle());
-        assertEquals(PlateMetadataGridIDs.TYPE, headers.get(1).getId());
+        assertEquals(PlateMetadataGridColumnIDs.TYPE, headers.get(1).getId());
         assertEquals(1, headers.get(1).getIndex());
         assertEquals(DataTypeCode.VARCHAR, headers.get(1).getDataType());
         assertEquals("answer", headers.get(2).getTitle());
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoaderTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoaderTest.java
index bfbf8e230fe42b9664163fbfa1fe33a96f204b2f..0e6f655fbbacc3ad3eeb64a6b39e9fe3627ec027 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoaderTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellContentLoaderTest.java
@@ -69,8 +69,7 @@ public class WellContentLoaderTest extends AbstractScreeningDAOTest
 
         Session session = createSession(getSystemPerson());
         List<WellContent> wellContents =
-                WellContentLoader.load(session, businessObjectFactory,
-                        daoFactory, searchCriteria);
+                WellContentLoader.load(session, businessObjectFactory, daoFactory, searchCriteria);
 
         // the test database contains two matching wells
         assertEquals(2, wellContents.size());