From 9fbb74965edc20f2768cce827333994d057c502c Mon Sep 17 00:00:00 2001
From: tpylak <tpylak>
Date: Wed, 28 Jul 2010 09:01:25 +0000
Subject: [PATCH] SE-281 DynamiX plugin fixes, screening bugfixes: show correct
 plate size even when datasets are not loaded, magnify the well image if there
 is only one tile

SVN: 17252
---
 .../cisd/etlserver/BDSStorageProcessor.java   |   2 +
 .../cisd/etlserver/PlateDimension.java        |   2 +
 .../cisd/etlserver/PlateDimensionParser.java  |   2 +
 .../etlserver/BDSStorageProcessorTest.java    |   2 +
 .../generic/server/business/bo/ISampleBO.java |   5 +
 .../generic/server/business/bo/SampleBO.java  |   8 ++
 .../openbis/dss/etl/HCSImageCheckList.java    |  18 ++-
 .../dss/etl/PlateStorageProcessor.java        |   2 +-
 .../etl/ScreeningContainerDatasetInfo.java    |   4 +-
 .../etl/dynamix/HCSImageFileExtractor.java    |  12 +-
 .../detailviewers/WellContentDialog.java      |  67 +++-------
 .../server/logic/PlateContentLoader.java      |  23 +++-
 .../shared/basic/dto/PlateContent.java        |   4 +-
 .../shared/basic/dto/PlateImages.java         |  25 ++--
 .../screening/shared/dto/PlateDimension.java  |  79 +++++++++++
 .../shared/dto/PlateDimensionParser.java      | 126 ++++++++++++++++++
 .../imaging/dataaccess/IImagingQueryDAO.java  |   6 +-
 .../genedata/FeatureStorageProcessorTest.java |   2 +-
 18 files changed, 302 insertions(+), 87 deletions(-)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/dto/PlateDimension.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/dto/PlateDimensionParser.java

diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/BDSStorageProcessor.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/BDSStorageProcessor.java
index c30d02a09b3..7a4e03f5159 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/BDSStorageProcessor.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/BDSStorageProcessor.java
@@ -85,6 +85,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.StorageFormat;
  * 
  * @author Christian Ribeaud
  */
