From dff11e09fbb50820298fcb2dc844d51a1bdbffe7 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Wed, 21 Oct 2009 09:24:17 +0000
Subject: [PATCH] LMS-1231 TableModel refactored to allow ImageTableCell.
 URLMethodWithParameters encoded.

SVN: 13021
---
 .../data/DataSetReportColumnDefinition.java   |  42 +++++-
 .../ui/data/DataSetReporterGrid.java          |  49 ++++---
 .../ui/grid/AbstractBrowserGrid.java          |   1 +
 .../openbis/generic/server/CommonServer.java  |   7 +-
 .../shared/basic/URLMethodWithParameters.java |  65 ++++++++-
 .../dto/DatastoreServiceDescription.java      |  14 +-
 .../basic/dto/ISerializableComparable.java    |  32 +++++
 .../shared/basic/dto/ImageTableCell.java      | 127 ++++++++++++++++++
 .../shared/basic/dto/StringTableCell.java     |  80 +++++++++++
 .../generic/shared/basic/dto/TableModel.java  |   2 +-
 .../shared/basic/dto/TableModelRow.java       |   8 +-
 .../basic/URLMethodWithParametersTest.java    |  35 +++++
 12 files changed, 426 insertions(+), 36 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ISerializableComparable.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ImageTableCell.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/StringTableCell.java
 create mode 100644 openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/URLMethodWithParametersTest.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/data/DataSetReportColumnDefinition.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/data/DataSetReportColumnDefinition.java
index 387ab0c9d54..c5f07352b86 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/data/DataSetReportColumnDefinition.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/data/DataSetReportColumnDefinition.java
@@ -19,6 +19,9 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.column
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.StringUtils;
 import ch.systemsx.cisd.openbis.generic.shared.basic.GridRowModel;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IColumnDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.basic.URLMethodWithParameters;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ISerializableComparable;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ImageTableCell;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRow;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel.TableModelColumnHeader;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel.TableModelColumnType;
