From 64fb1cecf045db101653eab2452b6e17521ea0a2 Mon Sep 17 00:00:00 2001
From: buczekp <buczekp>
Date: Mon, 16 Aug 2010 17:31:49 +0000
Subject: [PATCH] [LMS-1645] added tile grid for channel stack with slider

SVN: 17468
---
 .../detailviewers/WellContentDialog.java      | 176 +++++++++++++++++-
 .../basic/dto/ChannelStackImageReference.java |  20 +-
 2 files changed, 187 insertions(+), 9 deletions(-)

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 2aed2fbef50..e8a2bfbc17d 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,13 +16,23 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening.client.web.client.application.detailviewers;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.Map.Entry;
 
 import com.extjs.gxt.ui.client.Style.Scroll;
+import com.extjs.gxt.ui.client.event.Events;
+import com.extjs.gxt.ui.client.event.Listener;
+import com.extjs.gxt.ui.client.event.SliderEvent;
 import com.extjs.gxt.ui.client.widget.Component;
 import com.extjs.gxt.ui.client.widget.Dialog;
 import com.extjs.gxt.ui.client.widget.Html;
+import com.extjs.gxt.ui.client.widget.Label;
 import com.extjs.gxt.ui.client.widget.LayoutContainer;
+import com.extjs.gxt.ui.client.widget.Slider;
 import com.extjs.gxt.ui.client.widget.Text;
 import com.extjs.gxt.ui.client.widget.layout.FitLayout;
 import com.extjs.gxt.ui.client.widget.layout.RowLayout;
@@ -119,8 +129,13 @@ public class WellContentDialog extends Dialog
             DefaultChannelState channelState, IViewContext<?> viewContext)
     {
         System.out.println("result: " + channelStackImages);
-        // TODO 2010-08-16, Tomasz Pylak: implement me!
-        return new LayoutContainer();
+        float imageSizeMultiplyFactor = getImageSizeMultiplyFactor(images);
+        String sessionId = getSessionId(viewContext);
+
+        return createTilesGridForStack(channelStackImages, images, channelState.getDefaultChannel(images
+                .getChannelsNames()), sessionId,
+                (int) (ONE_IMAGE_WIDTH_PX * imageSizeMultiplyFactor),
+                (int) (ONE_IMAGE_HEIGHT_PX * imageSizeMultiplyFactor));
     }
 
     private static int getDialogWidth(final WellImages images)
@@ -295,7 +310,7 @@ public class WellContentDialog extends Dialog
                 public LayoutContainer create(String channel)
                 {
                     String sessionId = getSessionId(viewContext);
-                    return createTilesGrid(images, channel, sessionId,
+                    return createTilesGridWithSlider(images, channel, sessionId,
                             (int) (ONE_IMAGE_WIDTH_PX * imageSizeMultiplyFactor),
                             (int) (ONE_IMAGE_HEIGHT_PX * imageSizeMultiplyFactor));
                 }
@@ -354,9 +369,160 @@ public class WellContentDialog extends Dialog
         return container;
     }
 