+// TODO 2010-07-28, Tomasz Pylak: remove this class
+@Deprecated
 public final class BDSStorageProcessor extends AbstractStorageProcessor implements
         IHCSImageFileAccepter
 {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/PlateDimension.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/PlateDimension.java
index b7ee40deb35..5cd56019c4c 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/PlateDimension.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/PlateDimension.java
@@ -24,6 +24,8 @@ import ch.systemsx.cisd.openbis.generic.shared.IServer;
 /**
  * @author Tomasz Pylak
  */
+// TODO 2010-07-28, Tomasz Pylak: remove this class together with BDS
+@Deprecated
 public class PlateDimension extends AbstractHashable implements Serializable
 {
     private static final long serialVersionUID = IServer.VERSION;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/PlateDimensionParser.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/PlateDimensionParser.java
index 6e334a7b791..9a02274cd00 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/PlateDimensionParser.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/PlateDimensionParser.java
@@ -24,6 +24,8 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
  * 
  * @author Tomasz Pylak
  */
+// TODO 2010-07-28, Tomasz Pylak: remove this class together with BDS
+@Deprecated
 public class PlateDimensionParser
 {
     public static final String PLATE_GEOMETRY_PROPERTY_NAME = "$PLATE_GEOMETRY";
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/BDSStorageProcessorTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/BDSStorageProcessorTest.java
index dd60be44203..02522823955 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/BDSStorageProcessorTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/BDSStorageProcessorTest.java
@@ -78,6 +78,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifi
  * 
  * @author Christian Ribeaud
  */
+// TODO 2010-07-28, Tomasz Pylak: remove this class
+@Deprecated
 @Friend(toClasses = DssPropertyParametersUtil.class)
 public final class BDSStorageProcessorTest extends AbstractFileSystemTestCase
 {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ISampleBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ISampleBO.java
index 95601d34d4b..5caf7a2bad1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ISampleBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ISampleBO.java
@@ -52,6 +52,11 @@ public interface ISampleBO extends IEntityBusinessObject
      */
     public void enrichWithPropertyTypes();
 
+    /**
+     * Enrich with properties.
+     */
+    public void enrichWithProperties();
+
     /**
      * Returns the loaded or defined sample or <code>null</code>.
      */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
index 86d33b575e8..2448908f521 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleBO.java
@@ -319,4 +319,12 @@ public final class SampleBO extends AbstractSampleBusinessObject implements ISam
             HibernateUtils.initialize(sample.getSampleType().getSampleTypePropertyTypes());
         }
     }
+
+    public void enrichWithProperties()
+    {
+        if (sample != null)
+        {
+            HibernateUtils.initialize(sample.getProperties());
+        }
+    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageCheckList.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageCheckList.java
index 95827467dc2..73fa86b240c 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageCheckList.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/HCSImageCheckList.java
@@ -23,7 +23,7 @@ import java.util.Map;
 
 import ch.systemsx.cisd.bds.hcs.Geometry;
 import ch.systemsx.cisd.common.utilities.AbstractHashable;
-import ch.systemsx.cisd.etlserver.PlateDimension;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateDimension;
 
 /**
  * Helper class to set the <code>is_complete</code> flag in the <i>BDS</i> library.
@@ -84,11 +84,12 @@ public final class HCSImageCheckList
         {
             throw new IllegalArgumentException("Invalid channel/well/tile: " + image);
         }
-        if (check.isCheckedOff())
+        Float timepointOrNull = image.tryGetTimePoint();
+        if (check.isCheckedOff(timepointOrNull))
         {
             throw new IllegalArgumentException("Image already handled: " + image);
         }
-        check.checkOff();
+        check.checkOff(timepointOrNull);
     }
 
     private static FullLocation createLocation(AcquiredPlateImage image)
@@ -102,7 +103,7 @@ public final class HCSImageCheckList
         final List<FullLocation> fullLocations = new ArrayList<FullLocation>();
         for (final Map.Entry<FullLocation, Check> entry : imageMap.entrySet())
         {
-            if (entry.getValue().isCheckedOff() == false)
+            if (entry.getValue().isCheckedOff(null) == false)
             {
                 fullLocations.add(entry.getKey());
             }
@@ -118,14 +119,17 @@ public final class HCSImageCheckList
     {
         private boolean checkedOff;
 
-        final void checkOff()
+        private List<Float> timepoints = new ArrayList<Float>();
+
+        final void checkOff(Float timepointOrNull)
         {
+            timepoints.add(timepointOrNull);
             checkedOff = true;
         }
 
-        final boolean isCheckedOff()
+        final boolean isCheckedOff(Float timepointOrNull)
         {
-            return checkedOff;
+            return checkedOff && (timepointOrNull == null || timepoints.contains(timepointOrNull));
         }
     }
 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateStorageProcessor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateStorageProcessor.java
index 76a6cfb7bd8..f4be0d65f92 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateStorageProcessor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/PlateStorageProcessor.java
@@ -56,7 +56,6 @@ import ch.systemsx.cisd.common.utilities.PropertyUtils;
 import ch.systemsx.cisd.etlserver.AbstractStorageProcessor;
 import ch.systemsx.cisd.etlserver.IHCSImageFileAccepter;
 import ch.systemsx.cisd.etlserver.ITypeExtractor;
-import ch.systemsx.cisd.etlserver.PlateDimension;
 import ch.systemsx.cisd.hdf5.HDF5FactoryProvider;
 import ch.systemsx.cisd.hdf5.IHDF5Writer;
 import ch.systemsx.cisd.openbis.dss.Constants;
@@ -67,6 +66,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.dto.StorageFormat;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateDimension;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingQueryDAO;
 
 /**
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfo.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfo.java
index e44701a7fb8..e2665aa68bb 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfo.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ScreeningContainerDatasetInfo.java
@@ -17,12 +17,12 @@
 package ch.systemsx.cisd.openbis.dss.etl;
 
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
-import ch.systemsx.cisd.etlserver.PlateDimension;
-import ch.systemsx.cisd.etlserver.PlateDimensionParser;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateDimension;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateDimensionParser;
 
 /**
  * Describes one dataset container (e.g. plate) with images.
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/HCSImageFileExtractor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/HCSImageFileExtractor.java
index e3b4b51cbe5..88320361ef9 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/HCSImageFileExtractor.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/HCSImageFileExtractor.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.dss.etl.dynamix;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
@@ -81,7 +82,7 @@ public class HCSImageFileExtractor extends AbstractHCSImageFileExtractor
     {
         final String[] tokens = StringUtils.split(plateLocation, "_");
         boolean isLeft = (tokens[0].equalsIgnoreCase("left"));
-        Integer pos = Integer.parseInt(plateLocation.substring(3));
+        Integer pos = Integer.parseInt(tokens[1].substring(3));
         assert pos > 0 && pos <= 576 : "wrong position: " + pos;
 
         int sideShift = isLeft ? 1 : 0;
@@ -93,10 +94,9 @@ public class HCSImageFileExtractor extends AbstractHCSImageFileExtractor
     }
 
     @Override
-    /* @param timepointToken - format 20100227152439 */
     protected final Float tryGetTimepoint(final String timepointToken)
     {
-        return Float.parseFloat(timepointToken);
+        return new Float(timepointToken);
     }
 
     @Override
@@ -120,8 +120,10 @@ public class HCSImageFileExtractor extends AbstractHCSImageFileExtractor
         info.setPlateLocationToken(tokens[0] + "_" + tokens[2]);
         info.setWellLocationToken(null);
         info.setChannelToken(tokens[1]);
-        // 20100227152439
-        info.setTimepointToken(tokens[3].substring(1) + tokens[4]);
+
+        File[] images = imageFile.getParentFile().listFiles();
+        Arrays.sort(images);
+        info.setTimepointToken("" + Arrays.asList(images).indexOf(imageFile));
         return info;
     }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
index b09b816c529..caf19ad69da 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/client/web/client/application/detailviewers/WellContentDialog.java
@@ -16,7 +16,6 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import com.extjs.gxt.ui.client.Style.Scroll;
@@ -47,7 +46,6 @@ import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.S
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.ChannelChooser.DefaultChannelState;
 import ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers.ChannelChooser.IChanneledViewerFactory;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.DatasetImagesReference;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateImageParameters;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellContent;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
@@ -61,6 +59,8 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellMetadata;
 public class WellContentDialog extends Dialog
 {
 
+    private static final int SINGLE_IMG_SIZE_MULTIPLY_FACTOR = 3;
+
     public static void showContentDialog(final WellData wellData, DefaultChannelState channelState,
             final ScreeningViewContext viewContext)
     {
@@ -86,8 +86,9 @@ public class WellContentDialog extends Dialog
                     createImageViewer(images, channelState, viewContext, imgW, imgH);
             container.add(imageViewer);
 
-            dialogWidth = imgW * Math.max(2, images.getTileColsNum()) + 100;
-            dialogHeight = imgH * images.getTileRowsNum() + 300;
+            int imageSizeMultiplyFactor = getImageSizeMultiplyFactor(images);
+            dialogWidth = imgW * imageSizeMultiplyFactor * images.getTileColsNum() + 100;
+            dialogHeight = imgH * imageSizeMultiplyFactor * images.getTileRowsNum() + 300;
         } else
         {
             dialogWidth = 300;
@@ -97,6 +98,17 @@ public class WellContentDialog extends Dialog
         setupContentAndShow(contentDialog, container, dialogWidth, dialogHeight, title);
     }
 
+    private static int getImageSizeMultiplyFactor(WellImages images)
+    {
+        if (images.getTileColsNum() == 1 && images.getTileRowsNum() == 1)
+        {
+            return SINGLE_IMG_SIZE_MULTIPLY_FACTOR;
+        } else
+        {
+            return 1;
+        }
+    }
+
     // ----------------
 
     private final WellMetadata metadataOrNull;
@@ -213,61 +225,20 @@ public class WellContentDialog extends Dialog
             DefaultChannelState channelState, final IViewContext<?> viewContext,
             final int imageWidth, final int imageHeight)
     {
+        final int imageSizeMultiplyFactor = getImageSizeMultiplyFactor(images);
         final IChanneledViewerFactory viewerFactory = new IChanneledViewerFactory()
             {
                 public LayoutContainer create(String channel)
                 {
                     String sessionId = getSessionId(viewContext);
-                    return createTilesGrid(images, channel, sessionId, imageWidth, imageHeight);
+                    return createTilesGrid(images, channel, sessionId, imageWidth
+                            * imageSizeMultiplyFactor, imageHeight * imageSizeMultiplyFactor);
                 }
             };
         return ChannelChooser.createViewerWithChannelChooser(viewerFactory, channelState, images
                 .getChannelsNames());
     }
 
-    /** view with channel chooser, no metadata are displayed */
-    public static void showContentDialog(final WellContent wellContent,
-            DefaultChannelState channelState, final IViewContext<?> viewContext,
-            final int imageWidthPx, final int imageHeightPx)
-    {
-        final IChanneledViewerFactory viewerFactory = new IChanneledViewerFactory()
-            {
-                public Widget create(String channel)
-                {
-                    return createImageViewerForChannel(viewContext, wellContent, imageWidthPx,
-                            imageHeightPx, channel);
-                }
-            };
-        DatasetImagesReference imageDataset = wellContent.tryGetImages();
-
-        int dialogWidth;
-        int dialogHeight;
-        List<String> channelsNames = new ArrayList<String>();
-        if (imageDataset != null)
-        {
-            PlateImageParameters imageParameters = imageDataset.getImageParameters();
-            channelsNames = imageParameters.getChannelsNames();
-            dialogWidth = imageWidthPx * Math.max(2, imageParameters.getTileColsNum()) + 100;
-            dialogHeight = imageHeightPx * imageParameters.getTileRowsNum() + 300;
-        } else
-        {
-            dialogWidth = 300;
-            dialogHeight = 160;
-        }
-        Widget content =
-                ChannelChooser.createViewerWithChannelChooser(viewerFactory, channelState,
-                        channelsNames);
-        setupContentAndShow(new Dialog(), content, dialogWidth, dialogHeight,
-                createDialogTitle(wellContent));
-    }
-
-    private static String createDialogTitle(WellContent wellContent)
-    {
-        String content = wellContent.getMaterialContent().getCode();
-        return "Plate: " + wellContent.getPlate().getCode() + ", well: "
-                + wellContent.getWell().getCode() + ", content: " + content;
-    }
-
     /**
      * Creates a view for the specified channel.
      * 
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateContentLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateContentLoader.java
index 6f0ec5ad69d..150adfba1f4 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateContentLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateContentLoader.java
@@ -25,15 +25,18 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.IExternalDataTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ISampleBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListOrSearchSampleCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.generic.shared.translator.EntityPropertyTranslator;
 import ch.systemsx.cisd.openbis.generic.shared.translator.SampleTranslator;
 import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
 import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.DatasetImagesReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.DatasetReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateContent;
@@ -41,6 +44,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateImagePara
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateImages;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellMetadata;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateDimensionParser;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.IHCSDatasetLoader;
 
 /**
@@ -108,7 +112,16 @@ public class PlateContentLoader
         List<WellMetadata> wells = loadWells(new TechId(HibernateUtils.getId(plate)));
         DatasetImagesReference datasetImagesReference =
                 loadImages(createExternalDataTable(), externalData);
-        return new PlateImages(translate(plate), wells, datasetImagesReference);
+        Geometry plateGeometry = getPlateGeometry(plate);
+        return new PlateImages(translate(plate), wells, datasetImagesReference, plateGeometry
+                .getNumberOfRows(), plateGeometry.getNumberOfColumns());
+    }
+
+    private Geometry getPlateGeometry(SamplePE plate)
+    {
+        List<IEntityProperty> properties =
+                EntityPropertyTranslator.translate(plate.getProperties(), null);
+        return PlateDimensionParser.getPlateGeometry(properties);
     }
 
     private ExternalDataPE loadDataset(TechId datasetId)
@@ -205,8 +218,11 @@ public class PlateContentLoader
             analysisDataset = ScreeningUtils.createDatasetReference(analysisDatasets.get(0));
         }
 
-        return new PlateContent(plate, wells, imageDataset, imageDatasets.size(), analysisDataset,
-                analysisDatasets.size());
+        Geometry plateGeometry = PlateDimensionParser.getPlateGeometry(plate.getProperties());
+        int rows = plateGeometry.getNumberOfRows();
+        int cols = plateGeometry.getNumberOfColumns();
+        return new PlateContent(plate, wells, rows, cols, imageDataset, imageDatasets.size(),
+                analysisDataset, analysisDatasets.size());
     }
 
     private IExternalDataTable createExternalDataTable()
@@ -218,6 +234,7 @@ public class PlateContentLoader
     {
         ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
         sampleBO.loadDataByTechId(plateId);
+        sampleBO.enrichWithProperties();
         SamplePE sample = sampleBO.getSample();
         return translate(sample);
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateContent.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateContent.java
index ceaec98477a..94d50bd44dd 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateContent.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateContent.java
@@ -46,7 +46,7 @@ public class PlateContent implements IsSerializable
     {
     }
 
-    public PlateContent(Sample plate, List<WellMetadata> wells,
+    public PlateContent(Sample plate, List<WellMetadata> wells, int plateRowsNum, int plateColsNum,
             DatasetImagesReference imagesOrNull, int imageDatasetsNumber,
             DatasetReference imageAnalysisDatasetOrNull, int imageAnalysisDatasetsNumber)
     {
@@ -54,7 +54,7 @@ public class PlateContent implements IsSerializable
                 || (imagesOrNull == null && imageDatasetsNumber != 1);
         assert (imageAnalysisDatasetOrNull != null && imageAnalysisDatasetsNumber == 1)
                 || (imageAnalysisDatasetOrNull == null && imageAnalysisDatasetsNumber != 1);
-        this.plateImages = new PlateImages(plate, wells, imagesOrNull);
+        this.plateImages = new PlateImages(plate, wells, imagesOrNull, plateRowsNum, plateColsNum);
         this.imageDatasetsNumber = imageDatasetsNumber;
         this.imageAnalysisDatasetOrNull = imageAnalysisDatasetOrNull;
         this.imageAnalysisDatasetsNumber = imageAnalysisDatasetsNumber;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImages.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImages.java
index af4061dc5b1..8ebdaf5887b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImages.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/PlateImages.java
@@ -42,6 +42,9 @@ public class PlateImages implements IsSerializable
     // null if dataset with images does not exist
     private DatasetImagesReference imagesOrNull;
 
+    // plate dimension
+    private int plateRowsNum, plateColsNum;
+
     // GWT only
     @SuppressWarnings("unused")
     private PlateImages()
@@ -49,11 +52,13 @@ public class PlateImages implements IsSerializable
     }
 
     public PlateImages(Sample plate, List<WellMetadata> wellsMetadata,
-            DatasetImagesReference imagesOrNull)
+            DatasetImagesReference imagesOrNull, int plateRowsNum, int plateColsNum)
     {
         this.plate = plate;
         this.wellsMetadata = wellsMetadata;
         this.imagesOrNull = imagesOrNull;
+        this.plateRowsNum = plateRowsNum;
+        this.plateColsNum = plateColsNum;
     }
 
     public List<WellMetadata> getWells()
@@ -74,25 +79,11 @@ public class PlateImages implements IsSerializable
 
     public int getRowsNum()
     {
-        if (imagesOrNull != null)
-        {
-            return imagesOrNull.getImageParameters().getRowsNum();
-        } else
-        {
-            // TODO 2009-12-09, Tomasz Pylak: calculate rows number on the basis of metadata
-            return 16;
-        }
+        return plateRowsNum;
     }
 
     public int getColsNum()
     {
-        if (imagesOrNull != null)
-        {
-            return imagesOrNull.getImageParameters().getColsNum();
-        } else
-        {
-            // TODO 2009-12-09, Tomasz Pylak: calculate rows number on the basis of metadata
-            return 24;
-        }
+        return plateColsNum;
     }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/dto/PlateDimension.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/dto/PlateDimension.java
new file mode 100644
index 00000000000..4f5f0c06b67
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/dto/PlateDimension.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2007 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.shared.dto;
+
+import java.io.Serializable;
+
+import ch.systemsx.cisd.common.utilities.AbstractHashable;
+import ch.systemsx.cisd.openbis.generic.shared.IServer;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
+
+/**
+ * @author Tomasz Pylak
+ */
+public class PlateDimension extends AbstractHashable implements Serializable
+{
+    private static final long serialVersionUID = IServer.VERSION;
+
+    private int rowsNum;
+
+    private int colsNum;
+
+    // for internal use only
+    public PlateDimension()
+    {
+        this(0, 0);
+    }
+
+    public PlateDimension(int rowsNum, int colsNum)
+    {
+        super();
+        this.rowsNum = rowsNum;
+        this.colsNum = colsNum;
+    }
+
+    public int getRowsNum()
+    {
+        return rowsNum;
+    }
+
+    public void setRowsNum(int rowsNum)
+    {
+        this.rowsNum = rowsNum;
+    }
+
+    public int getColsNum()
+    {
+        return colsNum;
+    }
+
+    public void setColsNum(int colsNum)
+    {
+        this.colsNum = colsNum;
+    }
+
+    public Geometry getPlateGeometry()
+    {
+        return Geometry.createFromRowColDimensions(rowsNum, colsNum);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "(" + rowsNum + ", " + colsNum + ")";
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/dto/PlateDimensionParser.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/dto/PlateDimensionParser.java
new file mode 100644
index 00000000000..48a2171d205
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/dto/PlateDimensionParser.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2008 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.shared.dto;
+
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry;
+
+/**
+ * Extractor and parser of the plate geometry from an array of properties.
+ * 
+ * @author Tomasz Pylak
+ */
+public class PlateDimensionParser
+{
+    public static final String PLATE_GEOMETRY_PROPERTY_NAME = "$PLATE_GEOMETRY";
+
+    /**
+     * Returns the plate geometry from the specified properties.
+     * 
+     * @throws IllegalArgumentException if either their isn't such a property or it has an invalid
+     *             value.
+     */
+    public static PlateDimension getPlateDimension(final IEntityProperty[] properties)
+    {
+        final PlateDimension plateDimension = tryToGetPlateDimension(properties);
+        if (plateDimension == null)
+        {
+            throw new IllegalArgumentException("Cannot find property "
+                    + PLATE_GEOMETRY_PROPERTY_NAME);
+        }
+        return plateDimension;
+    }
+
+    /**
+     * Tries to get the plate geometry from the specified properties.
+     * 
+     * @return <code>null</code> if their isn't such a property.
+     * @throws IllegalArgumentException if the property for the plate geometry has an invalid value.
+     */
+    public static PlateDimension tryToGetPlateDimension(final IEntityProperty[] properties)
+    {
+        assert properties != null : "Unspecified properties";
+        final String plateGeometryString =
+                tryFindProperty(properties, PLATE_GEOMETRY_PROPERTY_NAME);
+        if (plateGeometryString == null)
+        {
+            return null;
+        }
+        final PlateDimension dimension = tryParsePlateDimension(plateGeometryString);
+        if (dimension == null)
+        {
+            throw new IllegalArgumentException("Cannot parse plate geometry " + plateGeometryString);
+        }
+        return dimension;
+
+    }
+
+    // parses plate geometry - takes the token after the last "_" sign and assumes that the number
+    // of rows is separated
+    // from number of columns by the 'X' sign, e.g. XXX_YYY_16x24
+    private static PlateDimension tryParsePlateDimension(final String plateGeometryString)
+    {
+        final String[] tokens = plateGeometryString.split("_");
+        final String sizeToken = tokens[tokens.length - 1];
+        final String[] dims = sizeToken.split("X");
+        if (dims.length != 2)
+        {
+            return null;
+        }
+        final Integer rows = tryParseInteger(dims[0]);
+        final Integer cols = tryParseInteger(dims[1]);
+        if (rows == null || cols == null)
+        {
+            return null;
+        }
+        return new PlateDimension(rows, cols);
+    }
+
+    private static Integer tryParseInteger(final String value)
+    {
+        try
+        {
+            return Integer.parseInt(value);
+        } catch (final NumberFormatException e)
+        {
+            return null;
+        }
+    }
+
+    private static String tryFindProperty(final IEntityProperty[] properties,
+            final String propertyCode)
+    {
+        for (final IEntityProperty property : properties)
+        {
+            final PropertyType propertyType = property.getPropertyType();
+            if (propertyType.getCode().equals(propertyCode))
+            {
+                return property.tryGetAsString();
+            }
+        }
+        return null;
+    }
+
+    public static Geometry getPlateGeometry(List<IEntityProperty> properties)
+    {
+        return getPlateDimension(properties.toArray(new IEntityProperty[0])).getPlateGeometry();
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingQueryDAO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingQueryDAO.java
index 096c8aac317..3be6357d8d2 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingQueryDAO.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/IImagingQueryDAO.java
@@ -44,7 +44,11 @@ public interface IImagingQueryDAO extends TransactionQuery
                     // and acquired_images.channel_stack.spot.y = wellY
                     + "cs.x = ?{3.x} and cs.y = ?{3.y} and s.x = ?{4.x} and s.y = ?{4.y} and "
                     // joins
-                    + "ai.CHANNEL_STACK_ID = cs.ID and cs.SPOT_ID = s.ID";
+                    + "ai.CHANNEL_STACK_ID = cs.ID and cs.SPOT_ID = s.ID "
+                    // TODO 2010-07-27, Tomasz Pylak: select the first image if there are many time
+                    // points or depth scans.
+                    // Should be deleted when support for time points will be added!
+                    + "order by cs.T_in_SEC, cs.Z_in_M limit 1";
 
     // select acquired_images.images.* from acquired_images
     @Select("select i.* " + "from ACQUIRED_IMAGES as ai join IMAGES as i on ai.IMG_ID = i.ID "
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/genedata/FeatureStorageProcessorTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/genedata/FeatureStorageProcessorTest.java
index 1f233bf5b93..6cfc05a3cce 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/genedata/FeatureStorageProcessorTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/genedata/FeatureStorageProcessorTest.java
@@ -33,7 +33,6 @@ import org.testng.annotations.Test;
 import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
 import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.etlserver.IStorageProcessor;
-import ch.systemsx.cisd.etlserver.PlateDimensionParser;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
@@ -41,6 +40,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GenericValueEntityPrope
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateDimensionParser;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingQueryDAO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgDatasetDTO;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO;
-- 
GitLab