@@ -31,10 +34,14 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel.TableModelCo
 public class DataSetReportColumnDefinition implements IColumnDefinition<TableModelRow>
 {
     private TableModelColumnHeader columnHeader;
+    private String downloadURL;
+    private String sessionID;
 
-    public DataSetReportColumnDefinition(TableModelColumnHeader columnHeader)
+    public DataSetReportColumnDefinition(TableModelColumnHeader columnHeader, String downloadURL, String sessionID)
     {
         this.columnHeader = columnHeader;
+        this.downloadURL = downloadURL;
+        this.sessionID = sessionID;
     }
 
     public Comparable<?> getComparableValue(GridRowModel<TableModelRow> rowModel)
@@ -78,9 +85,24 @@ public class DataSetReportColumnDefinition implements IColumnDefinition<TableMod
     public String getValue(GridRowModel<TableModelRow> rowModel)
     {
         int index = columnHeader.getIndex();
-        return rowModel.getOriginalObject().getValues().get(index);
+        TableModelRow originalObject = rowModel.getOriginalObject();
+        ISerializableComparable cell = originalObject.getValues().get(index);
+        if (cell instanceof ImageTableCell == false)
+        {
+            return cell.toString();
+        }
+        ImageTableCell imageCell = (ImageTableCell) cell;
+        URLMethodWithParameters methodWithParameters =
+            new URLMethodWithParameters(downloadURL + "/datastore_server/" + imageCell.getPath());
+        methodWithParameters.addParameter("sessionID", sessionID);
+        String linkURL = methodWithParameters.toString();
+        methodWithParameters.addParameter("mode", "thumbnail"
+                + imageCell.getMaxThumbnailWidth() + "x" + imageCell.getMaxThumbnailHeight());
+        String imageURL = methodWithParameters.toString();
+        return "<div align='center'><a class='link-style' href='" + linkURL + "' target='_blank'><img src='"
+                + imageURL + "' alt='" + cell.toString() + "'/></a></div>";
     }
-
+    
     public String tryToGetProperty(String key)
     {
         return null;
@@ -99,4 +121,18 @@ public class DataSetReportColumnDefinition implements IColumnDefinition<TableMod
         this.columnHeader = columnHeader;
     }
 
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setDownloadURL(String downloadURL)
+    {
+        this.downloadURL = downloadURL;
+    }
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setSessionID(String sessionID)
+    {
+        this.sessionID = sessionID;
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporterGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporterGrid.java
index 682da29151c..707de438527 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporterGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporterGrid.java
@@ -70,33 +70,20 @@ public class DataSetReporterGrid extends
             TableModelReference tableModelReference, DatastoreServiceDescription service)
     {
         final DataSetReporterGrid grid =
-                new DataSetReporterGrid(viewContext, tableModelReference, service.getKey());
+                new DataSetReporterGrid(viewContext, tableModelReference, service.getKey(), service
+                        .getDownloadURL());
         return grid.asDisposableWithoutToolbar();
     }
 
-    private static List<IColumnDefinitionUI<TableModelRow>> createColumnDefinitions(
-            List<TableModelColumnHeader> header)
-    {
-        List<IColumnDefinitionUI<TableModelRow>> columns =
-                new ArrayList<IColumnDefinitionUI<TableModelRow>>();
-        int i = 0;
-        for (TableModelColumnHeader columnHeader : header)
-        {
-            boolean isHidden = (i > MAX_SHOWN_COLUMNS);
-            columns.add(new DatasetReportColumnUI(columnHeader, isHidden));
-            i++;
-        }
-        return columns;
-    }
-
     public static class DatasetReportColumnUI extends DataSetReportColumnDefinition implements
             IColumnDefinitionUI<TableModelRow>
     {
         private boolean isHidden;
 
-        public DatasetReportColumnUI(TableModelColumnHeader columnHeader, boolean isHidden)
+        public DatasetReportColumnUI(TableModelColumnHeader columnHeader, String downloadURL,
+                String sessionID, boolean isHidden)
         {
-            super(columnHeader);
+            super(columnHeader, downloadURL, sessionID);
             this.isHidden = isHidden;
         }
 
@@ -119,7 +106,7 @@ public class DataSetReporterGrid extends
         @SuppressWarnings("unused")
         private DatasetReportColumnUI()
         {
-            this(null, false);
+            this(null, null, null, false);
         }
     }
 
@@ -134,10 +121,13 @@ public class DataSetReporterGrid extends
 
     private final String reportKind;
 
+    private final String downloadURL;
+
     private DataSetReporterGrid(IViewContext<ICommonClientServiceAsync> viewContext,
-            TableModelReference tableModelReference, String reportKind)
+            TableModelReference tableModelReference, String reportKind, String downloadURL)
     {
         super(viewContext, GRID_ID, false, true, DisplayTypeIDGenerator.DATA_SET_REPORTING_GRID);
+        this.downloadURL = downloadURL;
         setId(BROWSER_ID);
         this.tableHeader = tableModelReference.getHeader();
         this.resultSetKey = tableModelReference.getResultSetKey();
@@ -154,7 +144,7 @@ public class DataSetReporterGrid extends
     @Override
     protected BaseEntityModel<TableModelRow> createModel(GridRowModel<TableModelRow> entity)
     {
-        return new BaseEntityModel<TableModelRow>(entity, createColumnDefinitions(tableHeader));
+        return new BaseEntityModel<TableModelRow>(entity, createColDefinitions());
     }
 
     @Override
@@ -214,6 +204,21 @@ public class DataSetReporterGrid extends
     @Override
     protected ColumnDefsAndConfigs<TableModelRow> createColumnsDefinition()
     {
-        return ColumnDefsAndConfigs.create(createColumnDefinitions(tableHeader));
+        return ColumnDefsAndConfigs.create(createColDefinitions());
+    }
+
+    private List<IColumnDefinitionUI<TableModelRow>> createColDefinitions()
+    {
+        String sessionID = viewContext.getModel().getSessionContext().getSessionID();
+        List<IColumnDefinitionUI<TableModelRow>> columns =
+                new ArrayList<IColumnDefinitionUI<TableModelRow>>();
+        int i = 0;
+        for (TableModelColumnHeader columnHeader : tableHeader)
+        {
+            boolean isHidden = (i > MAX_SHOWN_COLUMNS);
+            columns.add(new DatasetReportColumnUI(columnHeader, downloadURL, sessionID, isHidden));
+            i++;
+        }
+        return columns;
     }
 }
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 02cf7f67672..93b7d1cce3f 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
@@ -659,6 +659,7 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
             onComplete(false);
             pagingToolbar.enable(); // somehow enabling toolbar is lost in its handleEvent() method
             // no need to show error message - it should be shown by DEFAULT_CALLBACK_LISTENER