+    private static LayoutContainer createTilesGridForStack(
+            List<ChannelStackImageReference> channelStackImages, WellImages images, String channel,
+            String sessionId, int imageWidth, int imageHeight)
+    {
+        final LayoutContainer mainContainer = new LayoutContainer();
+
+        final List<LayoutContainer> frames = new ArrayList<LayoutContainer>();
+        Map<Float, List<ChannelStackImageReference>> channelStackImagesByTimepoint =
+                groupImagesByTimepoint(channelStackImages);
+
+        int counter = 0;
+        for (Entry<Float, List<ChannelStackImageReference>> entry : channelStackImagesByTimepoint
+                .entrySet())
+        {
+            List<ChannelStackImageReference> imageReferences = entry.getValue();
+            Collections.sort(imageReferences); // TODO needed? were data already sorted?
+            final LayoutContainer container =
+                    new LayoutContainer(new TableLayout(images.getTileColsNum()));
+            frames.add(container);
+            for (ChannelStackImageReference imageReference : imageReferences)
+            {
+                Component tileContent;
+                String imageURL =
+                        createDatastoreImageUrl(images, channel, imageReference, imageWidth,
+                                imageHeight, sessionId);
+                tileContent = new Html(imageURL);
+                tileContent.setHeight("" + imageHeight);
+                PlateStyleSetter.setPointerCursor(tileContent);
+                container.add(tileContent);
+            }
+            mainContainer.add(container);
+            if (counter > 0)
+            {
+                container.setVisible(false);
+            }
+            counter++;
+        }
+
+        final Float[] timepoints = channelStackImagesByTimepoint.keySet().toArray(new Float[0]);
+        final Slider slider = createTimepointsSlider(frames.size() - 1, new Listener<SliderEvent>()
+            {
+                public void handleEvent(SliderEvent e)
+                {
+                    int oldValue = e.getOldValue();
+                    int newValue = e.getNewValue();
+                    frames.get(oldValue).hide();
+                    frames.get(newValue).show();
+                    mainContainer.remove(mainContainer.getItem(0));
+                    mainContainer.insert(new Label(createTimepointLabel(timepoints, newValue)), 0);
+                    mainContainer.layout();
+                }
+            });
+        mainContainer.insert(slider, 0);
+        mainContainer.insert(new Label(createTimepointLabel(timepoints, 0)), 0);
+        slider.setValue(0);
+
+        return mainContainer;
+    }
+
+    private static String createTimepointLabel(Float[] timepoints, int value)
+    {
+        return "Timepoint: " + timepoints[value] + "sec (" + value + "/" + (timepoints.length - 1)
+                + ")";
+    }
+
+    private static Map<Float, List<ChannelStackImageReference>> groupImagesByTimepoint(
+            List<ChannelStackImageReference> channelStackImages)
+    {
+        Map<Float, List<ChannelStackImageReference>> result =
+                new TreeMap<Float, List<ChannelStackImageReference>>();
+        for (ChannelStackImageReference ref : channelStackImages)
+        {
+            Float t = ref.tryGetTimepoint();
+            List<ChannelStackImageReference> imageReferences = result.get(t);
+            if (imageReferences == null)
+            {
+                imageReferences = new ArrayList<ChannelStackImageReference>();
+                result.put(t, imageReferences);
+            }
+            imageReferences.add(ref);
+        }
+        return result;
+    }
+
+    // TODO 2010-08-16, Piotr Buczek: remove this code - this is just to demo slider behaviour
+    private static LayoutContainer createTilesGridWithSlider(WellImages images, String channel,
+            String sessionId, int imageWidth, int imageHeight)
+    {
+        final LayoutContainer mainContainer = new LayoutContainer();
+
+        final List<LayoutContainer> frames = new ArrayList<LayoutContainer>();
+        final List<String> channelNames = images.getChannelsNames();
+        final int channels = channelNames.size() - 1;
+
+        int counter = 0;
+        for (String channelName : channelNames)
+        {
+            final LayoutContainer container =
+                    new LayoutContainer(new TableLayout(images.getTileColsNum()));
+            frames.add(container);
+            for (int row = 1; row <= images.getTileRowsNum(); row++)
+            {
+                for (int col = 1; col <= images.getTileColsNum(); col++)
+                {
+                    Component tileContent;
+                    String imageURL =
+                            createDatastoreImageUrl(images, channelName, row, col, imageWidth,
+                                    imageHeight, sessionId);
+                    tileContent = new Html(imageURL);
+                    tileContent.setHeight("" + imageHeight);
+                    PlateStyleSetter.setPointerCursor(tileContent);
+                    container.add(tileContent);
+                }
+            }
+            mainContainer.add(container);
+            if (counter > 0)
+            {
+                container.setVisible(false);
+            }
+            counter++;
+        }
+
+        final Slider slider = createTimepointsSlider(frames.size() - 1, new Listener<SliderEvent>()
+            {
+                public void handleEvent(SliderEvent e)
+                {
+                    int oldValue = e.getOldValue();
+                    int newValue = e.getNewValue();
+                    frames.get(oldValue).hide();
+                    frames.get(newValue).show();
+                    mainContainer.remove(mainContainer.getItem(0));
+                    mainContainer.insert(new Label("Timepoint: " + newValue + "/" + channels), 0);
+                    mainContainer.layout();
+                }
+            });
+        mainContainer.insert(slider, 0);
+        mainContainer.insert(new Label("Timepoint: 0/" + channels), 0);
+        slider.setValue(0);
+
+        return mainContainer;
+    }
+
+    private static final Slider createTimepointsSlider(int maxValue, Listener<SliderEvent> listener)
+    {
+        final Slider slider = new Slider();
+        slider.setWidth(230);
+        slider.setIncrement(1);
+        slider.setMaxValue(maxValue);
+        slider.setClickToChange(true);
+        slider.addListener(Events.Change, listener);
+        return slider;
+    }
+
     /** generates URL of an image on Data Store server */
-    // TODO 2010-08-16, Tomasz Pylak: implement and use me!!!!
-    @SuppressWarnings("unused")
     private static String createDatastoreImageUrl(WellImages images, String channel,
             ChannelStackImageReference channelStackRef, int width, int height, String sessionID)
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/ChannelStackImageReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/ChannelStackImageReference.java
index 95285db0186..bdd0a67c72a 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/ChannelStackImageReference.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/ChannelStackImageReference.java
@@ -24,7 +24,8 @@ import com.google.gwt.user.client.rpc.IsSerializable;
  * 
  * @author Tomasz Pylak
  */
-public class ChannelStackImageReference implements IsSerializable
+public class ChannelStackImageReference implements IsSerializable,
+        Comparable<ChannelStackImageReference>
 {
     // technical id in the imaging db
     private long channelStackTechId;
@@ -40,13 +41,13 @@ public class ChannelStackImageReference implements IsSerializable
     }
 
     public ChannelStackImageReference(long channelStackTechId, int tileRow, int tileCol,
-            Float orNull, Float orNull2)
+            Float tOrNull, Float zOrNull)
     {
         this.channelStackTechId = channelStackTechId;
         this.tileRow = tileRow;
         this.tileCol = tileCol;
-        tOrNull = orNull;
-        zOrNull = orNull2;
+        this.tOrNull = tOrNull;
+        this.zOrNull = zOrNull;
     }
 
     public long getChannelStackTechId()
@@ -90,4 +91,15 @@ public class ChannelStackImageReference implements IsSerializable
         return "tile [" + tileRow + "," + tileCol + "]" + desc;
     }
 
+    public int compareTo(ChannelStackImageReference other)
+    {
+        if (this.tileRow == other.tileRow)
+        {
+            return this.tileCol < other.tileCol ? -1 : (this.tileCol == other.tileCol ? 0 : 1);
+        } else
+        {
+            return this.tileRow < other.tileRow ? -1 : 1;
+        }
+    }
+
 }
-- 
GitLab