From 7325f799fe94d437f9e7ba2e1ce0e9e8fdcd2f2e Mon Sep 17 00:00:00 2001
From: tpylak <tpylak>
Date: Wed, 15 Jul 2009 15:29:06 +0000
Subject: [PATCH] LMS-1035 add a grid with TableModel

SVN: 11766
---
 .../plugins/tasks/TableModelBuilder.java      |   2 +-
 .../web/client/ICommonClientService.java      |  17 +-
 .../web/client/ICommonClientServiceAsync.java |  17 +-
 .../framework/DisplayTypeIDGenerator.java     |   1 +
 .../framework/CommonColumnDefinition.java     |   5 +-
 .../data/DataSetReportColumnDefinition.java   |  95 +++++++++
 .../ui/data/DataSetComputeMenu.java           |  58 ++++--
 .../application/ui/data/DataSetReporter.java  |  49 -----
 .../ui/data/DataSetReporterGrid.java          | 192 ++++++++++++++++++
 .../ui/data/DataStoreServicesGrid.java        |   2 +
 .../ui/grid/AbstractBrowserGrid.java          |   3 +-
 .../ui/grid/BrowserGridPagingToolBar.java     |   5 +
 .../web/client/dto/TableModelReference.java   |  75 +++++++
 .../web/server/CommonClientService.java       |  54 +++--
 .../generic/shared/basic/dto/TableModel.java  |  18 +-
 15 files changed, 504 insertions(+), 89 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/data/DataSetReportColumnDefinition.java
 delete mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporter.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporterGrid.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/TableModelReference.java

diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/TableModelBuilder.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/TableModelBuilder.java
index 653d8c4dc49..237d9e901c4 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/TableModelBuilder.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/TableModelBuilder.java
@@ -43,7 +43,7 @@ public class TableModelBuilder
 
     public void addHeader(String title, TableModelColumnType type)
     {
-        header.add(new TableModelColumnHeader(title, type));
+        header.add(new TableModelColumnHeader(title, type, header.size()));
     }
 
     public void addRow(List<String> values)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
index 6fa7b71f6f6..8548d10397c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
@@ -38,6 +38,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.dto.RoleAssignment;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SearchableEntity;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableModelReference;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.VocabularyTermWithStats;
 import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolder;
@@ -65,7 +66,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ProjectUpdates;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleSetCode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRow;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Vocabulary;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTerm;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTermReplacement;
@@ -588,9 +589,21 @@ public interface ICommonClientService extends IClientService
     /**
      * Uses the specified datastore service to generate reports from the specified datasets.
      */