+            caught.printStackTrace();
             delegate.onFailure(caught);
         }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index b92e955c3e0..e9c2eaa0cd3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -1586,8 +1586,11 @@ public final class CommonServer extends AbstractServer<ICommonServer> implements
     {
         String[] datasetTypeCodes = extractCodes(service.getDatasetTypes());
         String dssCode = service.getDataStore().getCode();
-        return new DatastoreServiceDescription(service.getKey(), service.getLabel(),
-                datasetTypeCodes, dssCode);
+        DatastoreServiceDescription dssDescription =
+                new DatastoreServiceDescription(service.getKey(), service.getLabel(),
+                        datasetTypeCodes, dssCode);
+        dssDescription.setDownloadURL(service.getDataStore().getDownloadUrl());
+        return dssDescription;
     }
 
     private static String[] extractCodes(Set<DataSetTypePE> datasetTypes)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/URLMethodWithParameters.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/URLMethodWithParameters.java
index be8733f8395..76fcfca7591 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/URLMethodWithParameters.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/URLMethodWithParameters.java
@@ -29,18 +29,77 @@ public class URLMethodWithParameters implements IsSerializable
 
     public URLMethodWithParameters(String methodName)
     {
-        builder = new StringBuilder(methodName);
+        builder = new StringBuilder();
+        for (int i = 0, n = methodName.length(); i < n; i++)
+        {
+            char c = methodName.charAt(i);
+            if (c == '/')
+            {
+                builder.append(c);
+            } else
+            {
+                builder.append(encode(c));
+            }
+                
+        }
     }
 
     public void addParameter(String parameterName, Object value)
     {
-        builder.append(delim).append(parameterName).append('=');
+        builder.append(delim).append(encode(parameterName)).append('=');
         if (value != null)
         {
-            builder.append(value);
+            builder.append(encode(value.toString()));
         }
         delim = '&';
     }
+    
+    private String encode(String string)
+    {
+        StringBuilder buffer = new StringBuilder();
+        for (int i = 0, n = string.length(); i < n; i++)
+        {
+            buffer.append(encode(string.charAt(i)));
+        }
+        return buffer.toString();
+    }
+    
+    // When encoding a String, the following rules apply:
+    //
+    // The alphanumeric characters "a" through "z", "A" through "Z" and "0" through "9" remain the
+    // same.
+    // The special characters ".", "-", "*", and "_" remain the same.
+    // The space character " " is converted into a plus sign "+".
+    // All other characters are unsafe and are first converted into one or more bytes using some
+    // encoding scheme. Then each byte is represented by the 3-character string "%xy", where xy is
+    // the two-digit hexadecimal representation of the byte. The recommended encoding scheme to use
+    // is UTF-8. However, for compatibility reasons, if an encoding is not specified, then the
+    // default encoding of the platform is used.
+    // For example using UTF-8 as the encoding scheme the string "The string Ÿ@foo-bar" would get
+    // converted to "The+string+%C3%BC%40foo-bar" because in UTF-8 the character Ÿ is encoded as two
+    // bytes C3 (hex) and BC (hex), and the character @ is encoded as one byte 40 (hex).
+    private String encode(char c)
+    {
+        if (".-*_:".indexOf(c) >= 0 || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))
+        {
+            return Character.toString(c);
+        }
+        if (c == ' ')
+        {
+            return "+";
+        }
+        int b1 = (c >> 8) & 0xff;
+        int b2 = c & 0xff;
+        return (b1 == 0 ? "" : encode(b1)) + encode(b2);
+    }
+    
+    private String encode(int number)
+    {
+        return "%" + Integer.toHexString((number >> 4) & 0xf) + Integer.toHexString(number & 0xf);
+        
+    }
+
+
 
     @Override
     public String toString()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/DatastoreServiceDescription.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/DatastoreServiceDescription.java