-    public TableModel createReportFromDatasets(DatastoreServiceDescription serviceDescription,
+    public TableModelReference createReportFromDatasets(
+            DatastoreServiceDescription serviceDescription,
             DisplayedOrSelectedDatasetCriteria displayedOrSelectedDatasetCriteria);
 
+    /**
+     * Returns a list of datasets report rows.
+     */
+    public ResultSet<TableModelRow> listDatasetReport(
+            DefaultResultSetConfig<String, TableModelRow> resultSetConfig);
+
+    /**
+     * Like {@link #prepareExportSamples(TableExportCriteria)}, but for TableModelRow.
+     */
+    public String prepareExportDatasetReport(TableExportCriteria<TableModelRow> exportCriteria);
+
     /**
      * Uses the specified datastore service to schedule processing of the specified datasets.
      */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
index 7f0ebb49519..ab303b0a983 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
@@ -40,6 +40,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.dto.RoleAssignment;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SearchableEntity;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableModelReference;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.VocabularyTermWithStats;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
@@ -66,7 +67,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ProjectUpdates;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleSetCode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRow;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Vocabulary;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTerm;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTermReplacement;
@@ -515,7 +516,19 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
      */
     public void createReportFromDatasets(DatastoreServiceDescription serviceDescription,
             DisplayedOrSelectedDatasetCriteria displayedOrSelectedDatasetCriteria,
-            AsyncCallback<TableModel> callback);
+            AsyncCallback<TableModelReference> callback);
+
+    /**
+     * @see ICommonClientService#listDatasetReport(DefaultResultSetConfig)
+     */
+    public void listDatasetReport(DefaultResultSetConfig<String, TableModelRow> resultSetConfig,
+            AsyncCallback<ResultSet<TableModelRow>> callback);
+
+    /**
+     * @see ICommonClientService#prepareExportDatasetReport(TableExportCriteria)
+     */
+    public void prepareExportDatasetReport(TableExportCriteria<TableModelRow> exportCriteria,
+            AsyncCallback<String> callback);
 
     /**
      * @see ICommonClientService#processDatasets(DatastoreServiceDescription,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/framework/DisplayTypeIDGenerator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/framework/DisplayTypeIDGenerator.java
index d1318091dec..587a7106592 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/framework/DisplayTypeIDGenerator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/framework/DisplayTypeIDGenerator.java
@@ -33,6 +33,7 @@ public enum DisplayTypeIDGenerator implements IDisplayTypeIDGenerator
     TYPE_BROWSER_GRID("type-browser-grid"),
     SEARCH_RESULT_GRID("search-result-grid"),
     DATA_SET_SEARCH_RESULT_GRID("data-set-search-result-grid"),
+    DATA_SET_REPORTING_GRID("data-set-reporting-grid"),
     PROJECT_BROWSER_GRID("project-browser-grid"),
     PERSON_BROWSER_GRID("person-browser-grid"),
     PLUGIN_TASKS_BROWSER_GRID("plugin-tasks-browser-grid"),
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/framework/CommonColumnDefinition.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/framework/CommonColumnDefinition.java
index 4dcc37d01f1..ea812d087da 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/framework/CommonColumnDefinition.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/framework/CommonColumnDefinition.java
@@ -16,10 +16,9 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.framework;
 
-
 /**
- * Definition of table columns for entities of type <code>T</code> together with the instructions
- * to render each column value.
+ * Definition of table columns for entities of type <code>T</code> together with the instructions to
+ * render each column value.
  * 
  * @author Tomasz Pylak
  * @author Franz-Josef Elmer
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
new file mode 100644
index 00000000000..7b34fa87349
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/data/DataSetReportColumnDefinition.java
@@ -0,0 +1,95 @@
+/*
+ * 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.client.web.client.application.ui.columns.specific.data;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IColumnDefinition;
+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;
+
+/**
+ * Definition of dataset report table columns.
+ * 
+ * @author Tomasz Pylak
+ */
+public class DataSetReportColumnDefinition implements IColumnDefinition<TableModelRow>
+{
+    private TableModelColumnHeader columnHeader;
+
+    public DataSetReportColumnDefinition(TableModelColumnHeader columnHeader)
+    {
+        this.columnHeader = columnHeader;
+    }
+
+    public Comparable<?> getComparableValue(TableModelRow rowModel)
+    {
+        TableModelColumnType type = columnHeader.getType();
+        String value = getValue(rowModel);
+        if (type == TableModelColumnType.REAL)
+        {
+            try
+            {
+                return new Float(value);
+            } catch (NumberFormatException e)
+            {
+                return new Float(0);
+            }
+        } else if (type == TableModelColumnType.INTEGER)
+        {
+            try
+            {
+                return new Long(value);
+            } catch (NumberFormatException e)
+            {
+                return new Long(0);
+            }
+        } else
+        {
+            return value;
+        }
+    }
+
+    public String getHeader()
+    {
+        return columnHeader.getTitle();
+    }
+
+    public String getIdentifier()
+    {
+        return "colIndex_" + columnHeader.getIndex();
+    }
+
+    public String getValue(TableModelRow rowModel)
+    {
+        int index = columnHeader.getIndex();
+        return rowModel.getValues().get(index);
+    }
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private DataSetReportColumnDefinition()
+    {
+    }
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setColumnHeader(TableModelColumnHeader columnHeader)
+    {
+        this.columnHeader = columnHeader;
+    }
+
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetComputeMenu.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetComputeMenu.java
index be49f2fc718..7ba835175d9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetComputeMenu.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetComputeMenu.java
@@ -29,10 +29,10 @@ import com.extjs.gxt.ui.client.data.ModelData;
 import com.extjs.gxt.ui.client.event.BaseEvent;
 import com.extjs.gxt.ui.client.event.Listener;
 import com.extjs.gxt.ui.client.event.SelectionEvent;
-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.MessageBox;
+import com.extjs.gxt.ui.client.widget.ProgressBar;
 import com.extjs.gxt.ui.client.widget.Window;
 import com.extjs.gxt.ui.client.widget.button.Button;
 import com.extjs.gxt.ui.client.widget.form.Radio;
@@ -52,6 +52,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.Actio
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.IActionMenuItem;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.ColumnConfigFactory;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.data.AbstractExternalDataGrid.SelectedAndDisplayedItems;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IDisposableComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.AbstractDataConfirmationDialog;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedAction;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedActionWithResult;
@@ -59,10 +60,10 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMess
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.StringUtils;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DisplayedOrSelectedDatasetCriteria;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableModelReference;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStoreServiceKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatastoreServiceDescription;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
 
 /**
  * 'Compute' menu for Data Sets.
@@ -163,14 +164,35 @@ public class DataSetComputeMenu extends TextToolItem
                                         createCriteria(selectedAndDisplayedItems, computeOnSelected);
                                 if (pluginTaskKind == DataStoreServiceKind.QUERIES)
                                 {
+                                    Dialog progressBar = createAndShowProgressBar();
                                     viewContext.getService().createReportFromDatasets(service,
-                                            criteria, new ReportDisplayCallback(viewContext));
+                                            criteria,
+                                            new ReportDisplayCallback(viewContext, progressBar));
                                 } else
                                 {
                                     viewContext.getService().processDatasets(service, criteria,
                                             new ProcessingDisplayCallback(viewContext));
                                 }
                             }
+
+                            private Dialog createAndShowProgressBar()
+                            {
+                                ProgressBar progressBar = new ProgressBar();
+                                progressBar.auto();
+
+                                Dialog dialog = new Dialog();
+                                String title = "Generating the report...";
+                                dialog.setTitle(title);
+
+                                dialog.add(progressBar);
+                                dialog.setButtons("");
+                                dialog.setAutoHeight(true);
+                                dialog.setClosable(false);
+                                dialog.addText(title);
+                                dialog.setResizable(false);
+                                dialog.show();
+                                return dialog;
+                            }
                         };
                 }
 
@@ -197,29 +219,37 @@ public class DataSetComputeMenu extends TextToolItem
         }
     }
 
-    private static final class ReportDisplayCallback extends AbstractAsyncCallback<TableModel>
+    private static final class ReportDisplayCallback extends
+            AbstractAsyncCallback<TableModelReference>
     {
+        private final IViewContext<ICommonClientServiceAsync> viewContext;
+
+        private final Dialog progressBar;
 
-        public ReportDisplayCallback(IViewContext<?> viewContext)
+        public ReportDisplayCallback(IViewContext<ICommonClientServiceAsync> viewContext,
+                Dialog progressBar)
         {
             super(viewContext);
+            this.viewContext = viewContext;
+            this.progressBar = progressBar;
         }
 
         @Override
-        protected void process(final TableModel tableModel)
+        protected void process(final TableModelReference tableModelReference)
         {
-            // TODO 2009-07-07, Tomasz Pylak: display a new tab with a grid
+            progressBar.close();
             final ITabItemFactory tabFactory = new ITabItemFactory()
                 {
                     public ITabItem create()
                     {
-                        Component component = DataSetReporter.create(tableModel);
-                        return DefaultTabItem.createUnaware("Data Store Report", component, false);
+                        IDisposableComponent component =
+                                DataSetReporterGrid.create(viewContext, tableModelReference);
+                        return DefaultTabItem.create("Data Store Report", component, viewContext);
                     }
 
                     public String getId()
                     {
-                        return DataSetReporter.createId();
+                        return DataSetReporterGrid.createId(tableModelReference.getResultSetKey());
                     }
                 };
             DispatcherHelper.dispatchNaviEvent(tabFactory);
@@ -446,13 +476,11 @@ public class DataSetComputeMenu extends TextToolItem
                             + "Unsupported Data Set types", dataSetTypes);
         }
 
-        private final String createDataSetTypeMsg(String singularMsgPrefix,
-                List<String> dataSetTypes)
+        private final String createDataSetTypeMsg(String msgPrefix, List<String> dataSetTypes)
         {
             StringBuilder sb = new StringBuilder();
-            sb.append(singularMsgPrefix);
-            sb.append(dataSetTypes.size() > 1 ? "s" : "");
-            sb.append(":");
+            sb.append(msgPrefix);
+            sb.append(": ");
             sb.append(StringUtils.joinList(dataSetTypes));
             return sb.toString();
         }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporter.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporter.java
deleted file mode 100644
index 9abfe3f003a..00000000000
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporter.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.client.web.client.application.ui.data;
-
-import com.extjs.gxt.ui.client.Style.Scroll;
-import com.extjs.gxt.ui.client.widget.Component;
-import com.extjs.gxt.ui.client.widget.Html;
-import com.extjs.gxt.ui.client.widget.LayoutContainer;
-
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericConstants;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
-
-/**
- * @author Tomasz Pylak
- */
-// TODO 2009-07-08, Tomasz Pylak: implement me, this is just a stub
-public class DataSetReporter
-{
-    protected static final String ID = GenericConstants.ID_PREFIX + "data-set-report";
-
-    public static String createId()
-    {
-        return ID;
-    }
-
-    public static Component create(TableModel tableModel)
-    {
-        LayoutContainer panel = new LayoutContainer();
-        panel.setScrollMode(Scroll.AUTO);
-        Html content = new Html("TODO");
-        panel.add(content);
-        return panel;
-    }
-
-}
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
new file mode 100644
index 00000000000..ecadbe3617f
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetReporterGrid.java
@@ -0,0 +1,192 @@
+/*
+ * 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.client.web.client.application.ui.data;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
+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.DisplayTypeIDGenerator;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.BaseEntityModel;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.framework.AbstractColumnDefinitionKind;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.framework.IColumnDefinitionUI;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.specific.data.DataSetReportColumnDefinition;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.AbstractBrowserGrid;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ColumnDefsAndConfigs;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IDisposableComponent;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IColumnDefinition;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ResultSet;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableModelReference;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRow;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel.TableModelColumnHeader;
+
+/**
+ * Grid displaying dataset reporting results. This grid is special comparing to other grids, because
+ * it cannot be refreshed and it is ensured, that the data for the grid are cached before it is
+ * created.
+ * 
+ * @author Tomasz Pylak
+ */
+public class DataSetReporterGrid extends
+        AbstractBrowserGrid<TableModelRow, BaseEntityModel<TableModelRow>>
+{
+    // browser consists of the grid and the paging toolbar
+    public static final String BROWSER_ID = GenericConstants.ID_PREFIX + "DataSetReporterGrid";
+
+    public static final String GRID_ID = BROWSER_ID + "_grid";
+
+    public static IDisposableComponent create(
+            final IViewContext<ICommonClientServiceAsync> viewContext,
+            TableModelReference tableModelReference)
+    {
+        final DataSetReporterGrid grid = new DataSetReporterGrid(viewContext, tableModelReference);
+        return grid.asDisposableWithoutToolbar();
+    }
+
+    private static List<IColumnDefinitionUI<TableModelRow>> createColumnDefinitions(
+            List<TableModelColumnHeader> header)
+    {
+        List<IColumnDefinitionUI<TableModelRow>> columns =
+                new ArrayList<IColumnDefinitionUI<TableModelRow>>();
+        for (TableModelColumnHeader columnHeader : header)
+        {
+            columns.add(new DatasetReportColumnUI(columnHeader));
+        }
+        return columns;
+    }
+
+    public static class DatasetReportColumnUI extends DataSetReportColumnDefinition implements
+            IColumnDefinitionUI<TableModelRow>
+    {
+        public DatasetReportColumnUI(TableModelColumnHeader columnHeader)
+        {
+            super(columnHeader);
+        }
+
+        public int getWidth()
+        {
+            return AbstractColumnDefinitionKind.DEFAULT_COLUMN_WIDTH;
+        }
+
+        public boolean isHidden()
+        {
+            return false;
+        }
+
+        // GWT only
+        @SuppressWarnings("unused")
+        private DatasetReportColumnUI()
+        {
+            super(null);
+        }
+    }
+
+    public static String createId(String idSuffix)
+    {
+        return BROWSER_ID + "_" + idSuffix;
+    }
+
+    private final List<TableModelColumnHeader> tableHeader;
+
+    private final String resultSetKey;
+
+    private DataSetReporterGrid(IViewContext<ICommonClientServiceAsync> viewContext,
+            TableModelReference tableModelReference)
+    {
+        super(viewContext, GRID_ID, false, true);
+        setId(BROWSER_ID);
+        this.tableHeader = tableModelReference.getHeader();
+        this.resultSetKey = tableModelReference.getResultSetKey();
+        updateDefaultRefreshButton();
+        setDisplayTypeIDGenerator(DisplayTypeIDGenerator.DATA_SET_REPORTING_GRID);
+
+    }
+
+    @Override
+    protected BaseEntityModel<TableModelRow> createModel(TableModelRow entity)
+    {
+        return new BaseEntityModel<TableModelRow>(entity, createColumnDefinitions(tableHeader));
+    }
+
+    @Override
+    protected void listEntities(DefaultResultSetConfig<String, TableModelRow> resultSetConfig,
+            AbstractAsyncCallback<ResultSet<TableModelRow>> callback)
+    {
+        // in all cases the data should be taken from the cache, and we know the key already
+        resultSetConfig.setResultSetKey(resultSetKey);
+        viewContext.getService().listDatasetReport(resultSetConfig, callback);
+    }
+
+    @Override
+    protected void prepareExportEntities(TableExportCriteria<TableModelRow> exportCriteria,
+            AbstractAsyncCallback<String> callback)
+    {
+        viewContext.getService().prepareExportDatasetReport(exportCriteria, callback);
+    }
+
+    public void update(Set<DatabaseModificationKind> observedModifications)
+    {
+        // do noting
+    }
+
+    @Override
+    protected List<IColumnDefinition<TableModelRow>> getInitialFilters()
+    {
+        return Collections.emptyList();
+    }
+
+    public DatabaseModificationKind[] getRelevantModifications()
+    {
+        return new DatabaseModificationKind[] {};
+    }
+
+    @Override
+    protected final boolean isRefreshEnabled()
+    {
+        /**
+         * Refresh is not possible. The reason is that we would have to regenerate the report using
+         * the datasets selected in another tab. But this tab may no longer exist!
+         */
+        return false;
+    }
+
+    @Override
+    protected void refresh()
+    {
+        refresh(null, false);
+    }
+
+    @Override
+    protected void showEntityViewer(TableModelRow entity, boolean editMode)
+    {
+        // do nothing
+    }
+
+    @Override
+    protected ColumnDefsAndConfigs<TableModelRow> createColumnsDefinition()
+    {
+        return ColumnDefsAndConfigs.create(createColumnDefinitions(tableHeader));
+    }
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataStoreServicesGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataStoreServicesGrid.java
index a091c3854a5..8376267783d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataStoreServicesGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataStoreServicesGrid.java
@@ -22,6 +22,7 @@ import java.util.List;
 import com.extjs.gxt.ui.client.Events;
 import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
 import com.extjs.gxt.ui.client.Style.SelectionMode;
+import com.extjs.gxt.ui.client.Style.SortDir;
 import com.extjs.gxt.ui.client.data.ModelData;
 import com.extjs.gxt.ui.client.event.Listener;
 import com.extjs.gxt.ui.client.event.SelectionEvent;
@@ -120,6 +121,7 @@ class DataStoreServicesGrid extends ContentPanel
                 new ListStore<PluginTaskDescriptionModel>();
         store.add(getPluginTaskModels(plugins));
         store.setSortField(ModelDataPropertyNames.LABEL);
+        store.setSortDir(SortDir.ASC);
 
         final ContentPanel cp = new ContentPanel();
 
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 5374a158c36..76ffeccc0bc 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
@@ -972,11 +972,12 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends BaseEntityMod
 
     private IDataRefreshCallback createInternalPostRefreshCallback()
     {
+        final boolean originalRefreshEnabled = pagingToolbar.isDefaultRefreshButtonEnabled();
         return new IDataRefreshCallback()
             {
                 public void postRefresh(boolean wasSuccessful)
                 {
-                    pagingToolbar.updateDefaultRefreshButton(true);
+                    pagingToolbar.updateDefaultRefreshButton(originalRefreshEnabled);
                     if (wasSuccessful)
                     {
                         pagingToolbar.updateDefaultConfigButton(true);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/BrowserGridPagingToolBar.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/BrowserGridPagingToolBar.java
index 82a81512bf2..f0a8e77d204 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/BrowserGridPagingToolBar.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/BrowserGridPagingToolBar.java
@@ -85,6 +85,11 @@ public final class BrowserGridPagingToolBar extends PagingToolBarAdapter
         add(new LabelToolItem(messageProvider.getMessage(Dict.ENTITY_OPERATIONS)));
     }
 
+    public boolean isDefaultRefreshButtonEnabled()
+    {
+        return refreshButton.isEnabled();
+    }
+
     protected final void updateDefaultRefreshButton(boolean isEnabled)
     {
         updateRefreshButton(refreshButton, isEnabled, messageProvider);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/TableModelReference.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/TableModelReference.java
new file mode 100644
index 00000000000..5a9acc2a3fe
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/TableModelReference.java
@@ -0,0 +1,75 @@
+/*
+ * 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.client.web.client.dto;
+
+import java.util.List;
+
+import com.google.gwt.user.client.rpc.IsSerializable;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel.TableModelColumnHeader;
+
+/**
+ * Stores:<br>
+ * - a pointer to rows of a table model in the server cache<br>
+ * - the table model header
+ * 
+ * @author Tomasz Pylak
+ */
+public class TableModelReference implements IsSerializable
+{
+    // a key at which data are stored in the server cache
+    private String resultSetKey;
+
+    private List<TableModelColumnHeader> header;
+
+    public TableModelReference(String resultSetKey, List<TableModelColumnHeader> header)
+    {
+        this.resultSetKey = resultSetKey;
+        this.header = header;
+    }
+
+    public String getResultSetKey()
+    {
+        return resultSetKey;
+    }
+
+    public List<TableModelColumnHeader> getHeader()
+    {
+        return header;
+    }
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private TableModelReference()
+    {
+    }
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setResultSetKey(String resultSetKey)
+    {
+        this.resultSetKey = resultSetKey;
+    }
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private void setHeader(List<TableModelColumnHeader> header)
+    {
+        this.header = header;
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
index f594f6826cb..3ba348b2f52 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
@@ -61,6 +61,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.dto.RoleAssignment;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SearchableEntity;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableModelReference;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.VocabularyTermWithStats;
 import ch.systemsx.cisd.openbis.generic.client.web.client.exception.InvalidSessionException;
 import ch.systemsx.cisd.openbis.generic.client.web.server.AbstractClientService.IDataStoreBaseURLProvider;
@@ -120,6 +121,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleSetCode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleTypePropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRow;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Vocabulary;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTerm;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTermReplacement;
@@ -1777,7 +1779,8 @@ public final class CommonClientService extends AbstractClientService implements
         }
     }
 
-    public TableModel createReportFromDatasets(DatastoreServiceDescription serviceDescription,
+    public TableModelReference createReportFromDatasets(
+            DatastoreServiceDescription serviceDescription,
             DisplayedOrSelectedDatasetCriteria displayedOrSelectedDatasetCriteria)
     {
         try
@@ -1785,14 +1788,47 @@ public final class CommonClientService extends AbstractClientService implements
             final String sessionToken = getSessionToken();
             List<String> datasetCodes =
                     extractDatasetCodes(displayedOrSelectedDatasetCriteria, serviceDescription);
-            return commonServer.createReportFromDatasets(sessionToken, serviceDescription,
-                    datasetCodes);
+            final TableModel tableModel =
+                    commonServer.createReportFromDatasets(sessionToken, serviceDescription,
+                            datasetCodes);
+            String resultSetKey = saveInCache(tableModel.getRows());
+            return new TableModelReference(resultSetKey, tableModel.getHeader());
         } catch (final UserFailureException e)
         {
             throw UserFailureExceptionTranslator.translate(e);
         }
     }
 
+    // Saves the specified rows in the cache.
+    // Returns a key in the cache where the data were saved.
+    private String saveInCache(final List<TableModelRow> tableModelRows)
+    {
+        DefaultResultSetConfig<String, TableModelRow> criteria =
+                new DefaultResultSetConfig<String, TableModelRow>();
+        criteria.setLimit(0); // we do not need any data now, just a key
+        ResultSet<TableModelRow> resultSet =
+                listEntities(criteria, new IOriginalDataProvider<TableModelRow>()
+                    {
+                        public List<TableModelRow> getOriginalData() throws UserFailureException
+                        {
+                            return tableModelRows;
+                        }
+                    });
+        return resultSet.getResultSetKey();
+    }
+
+    public ResultSet<TableModelRow> listDatasetReport(
+            DefaultResultSetConfig<String, TableModelRow> resultSetConfig)
+    {
+        IOriginalDataProvider<TableModelRow> dummyDataProvider = createDummyDataProvider();
+        return listEntities(resultSetConfig, dummyDataProvider);
+    }
+
+    public String prepareExportDatasetReport(TableExportCriteria<TableModelRow> criteria)
+    {
+        return prepareExportEntities(criteria);
+    }
+
     private List<String> extractDatasetCodes(
             DisplayedOrSelectedDatasetCriteria displayedOrSelectedDatasetCriteria)
     {
@@ -1836,17 +1872,6 @@ public final class CommonClientService extends AbstractClientService implements
         return result;
     }
 
-    //
-    // private static List<String> getDatasetCodes(List<ExternalData> datasets)
-    // {
-    // List<String> datasetCodes = new ArrayList<String>();
-    // for (ExternalData externalData : datasets)
-    // {
-    // datasetCodes.add(externalData.getCode());
-    // }
-    // return datasetCodes;
-    // }
-
     public void processDatasets(DatastoreServiceDescription serviceDescription,
             DisplayedOrSelectedDatasetCriteria displayedOrSelectedDatasetCriteria)
     {
@@ -1861,5 +1886,4 @@ public final class CommonClientService extends AbstractClientService implements
             throw UserFailureExceptionTranslator.translate(e);
         }
     }
-
 }
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 bc22617f6ed..bda57a3ed6a 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
@@ -93,10 +93,14 @@ public class TableModel implements IsSerializable, Serializable
 
         private TableModelColumnType type;
 
-        public TableModelColumnHeader(String title, TableModelColumnType type)
+        // allows to fetch the value for this column from the row content
+        private int index;
+
+        public TableModelColumnHeader(String title, TableModelColumnType type, int index)
         {
             this.title = title;
             this.type = type;
+            this.index = index;
         }
 
         public String getTitle()
@@ -109,6 +113,11 @@ public class TableModel implements IsSerializable, Serializable
             return type;
         }
 
+        public int getIndex()
+        {
+            return index;
+        }
+
         // GWT only
         @SuppressWarnings("unused")
         private TableModelColumnHeader()
@@ -128,5 +137,12 @@ public class TableModel implements IsSerializable, Serializable
         {
             this.type = type;
         }
+
+        // GWT only
+        @SuppressWarnings("unused")
+        private void setIndex(int index)
+        {
+            this.index = index;
+        }
     }
 }
-- 
GitLab