index 132704e031c..3bdb92fedb8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/DatastoreServiceDescription.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/DatastoreServiceDescription.java
@@ -27,7 +27,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
  */
 public class DatastoreServiceDescription implements IsSerializable, Serializable
 {
-    private static final long serialVersionUID = ServiceVersionHolder.VERSION;
+     private static final long serialVersionUID = ServiceVersionHolder.VERSION;
 
     private String key;
 
@@ -37,6 +37,8 @@ public class DatastoreServiceDescription implements IsSerializable, Serializable
 
     private String datastoreCode;
 
+    private String downloadURL;
+
     @SuppressWarnings("unused")
     // for GWT serialization
     private DatastoreServiceDescription()
@@ -75,6 +77,16 @@ public class DatastoreServiceDescription implements IsSerializable, Serializable
         return datastoreCode;
     }
 
+    public String getDownloadURL()
+    {
+        return downloadURL;
+    }
+
+    public void setDownloadURL(String downloadURL)
+    {
+        this.downloadURL = downloadURL;
+    }
+    
     // for GWT serialization
 
     @SuppressWarnings("unused")
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ISerializableComparable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ISerializableComparable.java
new file mode 100644
index 00000000000..3e91638351a
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ISerializableComparable.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2009 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.shared.basic.dto;
+
+import java.io.Serializable;
+
+import com.google.gwt.user.client.rpc.IsSerializable;
+
+/**
+ * Interface for objects which are comparable, java.io.Serializable and GWT serializable.
+ * 
+ * Implementations should override {@link Object#equals(Object)} and {@link Object#hashCode()}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface ISerializableComparable extends IsSerializable, Serializable, Comparable<ISerializableComparable>
+{
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ImageTableCell.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ImageTableCell.java
new file mode 100644
index 00000000000..b02ce24ecd4
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ImageTableCell.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2009 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.shared.basic.dto;
+
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ImageTableCell implements ISerializableComparable
+{
+    private static final long serialVersionUID = ServiceVersionHolder.VERSION;
+    
+    private static String getPath(String dataSetCode, String dataSetLocation, String originalPath)
+    {
+        int indexOfLocation = originalPath.indexOf(dataSetLocation);
+        if (indexOfLocation < 0)
+        {
+            throw new IllegalArgumentException("Data set location '" + dataSetLocation
+                    + "' inconsistent with original path: " + originalPath);
+        }
+        return dataSetCode + originalPath.substring(indexOfLocation + dataSetLocation.length());
+    }
+    
+    private String path;
+
+    private int maxThumbnailWidth;
+
+    private int maxThumbnailHeight;
+    
+    public ImageTableCell(String dataSetCode, String dataSetLocation, String originalPath,
+            int maxThumbnailWidth, int maxThumbnailHeight)
+    {
+        this(getPath(dataSetCode, dataSetLocation, originalPath), maxThumbnailWidth, maxThumbnailHeight);
+    }
+    
+    public ImageTableCell(String path, int maxThumbnailWidth, int maxThumbnailHeight)
+    {
+        System.out.println("path:"+path);
+        this.path = path;
+        this.maxThumbnailWidth = maxThumbnailWidth;
+        this.maxThumbnailHeight = maxThumbnailHeight;
+    }
+    
+    public String getPath()
+    {
+        return path;
+    }
+    
+    public int getMaxThumbnailWidth()
+    {
+        return maxThumbnailWidth;
+    }
+    
+    public int getMaxThumbnailHeight()
+    {
+        return maxThumbnailHeight;
+    }
+
+    public int compareTo(ISerializableComparable o)
+    {
+        return toString().compareTo(String.valueOf(o));
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return this == obj || (obj instanceof ImageTableCell && ((ImageTableCell) obj).path.equals(path));
+    }
+    
+    @Override
+    public int hashCode()
+    {
+        return path.hashCode();
+    }
+    
+    @Override
+    public String toString()
+    {
+        return path;
+    }
+    
+    // ---------------------------
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private ImageTableCell()
+    {
+    }
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setPath(String path)
+    {
+        this.path = path;
+    }
+    
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setMaxThumbnailWidth(int maxThumbnailWidth)
+    {
+        this.maxThumbnailWidth = maxThumbnailWidth;
+    }
+    
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setMaxThumbnailHeight(int maxThumbnailHeight)
+    {
+        this.maxThumbnailHeight = maxThumbnailHeight;
+    }
+}
+
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/StringTableCell.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/StringTableCell.java
new file mode 100644
index 00000000000..eef53885a0b
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/StringTableCell.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2009 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.shared.basic.dto;
+
+
+/**
+ * Table cell wrapping a string.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class StringTableCell implements ISerializableComparable
+{
+    private static final long serialVersionUID = ServiceVersionHolder.VERSION;
+    
+    private String string;
+
+    public StringTableCell(String string)
+    {
+        if (string == null)
+        {
+            throw new IllegalArgumentException("Unspecified string.");
+        }
+        this.string = string;
+    }
+
+    public int compareTo(ISerializableComparable o)
+    {
+        return string.compareTo(o.toString());
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return this == obj
+                || (obj instanceof StringTableCell && string.equals(((StringTableCell) obj).string));
+   }
+    
+    @Override
+    public int hashCode()
+    {
+        return string.hashCode();
+    }
+    
+    @Override
+    public String toString()
+    {
+        return string;
+    }
+    
+    // ---------------------------
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private StringTableCell()
+    {
+    }
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setString(String string)
+    {
+        this.string = string;
+    }
+
+    
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/TableModel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/TableModel.java
index bda57a3ed6a..8c567940f73 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/TableModel.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/TableModel.java
@@ -82,7 +82,7 @@ public class TableModel implements IsSerializable, Serializable
 
     public static enum TableModelColumnType implements IsSerializable
     {
-        DATE, INTEGER, REAL, TEXT, BOOLEAN
+        DATE, INTEGER, REAL, TEXT, BOOLEAN, THUMBNAIL
     }
 
     public static class TableModelColumnHeader implements IsSerializable, Serializable
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/TableModelRow.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/TableModelRow.java
index b42c0f2bf3d..8c4e7d557d3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/TableModelRow.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/TableModelRow.java
@@ -31,14 +31,14 @@ public class TableModelRow implements IsSerializable, Serializable
     private static final long serialVersionUID = ServiceVersionHolder.VERSION;
 
     // values in each column from left to right
-    private List<String> values;
+    private List<ISerializableComparable> values;
 
-    public TableModelRow(List<String> values)
+    public TableModelRow(List<ISerializableComparable> values)
     {
         this.values = values;
     }
 
-    public List<String> getValues()
+    public List<ISerializableComparable> getValues()
     {
         return values;
     }
@@ -53,7 +53,7 @@ public class TableModelRow implements IsSerializable, Serializable
 
     // GWT only
     @SuppressWarnings("unused")
-    private void setValues(List<String> values)
+    private void setValues(List<ISerializableComparable> values)
     {
         this.values = values;
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/URLMethodWithParametersTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/URLMethodWithParametersTest.java
new file mode 100644
index 00000000000..1523b54842f
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/URLMethodWithParametersTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2009 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.shared.basic;
+
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class URLMethodWithParametersTest extends AssertJUnit
+{
+    @Test
+    public void test()
+    {
+        URLMethodWithParameters method = new URLMethodWithParameters("http://my.host:1234/The string Ÿ@foo-bar");
+        assertEquals("http://my.host:1234/The+string+%fc%40foo-bar", method.toString());
+    }
+}
-- 
GitLab