diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/MatchingEntitiesPanel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/MatchingEntitiesPanel.java
index 32946e05f875829f5dd90c7579b2b7a4ef78269d..94c9c22dffcb71e9d1fe8de5a376ac0d365ed4e7 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/MatchingEntitiesPanel.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/MatchingEntitiesPanel.java
@@ -26,10 +26,12 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAs
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.DispatcherHelper;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.ITabItemFactory;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.MatchingEntityModel;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.MatchingEntityModel.MatchingEntityColumnKind;
 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.IColumnDefinitionUI;
 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.MatchingEntity;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ResultSet;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SearchableEntity;
@@ -121,4 +123,12 @@ final class MatchingEntitiesPanel extends AbstractBrowserGrid<MatchingEntity, Ma
         viewContext.getService().prepareExportMatchingEntities(exportCriteria, callback);
     }
 
+    @Override
+    protected List<IColumnDefinition<MatchingEntity>> getAvailableFilters()
+    {
+        return asColumnFilters(new MatchingEntityColumnKind[]
+            { MatchingEntityColumnKind.ENTITY_KIND, MatchingEntityColumnKind.ENTITY_TYPE,
+                    MatchingEntityColumnKind.MATCHING_FIELD });
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/AbstractEntityModel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/AbstractEntityModel.java
index e0a954fda7f156f37263eff934d38242a2092a5d..52c95d80949dfc77d6b86a14d30bcf57cc713655 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/AbstractEntityModel.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/AbstractEntityModel.java
@@ -43,7 +43,7 @@ public class AbstractEntityModel<T> extends BaseModelData
     protected AbstractEntityModel(final T entity, IColumnDefinitionKind<T>[] colDefKinds,
             IMessageProvider msgProviderOrNull)
     {
-        this(entity, createColumnsSchemaFrom(colDefKinds, msgProviderOrNull));
+        this(entity, createColumnsDefinition(colDefKinds, msgProviderOrNull));
     }
 
     protected AbstractEntityModel(final T entity, List<? extends IColumnDefinition<T>> columnsSchema)
@@ -85,19 +85,19 @@ public class AbstractEntityModel<T> extends BaseModelData
     }
 
     /** @param msgProviderOrNull if null, no headers labels will be generated */
-    public static <T> List<IColumnDefinitionUI<T>> createColumnsSchemaFrom(
+    public static <T> List<IColumnDefinitionUI<T>> createColumnsDefinition(
             IColumnDefinitionKind<T>[] columnKinds, IMessageProvider msgProviderOrNull)
     {
         List<IColumnDefinitionUI<T>> list = new ArrayList<IColumnDefinitionUI<T>>();
         for (IColumnDefinitionKind<T> columnKind : columnKinds)
         {
-            list.add(createColumn(columnKind, msgProviderOrNull));
+            list.add(createColumnDefinition(columnKind, msgProviderOrNull));
         }
         return list;
     }
 
-    private static <T> IColumnDefinitionUI<T> createColumn(IColumnDefinitionKind<T> columnKind,
-            IMessageProvider messageProviderOrNull)
+    public static <T> IColumnDefinitionUI<T> createColumnDefinition(
+            IColumnDefinitionKind<T> columnKind, IMessageProvider messageProviderOrNull)
     {
         String headerText = null;
         if (messageProviderOrNull != null)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/ExperimentModel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/ExperimentModel.java
index 4bcecce28fd99e6e97f7bfa8d880ca48860509fb..326fa4ec8b9cef1b637919320de4cd79a57fb106 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/ExperimentModel.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/ExperimentModel.java
@@ -97,7 +97,7 @@ public final class ExperimentModel extends AbstractEntityModel<Experiment>
     private static List<IColumnDefinitionUI<Experiment>> createCommonColumnsSchema(
             IMessageProvider msgProviderOrNull)
     {
-        return createColumnsSchemaFrom(CommonExperimentColDefKind.values(), msgProviderOrNull);
+        return createColumnsDefinition(CommonExperimentColDefKind.values(), msgProviderOrNull);
     }
 
     private static ArrayList<IColumnDefinitionUI<Experiment>> createColDefList()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/ExternalDataModel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/ExternalDataModel.java
index e5650c82743acfd9110714c3e5290b2cdba17edb..3b9d12ee8f3fd7d5bb9a5cce06525cd47df54e79 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/ExternalDataModel.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/ExternalDataModel.java
@@ -44,7 +44,7 @@ public final class ExternalDataModel extends AbstractEntityModel<ExternalData>
     public static List<IColumnDefinitionUI<ExternalData>> createColumnsSchema(
             IMessageProvider msgProviderOrNull)
     {
-        return createColumnsSchemaFrom(CommonExternalDataColDefKind.values(), msgProviderOrNull);
+        return createColumnsDefinition(CommonExternalDataColDefKind.values(), msgProviderOrNull);
     }
 
     public final static List<ExternalDataModel> asExternalDataModels(final List<ExternalData> result)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/MatchingEntityModel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/MatchingEntityModel.java
index 90b5b49f158e44ae91cd7ef50148d9e691b3db1f..8b29d4b0f65cc1d67f66e3fbd88befa8a839f25f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/MatchingEntityModel.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/model/MatchingEntityModel.java
@@ -49,7 +49,7 @@ public final class MatchingEntityModel extends AbstractEntityModel<MatchingEntit
     public static List<IColumnDefinitionUI<MatchingEntity>> createColumnsSchema(
             IMessageProvider msgProviderOrNull)
     {
-        return createColumnsSchemaFrom(MatchingEntityColumnKind.values(), msgProviderOrNull);
+        return createColumnsDefinition(MatchingEntityColumnKind.values(), msgProviderOrNull);
     }
 
     public enum MatchingEntityColumnKind implements IColumnDefinitionKind<MatchingEntity>
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/experiment/ExperimentBrowserGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/experiment/ExperimentBrowserGrid.java
index da49dda923c68c57b373735a6e998f8ef8016ac4..6a01633ae2f85cd0fb9fc16ee0f6ea49e50fa1f4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/experiment/ExperimentBrowserGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/experiment/ExperimentBrowserGrid.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.experiment;
 
+import java.util.List;
+
 import com.extjs.gxt.ui.client.event.SelectionChangedListener;
 import com.extjs.gxt.ui.client.widget.LayoutContainer;
 
@@ -28,11 +30,13 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewConte
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.DispatcherHelper;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.ITabItemFactory;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.ExperimentModel;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.experiment.columns.CommonExperimentColDefKind;
 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.DisposableComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IColumnDefinition;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ListExperimentsCriteria;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ResultSet;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
@@ -91,6 +95,7 @@ public final class ExperimentBrowserGrid extends AbstractBrowserGrid<Experiment,
         criteria.setLimit(resultSetConfig.getLimit());
         criteria.setOffset(resultSetConfig.getOffset());
         criteria.setSortInfo(resultSetConfig.getSortInfo());
+        criteria.setFilterInfos(resultSetConfig.getFilterInfos());
         criteria.setResultSetKey(resultSetConfig.getResultSetKey());
     }
 
@@ -157,4 +162,12 @@ public final class ExperimentBrowserGrid extends AbstractBrowserGrid<Experiment,
     {
         return (criteria == null || entityType.equals(criteria.getExperimentType()) == false);
     }
+
+    @Override
+    protected List<IColumnDefinition<Experiment>> getAvailableFilters()
+    {
+        return asColumnFilters(new CommonExperimentColDefKind[]
+            { CommonExperimentColDefKind.CODE, CommonExperimentColDefKind.GROUP,
+                    CommonExperimentColDefKind.PROJECT });
+    }
 }
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 5240d64dff7f7a5ddba87c4d1bf9f08603c1ce93..2bdd68656df467ad3726c9aa12931fbd6313f104 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
@@ -46,6 +46,8 @@ import com.extjs.gxt.ui.client.widget.layout.FitLayout;
 import com.extjs.gxt.ui.client.widget.layout.RowData;
 import com.extjs.gxt.ui.client.widget.layout.RowLayout;
 import com.extjs.gxt.ui.client.widget.toolbar.AdapterToolItem;
+import com.extjs.gxt.ui.client.widget.toolbar.FillToolItem;
+import com.extjs.gxt.ui.client.widget.toolbar.LabelToolItem;
 import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -56,11 +58,14 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
 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.VoidAsyncCallback;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.AbstractEntityModel;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.BrowserGridPagingToolBar.IBrowserGridActionInvoker;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.GWTUtils;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMessageProvider;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.URLMethodWithParameters;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.WindowUtils;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.GridFilterInfo;
 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.SortInfo;
@@ -104,10 +109,17 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
     /** @return should the refresh button be enabled? */
     abstract protected boolean isRefreshEnabled();
 
+    /** @return on which fields user can set filters? */
+    abstract protected List<IColumnDefinition<T>> getAvailableFilters();
+
     protected final IViewContext<ICommonClientServiceAsync> viewContext;
 
     // ------ private section. NOTE: it should remain unaccessible to subclasses! ---------------
 
+    private static final String LABEL_APPLY_FILTERS_HINT = "Refresh to apply filters";
+
+    private static final String LABEL_FILTERS = "Filters";
+
     private static final int PAGE_SIZE = 50;
 
     private final PagingLoader<PagingLoadConfig> pagingLoader;
@@ -119,18 +131,16 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
     // the toolbar has the refresh and export buttons besides the paging controls
     private final BrowserGridPagingToolBar pagingToolbar;
 
-    // should the data be automatically loaded when the grid is rendered for the first time?
     private final boolean refreshAutomatically;
 
+    private final List<PagingColumnFilter<T>> filterWidgets;
+
     // available columns configs and definitions
     private ColumnDefsAndConfigs<T> columns;
 
     // result set key of the last refreshed data
     private String resultSetKey;
 
-    // information about sorting options of the last refreshed data
-    private SortInfo<T> sortInfo;
-
     private IDataRefreshCallback refreshCallback;
 
     public interface IDataRefreshCallback
@@ -149,6 +159,13 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
         this(viewContext, gridId, true, false);
     }
 
+    /**
+     * @param showHeader decides if the header bar on top of the grid should be displayed. If false,
+     *            then an attempt to set a non-null header (e.g. in refresh method) is treated as an
+     *            error.
+     * @param refreshAutomatically should the data be automatically loaded when the grid is rendered
+     *            for the first time?
+     */
     protected AbstractBrowserGrid(final IViewContext<ICommonClientServiceAsync> viewContext,
             String gridId, boolean showHeader, boolean refreshAutomatically)
     {
@@ -160,14 +177,30 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
         this.pagingToolbar =
                 new BrowserGridPagingToolBar(asActionInvoker(), viewContext, PAGE_SIZE);
         pagingToolbar.bind(pagingLoader);
+        this.filterWidgets = createFilterWidgets(getAvailableFilters());
+
+        final LayoutContainer bottomToolbars = createBottomToolbars(filterWidgets, pagingToolbar);
 
         this.contentPanel = createEmptyContentPanel();
         contentPanel.add(grid);
-        contentPanel.setBottomComponent(pagingToolbar);
+        contentPanel.setBottomComponent(bottomToolbars);
         contentPanel.setHeaderVisible(showHeader);
 
         setLayout(new FitLayout());
         add(contentPanel);
+
+    }
+
+    private static <T> List<PagingColumnFilter<T>> createFilterWidgets(
+            List<IColumnDefinition<T>> availableFilters)
+    {
+        List<PagingColumnFilter<T>> filterWidgets = new ArrayList<PagingColumnFilter<T>>();
+        for (IColumnDefinition<T> columnDefinition : availableFilters)
+        {
+            PagingColumnFilter<T> filterWidget = new PagingColumnFilter<T>(columnDefinition);
+            filterWidgets.add(filterWidget);
+        }
+        return filterWidgets;
     }
 
     /** @return this grid as a disposable component with a specified toolbar at the top. */
@@ -231,8 +264,10 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
                 public final void load(final PagingLoadConfig loadConfig,
                         final AsyncCallback<PagingLoadResult<M>> callback)
                 {
+                    List<GridFilterInfo<T>> appliedFilters = getAppliedFilters();
                     DefaultResultSetConfig<String, T> resultSetConfig =
-                            createPagingConfig(loadConfig, columns.getColumnDefs(), resultSetKey);
+                            createPagingConfig(loadConfig, columns.getColumnDefs(), appliedFilters,
+                                    resultSetKey);
                     ListEntitiesCallback listCallback =
                             new ListEntitiesCallback(viewContext, callback, resultSetConfig);
                     listEntities(resultSetConfig, listCallback);
@@ -240,15 +275,50 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
             };
     }
 
+    // returns filters which user wants to apply to the data
+    private List<GridFilterInfo<T>> getAppliedFilters()
+    {
+        List<GridFilterInfo<T>> filters = new ArrayList<GridFilterInfo<T>>();
+        for (PagingColumnFilter<T> filterWidget : filterWidgets)
+        {
+            GridFilterInfo<T> filter = filterWidget.tryGetFilter();
+            if (filter != null)
+            {
+                filters.add(filter);
+            }
+        }
+        return filters;
+    }
+
+    protected List<IColumnDefinition<T>> asColumnFilters(
+            IColumnDefinitionKind<T>[] filteredColumnKinds)
+    {
+        return asColumnFilters(filteredColumnKinds, viewContext);
+    }
+
+    private static <T> List<IColumnDefinition<T>> asColumnFilters(
+            IColumnDefinitionKind<T>[] filteredColumnKinds, IMessageProvider messageProvider)
+    {
+        List<IColumnDefinition<T>> filters = new ArrayList<IColumnDefinition<T>>();
+        for (IColumnDefinitionKind<T> colDefKind : filteredColumnKinds)
+        {
+            IColumnDefinition<T> codeColDef =
+                    AbstractEntityModel.createColumnDefinition(colDefKind, messageProvider);
+            filters.add(codeColDef);
+        }
+        return filters;
+    }
+
     private static <T> DefaultResultSetConfig<String, T> createPagingConfig(
             PagingLoadConfig loadConfig, List<IColumnDefinition<T>> availableColumns,
-            String resultSetKey)
+            List<GridFilterInfo<T>> appliedFilters, String resultSetKey)
     {
         DefaultResultSetConfig<String, T> resultSetConfig = new DefaultResultSetConfig<String, T>();
         resultSetConfig.setLimit(loadConfig.getLimit());
         resultSetConfig.setOffset(loadConfig.getOffset());
         SortInfo<T> sortInfo = translateSortInfo(loadConfig, availableColumns);
         resultSetConfig.setSortInfo(sortInfo);
+        resultSetConfig.setFilterInfos(appliedFilters);
         resultSetConfig.setResultSetKey(resultSetKey);
         return resultSetConfig;
     }
@@ -256,18 +326,24 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
     private static <T> SortInfo<T> translateSortInfo(PagingLoadConfig loadConfig,
             List<IColumnDefinition<T>> availableColumns)
     {
-        com.extjs.gxt.ui.client.data.SortInfo origSortInfo = loadConfig.getSortInfo();
-        String origSortField = origSortInfo.getSortField();
+        com.extjs.gxt.ui.client.data.SortInfo sortInfo = loadConfig.getSortInfo();
+        return translateSortInfo(sortInfo.getSortField(), sortInfo.getSortDir(), availableColumns);
+    }
+
+    private static <T> SortInfo<T> translateSortInfo(String dortFieldId,
+            com.extjs.gxt.ui.client.Style.SortDir sortDir,
+            List<IColumnDefinition<T>> availableColumns)
+    {
         IColumnDefinition<T> sortColumnDefinition = null;
-        if (origSortField != null)
+        if (dortFieldId != null)
         {
             Map<String, IColumnDefinition<T>> availableColumnsMap = asColumnIdMap(availableColumns);
-            sortColumnDefinition = availableColumnsMap.get(origSortField);
+            sortColumnDefinition = availableColumnsMap.get(dortFieldId);
             assert sortColumnDefinition != null : "sortColumnDefinition is null";
         }
         SortInfo<T> sortInfo = new SortInfo<T>();
         sortInfo.setSortField(sortColumnDefinition);
-        sortInfo.setSortDir(translate(origSortInfo.getSortDir()));
+        sortInfo.setSortDir(translate(sortDir));
         return sortInfo;
     }
 
@@ -328,7 +404,6 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
             // save the key of the result, later we can refer to the result in the cache using this
             // key
             saveCacheKey(result.getResultSetKey());
-            saveSortInfo(resultSetConfig.getSortInfo());
             // convert the result to the model data for the grid control
             final List<M> models = createModels(result.getList());
             final PagingLoadResult<M> loadResult =
@@ -510,11 +585,6 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
         return getSelectedColumns(availableColumnsMap, columnModel);
     }
 
-    private void saveSortInfo(SortInfo<T> newSortInfo)
-    {
-        this.sortInfo = newSortInfo;
-    }
-
     private void saveCacheKey(final String newResultSetKey)
     {
         if (resultSetKey == null)
@@ -549,12 +619,20 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
         assert resultSetKey != null : "refresh before exporting, resultSetKey is null!";
 
         final List<IColumnDefinition<T>> columnDefs = getSelectedColumns(columns.getColumnDefs());
+        SortInfo<T> sortInfo = getGridSortInfo();
         final TableExportCriteria<T> exportCriteria =
-                new TableExportCriteria<T>(resultSetKey, sortInfo, columnDefs);
+                new TableExportCriteria<T>(resultSetKey, sortInfo, getAppliedFilters(), columnDefs);
 
         prepareExportEntities(exportCriteria, callback);
     }
 
+    // returns info about soring in current grid
+    private SortInfo<T> getGridSortInfo()
+    {
+        ListStore<M> store = grid.getStore();
+        return translateSortInfo(store.getSortField(), store.getSortDir(), columns.getColumnDefs());
+    }
+
     // ------- generic static helpers
 
     private final static ContentPanel createEmptyContentPanel()
@@ -566,6 +644,36 @@ public abstract class AbstractBrowserGrid<T/* Entity */, M extends ModelData> ex
         return contentPanel;
     }
 
+    private static <T> LayoutContainer createBottomToolbars(
+            List<PagingColumnFilter<T>> filterWidgets, Component pagingToolbar)
+    {
+        Component filterToolbar = createFilterToolbar(filterWidgets);
+
+        LayoutContainer bottomToolbars = new LayoutContainer();
+        bottomToolbars.setLayout(new RowLayout(com.extjs.gxt.ui.client.Style.Orientation.VERTICAL));
+        bottomToolbars.add(filterToolbar);
+        bottomToolbars.add(pagingToolbar);
+        return bottomToolbars;
+    }
+
+    private static <T> ToolBar createFilterToolbar(List<PagingColumnFilter<T>> filterWidgets)
+    {
+        ToolBar filterToolbar = new ToolBar();
+        if (filterWidgets.size() == 0)
+        {
+            return filterToolbar;
+        }
+        filterToolbar.add(new LabelToolItem(LABEL_FILTERS + ": "));
+
+        for (PagingColumnFilter<T> filterWidget : filterWidgets)
+        {
+            filterToolbar.add(new AdapterToolItem(filterWidget));
+        }
+        filterToolbar.add(new FillToolItem());
+        filterToolbar.add(new LabelToolItem(LABEL_APPLY_FILTERS_HINT));
+        return filterToolbar;
+    }
+
     private static final <T extends ModelData> Grid<T> createGrid(
             PagingLoader<PagingLoadConfig> dataLoader, Listener<GridEvent> detailsViewer,
             String gridId)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractSimpleBrowserGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractSimpleBrowserGrid.java
index 2196159766f1a673b5e948923973556df3bf308f..fe373c321976bcb9fdac7a1c9dc00a1a0b9abbe8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractSimpleBrowserGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/AbstractSimpleBrowserGrid.java
@@ -47,7 +47,7 @@ abstract public class AbstractSimpleBrowserGrid<T/* Entity */, M extends ModelDa
     {
         IColumnDefinitionKind<T>[] colDefKinds = getStaticColumnsDefinition();
         List<IColumnDefinitionUI<T>> colDefs =
-                AbstractEntityModel.createColumnsSchemaFrom(colDefKinds, viewContext);
+                AbstractEntityModel.createColumnsDefinition(colDefKinds, viewContext);
         return ColumnDefsAndConfigs.create(colDefs);
     }
 
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 62a7027e115c1ce7861ee5ef80fddd42cc7fbf86..ea8b2f0cffab5ccea95ebff82fa1e526154dd25b 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
@@ -21,6 +21,7 @@ import com.extjs.gxt.ui.client.event.SelectionListener;
 import com.extjs.gxt.ui.client.widget.PagingToolBar;
 import com.extjs.gxt.ui.client.widget.button.Button;
 import com.extjs.gxt.ui.client.widget.toolbar.AdapterToolItem;
+import com.google.gwt.user.client.ui.Widget;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericConstants;
@@ -70,9 +71,9 @@ public final class BrowserGridPagingToolBar extends PagingToolBarAdapter
         add(exportButton);
     }
 
-    private void add(Button button)
+    private void add(Widget widget)
     {
-        add(new AdapterToolItem(button));
+        add(new AdapterToolItem(widget));
     }
 
     protected final void updateDefaultRefreshButton(boolean isEnabled)
@@ -115,6 +116,7 @@ public final class BrowserGridPagingToolBar extends PagingToolBarAdapter
         return createRefreshButton(messageProvider.getMessage(Dict.BUTTON_REFRESH), invoker);
     }
 
+    /** creates a new refresh button, the caller has to add it to a parent container */
     public static Button createRefreshButton(String title, final IBrowserGridActionInvoker invoker)
     {
         final Button button = new Button(title, new SelectionListener<ButtonEvent>()
@@ -131,6 +133,7 @@ public final class BrowserGridPagingToolBar extends PagingToolBarAdapter
         return button;
     }
 
+    /** creates a new export button, the caller has to add it to a parent container */
     public static Button createExportButton(IMessageProvider messageProvider,
             final IBrowserGridActionInvoker invoker)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/PagingColumnFilter.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/PagingColumnFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..881004b69ea6a14a25252b8817808f6259a5e29e
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/PagingColumnFilter.java
@@ -0,0 +1,63 @@
+/*
+ * 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.generic.client.web.client.application.ui.grid;
+
+import com.extjs.gxt.ui.client.data.ModelData;
+import com.extjs.gxt.ui.client.store.Store;
+import com.extjs.gxt.ui.client.widget.StoreFilterField;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.GridFilterInfo;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IColumnDefinition;
+
+/**
+ * {@link StoreFilterField} extension for filtering columns in cached grid with paging.
+ * 
+ * @author Tomasz Pylak
+ */
+public class PagingColumnFilter<T/* entity */> extends StoreFilterField<ModelData>
+{
+    private final IColumnDefinition<T> filteredField;
+
+    public PagingColumnFilter(IColumnDefinition<T> filteredField)
+    {
+        this.filteredField = filteredField;
+        setWidth(100);
+        String label = filteredField.getHeader() + "...";
+        setEmptyText(label);
+    }
+
+    /** @return filter with the pattern or null if pattern was not specified by the user */
+    public GridFilterInfo<T> tryGetFilter()
+    {
+        String pattern = getRawValue();
+        if (pattern != null && pattern.length() > 0)
+        {
+            return new GridFilterInfo<T>(filteredField, pattern);
+        } else
+        {
+            return null;
+        }
+    }
+
+    /** We do not use this method, data are filtered on the server side */
+    @Override
+    protected boolean doSelect(Store<ModelData> store, ModelData parent, ModelData record,
+            String property, String filterText)
+    {
+        return true;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/project/ProjectGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/project/ProjectGrid.java
index 01b84885b6522f669a236bfc6d33f65d96f765b5..13c153ea5332b57a2c670cd7581378a889fa9917 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/project/ProjectGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/project/ProjectGrid.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.project;
 
+import java.util.List;
+
 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;
@@ -25,6 +27,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.Ab
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.DisposableComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IColumnDefinitionKind;
 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.Project;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ResultSet;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TableExportCriteria;
@@ -77,4 +80,11 @@ public class ProjectGrid extends AbstractSimpleBrowserGrid<Project, ProjectModel
     {
         viewContext.getService().prepareExportProjects(exportCriteria, callback);
     }
+
+    @Override
+    protected List<IColumnDefinition<Project>> getAvailableFilters()
+    {
+        return asColumnFilters(new ProjectColDefKind[]
+            { ProjectColDefKind.CODE, ProjectColDefKind.GROUP });
+    }
 }
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeAssignmentGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeAssignmentGrid.java
index 728d5d6bf285eede9d7d9176a94c24c85be73acc..a2c318649cc5bcb181cb5e87b9d6409a442b006f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeAssignmentGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeAssignmentGrid.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.property_type;
 
+import java.util.List;
+
 import ch.systemsx.cisd.openbis.generic.client.shared.EntityTypePropertyType;
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
@@ -26,6 +28,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.Ab
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.DisposableComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IColumnDefinitionKind;
 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;
 
@@ -60,6 +63,15 @@ public class PropertyTypeAssignmentGrid extends
         return PropertyTypeAssignmentColDefKind.values();
     }
 
+    @Override
+    protected List<IColumnDefinition<EntityTypePropertyType<?>>> getAvailableFilters()
+    {
+        return asColumnFilters(new PropertyTypeAssignmentColDefKind[]
+            { PropertyTypeAssignmentColDefKind.PROPERTY_TYPE_CODE,
+                    PropertyTypeAssignmentColDefKind.ENTITY_TYPE_CODE,
+                    PropertyTypeAssignmentColDefKind.ENTITY_KIND });
+    }
+
     @Override
     protected ETPTModel createModel(EntityTypePropertyType<?> entity)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeGrid.java
index 228b6663ed3556344051963cf4bf49ca30550bb5..25f4b79fa107ab6baed504b79463900609aede34 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeGrid.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.property_type;
 
+import java.util.List;
+
 import ch.systemsx.cisd.openbis.generic.client.shared.PropertyType;
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
@@ -26,6 +28,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.Ab
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.DisposableComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IColumnDefinitionKind;
 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;
 
@@ -58,6 +61,14 @@ public class PropertyTypeGrid extends AbstractSimpleBrowserGrid<PropertyType, Pr
         return PropertyTypeColDefKind.values();
     }
 
+    @Override
+    protected List<IColumnDefinition<PropertyType>> getAvailableFilters()
+    {
+        return asColumnFilters(new PropertyTypeColDefKind[]
+            { PropertyTypeColDefKind.LABEL, PropertyTypeColDefKind.CODE,
+                    PropertyTypeColDefKind.DATA_TYPE });
+    }
+
     @Override
     protected PropertyTypeModel createModel(PropertyType entity)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBrowserGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBrowserGrid.java
index ac3a55a33e75fa6dabc994bd3832547effab8be2..e3f1ce49280d0f16e85e76af05b7cf942f3b2c36 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBrowserGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/SampleBrowserGrid.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.sample;
 
+import java.util.List;
+
 import com.extjs.gxt.ui.client.event.SelectionChangedListener;
 import com.extjs.gxt.ui.client.widget.LayoutContainer;
 
@@ -30,8 +32,10 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.
 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.DisposableComponent;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.sample.columns.CommonSampleColDefKind;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.sample.columns.SampleModel;
 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.ListSampleCriteria;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ResultSet;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.Sample;
@@ -125,6 +129,7 @@ public final class SampleBrowserGrid extends AbstractBrowserGrid<Sample, SampleM
         criteria.setLimit(resultSetConfig.getLimit());
         criteria.setOffset(resultSetConfig.getOffset());
         criteria.setSortInfo(resultSetConfig.getSortInfo());
+        criteria.setFilterInfos(resultSetConfig.getFilterInfos());
         criteria.setResultSetKey(resultSetConfig.getResultSetKey());
     }
 
@@ -134,6 +139,14 @@ public final class SampleBrowserGrid extends AbstractBrowserGrid<Sample, SampleM
         return new SampleModel(entity);
     }
 
+    @Override
+    protected List<IColumnDefinition<Sample>> getAvailableFilters()
+    {
+        return asColumnFilters(new CommonSampleColDefKind[]
+            { CommonSampleColDefKind.CODE, CommonSampleColDefKind.EXPERIMENT,
+                    CommonSampleColDefKind.PROJECT, CommonSampleColDefKind.GROUP });
+    }
+
     @Override
     protected void showEntityViewer(SampleModel sampleModel)
     {
@@ -208,6 +221,7 @@ public final class SampleBrowserGrid extends AbstractBrowserGrid<Sample, SampleM
     @Override
     protected ColumnDefsAndConfigs<Sample> createColumnsDefinition()
     {
+        assert criteria != null : "criteria not set!";
         return SampleModel.createColumnsSchema(viewContext, criteria.getSampleType());
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/CommonSampleColDefKind.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/CommonSampleColDefKind.java
index a98c8dc505ff1f66a6c3c1ec6390193b664de017..9743f7d1e2024d4e0c777c7c7d49025932eba348 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/CommonSampleColDefKind.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/CommonSampleColDefKind.java
@@ -42,7 +42,7 @@ public enum CommonSampleColDefKind implements IColumnDefinitionKind<Sample>
             }
         }),
 
-    GROUP(new AbstractColumnDefinitionKind<Sample>(Dict.GROUP)
+    GROUP(new AbstractColumnDefinitionKind<Sample>(Dict.GROUP, true)
         {
             @Override
             public String tryGetValue(Sample entity)
@@ -107,34 +107,34 @@ public enum CommonSampleColDefKind implements IColumnDefinitionKind<Sample>
             }
         }),
 
-    PROJECT_FOR_SAMPLE(new AbstractColumnDefinitionKind<Sample>(Dict.PROJECT)
+    EXPERIMENT(new AbstractColumnDefinitionKind<Sample>(Dict.EXPERIMENT)
         {
             @Override
             public String tryGetValue(Sample entity)
             {
                 final Experiment exp = tryToGetExperiment(entity);
-                return exp == null ? null : exp.getProject().getCode();
+                return exp == null ? null : exp.getCode();
             }
         }),
 
-    EXPERIMENT_FOR_SAMPLE(new AbstractColumnDefinitionKind<Sample>(Dict.EXPERIMENT)
+    EXPERIMENT_IDENTIFIER(new AbstractColumnDefinitionKind<Sample>(Dict.EXPERIMENT_IDENTIFIER, 200,
+            true)
         {
             @Override
             public String tryGetValue(Sample entity)
             {
                 final Experiment exp = tryToGetExperiment(entity);
-                return exp == null ? null : exp.getCode();
+                return exp == null ? null : exp.getIdentifier();
             }
         }),
 
-    EXPERIMENT_IDENTIFIER_FOR_SAMPLE(new AbstractColumnDefinitionKind<Sample>(
-            Dict.EXPERIMENT_IDENTIFIER, 200, true)
+    PROJECT(new AbstractColumnDefinitionKind<Sample>(Dict.PROJECT)
         {
             @Override
             public String tryGetValue(Sample entity)
             {
                 final Experiment exp = tryToGetExperiment(entity);
-                return exp == null ? null : exp.getIdentifier();
+                return exp == null ? null : exp.getProject().getCode();
             }
         });
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/SampleModel.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/SampleModel.java
index a48b162a467768561201cbb4cc887e45434a1379..b1e1d7d53537481a076eb2b45e55fcceca5cf045 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/SampleModel.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/SampleModel.java
@@ -113,7 +113,7 @@ public final class SampleModel extends AbstractEntityModel<Sample>
     private static List<IColumnDefinitionUI<Sample>> createCommonColumnsSchema(
             IMessageProvider msgProviderOrNull)
     {
-        return createColumnsSchemaFrom(CommonSampleColDefKind.values(), msgProviderOrNull);
+        return createColumnsDefinition(CommonSampleColDefKind.values(), msgProviderOrNull);
     }
 
     private static List<IColumnDefinitionUI<Sample>> createParentColumnsSchema(
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyGrid.java
index d395b5061f598cecc11c4da42c44ba35cd244f9a..21f7e743cef83c0a2182170b64056b3dbc2a0fdb 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/vocabulary/VocabularyGrid.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.vocabulary;
 
+import java.util.List;
+
 import ch.systemsx.cisd.openbis.generic.client.shared.Vocabulary;
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
@@ -26,6 +28,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.Ab
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.DisposableComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IColumnDefinitionKind;
 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;
 
@@ -58,6 +61,13 @@ public class VocabularyGrid extends AbstractSimpleBrowserGrid<Vocabulary, Vocabu
         return VocabularyColDefKind.values();
     }
 
+    @Override
+    protected List<IColumnDefinition<Vocabulary>> getAvailableFilters()
+    {
+        return asColumnFilters(new VocabularyColDefKind[]
+            { VocabularyColDefKind.CODE });
+    }
+
     @Override
     protected VocabularyModel createModel(Vocabulary entity)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/DefaultResultSetConfig.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/DefaultResultSetConfig.java
index 1e9d1a06e41cc3a4b918e2b20ca9ba9629718d13..7a40ad70d8723ba870b0cc5180fa2503cf17ccc4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/DefaultResultSetConfig.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/DefaultResultSetConfig.java
@@ -16,6 +16,9 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.dto;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import com.google.gwt.user.client.rpc.IsSerializable;
 
 /**
@@ -31,6 +34,8 @@ public class DefaultResultSetConfig<K, T> implements IResultSetConfig<K, T>, IsS
 
     private SortInfo<T> sortInfo = new SortInfo<T>();
 
+    private List<GridFilterInfo<T>> filterInfos = new ArrayList<GridFilterInfo<T>>();
+
     /**
      * The result set key.
      * <p>
@@ -64,6 +69,11 @@ public class DefaultResultSetConfig<K, T> implements IResultSetConfig<K, T>, IsS
         this.resultSetKeyOrNull = resultSetKey;
     }
 
+    public List<GridFilterInfo<T>> getFilterInfos()
+    {
+        return filterInfos;
+    }
+
     //
     // IResultSetConfig
     //
@@ -88,4 +98,9 @@ public class DefaultResultSetConfig<K, T> implements IResultSetConfig<K, T>, IsS
     {
         return resultSetKeyOrNull;
     }
+
+    public void setFilterInfos(List<GridFilterInfo<T>> filterInfos)
+    {
+        this.filterInfos = filterInfos;
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/GridFilterInfo.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/GridFilterInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecc49f328fc5f31962cfed1d21b7d12366bcf059
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/GridFilterInfo.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.google.gwt.user.client.rpc.IsSerializable;
+
+/**
+ * The specification of the value filter: the column schema and the filter pattern.
+ * 
+ * @author Tomasz Pylak
+ */
+public class GridFilterInfo<T> implements IsSerializable
+{
+    // allows to fetch the value from the row model
+    private IColumnDefinition<T> filteredField;
+
+    // the value has to match to this pattern
+    private String filterText;
+
+    // GWT only
+    @SuppressWarnings("unused")
+    private GridFilterInfo()
+    {
+    }
+
+    public GridFilterInfo(IColumnDefinition<T> filteredField, String filterText)
+    {
+        this.filteredField = filteredField;
+        this.filterText = filterText;
+    }
+
+    public IColumnDefinition<T> getFilteredField()
+    {
+        return filteredField;
+    }
+
+    public String getFilterPattern()
+    {
+        return filterText;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/IResultSetConfig.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/IResultSetConfig.java
index 5f5d708100323f20286e9227bf741cc037ccd27a..b71830f443100bbe63c340b69dd845ce67b18a65 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/IResultSetConfig.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/IResultSetConfig.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.dto;
 
+import java.util.List;
+
 import ch.systemsx.cisd.openbis.generic.client.web.server.resultset.IResultSet;
 
 /**
@@ -46,4 +48,7 @@ public interface IResultSetConfig<K, T> extends IResultSetKeyHolder<K>
      * Returns the sort info.
      */
     public SortInfo<T> getSortInfo();
+
+    /** The filters which should be applied for the result */
+    public List<GridFilterInfo<T>> getFilterInfos();
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/TableExportCriteria.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/TableExportCriteria.java
index b2bbc4f45efd4a2eec709f9679468143139b8fd4..910e3f11047125d15039d91c43aa6a74b44e6fc5 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/TableExportCriteria.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/dto/TableExportCriteria.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.dto;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import com.google.gwt.user.client.rpc.IsSerializable;
@@ -34,6 +35,9 @@ public class TableExportCriteria<T/* exported entity */> implements IResultSetKe
 
     private SortInfo<T> sortInfo = new SortInfo<T>();
 
+    /** @see IResultSetConfig#getFilterInfos() */
+    private List<GridFilterInfo<T>> filterInfos = new ArrayList<GridFilterInfo<T>>();
+
     // which columns should be exported
     private List<IColumnDefinition<T>> columnDefs;
 
@@ -43,10 +47,11 @@ public class TableExportCriteria<T/* exported entity */> implements IResultSetKe
     }
 
     public TableExportCriteria(String resultSetKey, SortInfo<T> sortInfo,
-            List<IColumnDefinition<T>> columnDefs)
+            List<GridFilterInfo<T>> filterInfos, List<IColumnDefinition<T>> columnDefs)
     {
         this.resultSetKey = resultSetKey;
         this.sortInfo = sortInfo;
+        this.filterInfos = filterInfos;
         this.columnDefs = columnDefs;
     }
 
@@ -60,6 +65,11 @@ public class TableExportCriteria<T/* exported entity */> implements IResultSetKe
         return sortInfo;
     }
 
+    public List<GridFilterInfo<T>> getFilterInfos()
+    {
+        return filterInfos;
+    }
+
     public List<IColumnDefinition<T>> getColumnDefs()
     {
         return columnDefs;
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 fee4a63cb714b72020353aa5e7d5c366ff50808e..1b4724a3bd2a6cc0cd8cba97918350057cd1772b 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
@@ -145,24 +145,31 @@ public final class CommonClientService extends AbstractClientService implements
     private final <T> List<T> fetchCachedEntities(final TableExportCriteria<T> exportCriteria)
     {
         final IResultSetManager<String> resultSetManager = getResultSetManager();
+        IResultSetConfig<String, T> resultSetConfig = createExportListCriteria(exportCriteria);
+        IOriginalDataProvider<T> dummyDataProvider = createDummyDataProvider();
         final IResultSet<String, T> result =
-                resultSetManager.getResultSet(createExportListCriteria(exportCriteria),
-                        new IOriginalDataProvider<T>()
-                            {
-                                public List<T> getOriginalData() throws UserFailureException
-                                {
-                                    throw new IllegalStateException("Data not found in the cache");
-                                }
-                            });
+                resultSetManager.getResultSet(resultSetConfig, dummyDataProvider);
         final ResultSet<T> entities = ResultSetTranslator.translate(result);
         return entities.getList();
     }
 
+    private static <T> IOriginalDataProvider<T> createDummyDataProvider()
+    {
+        return new IOriginalDataProvider<T>()
+            {
+                public List<T> getOriginalData() throws UserFailureException
+                {
+                    throw new IllegalStateException("Data not found in the cache");
+                }
+            };
+    }
+
     private static <T> IResultSetConfig<String, T> createExportListCriteria(
             final TableExportCriteria<T> exportCriteria)
     {
         final DefaultResultSetConfig<String, T> criteria = DefaultResultSetConfig.createFetchAll();
         criteria.setSortInfo(exportCriteria.getSortInfo());
+        criteria.setFilterInfos(exportCriteria.getFilterInfos());
         criteria.setResultSetKey(exportCriteria.getResultSetKey());
         return criteria;
     }
@@ -189,6 +196,7 @@ public final class CommonClientService extends AbstractClientService implements
      */
     public final String getExportTable(final String exportDataKey)
     {
+        // NOTE: no generics in GWT
         return getGenericExportTable(exportDataKey);
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/CachedResultSetManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/CachedResultSetManager.java
index f8ed9d399be860643864d7a58da98e581bf158de..b7260adcac6c8d34c83099d1ad0a2eb8a0d32c18 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/CachedResultSetManager.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/CachedResultSetManager.java
@@ -30,6 +30,7 @@ import org.apache.log4j.Logger;
 import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.GridFilterInfo;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IColumnDefinition;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.IResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SortInfo;
@@ -64,6 +65,46 @@ public final class CachedResultSetManager<K> implements IResultSetManager<K>, Se
         return (List<T>) list;
     }
 
+    private static final <T> List<T> filterData(final List<T> rows,
+            final List<GridFilterInfo<T>> filterInfos)
+    {
+        List<T> filtered = new ArrayList<T>();
+        for (T row : rows)
+        {
+            if (isMatching(row, filterInfos))
+            {
+                filtered.add(row);
+            }
+        }
+        return filtered;
+    }
+
+    // returns true if a row matches all the filters
+    private static final <T> boolean isMatching(final T row,
+            final List<GridFilterInfo<T>> filterInfos)
+    {
+        for (GridFilterInfo<T> filter : filterInfos)
+        {
+            if (isMatching(row, filter) == false)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static final <T> boolean isMatching(final T row, final GridFilterInfo<T> filterInfo)
+    {
+        IColumnDefinition<T> filteredField = filterInfo.getFilteredField();
+        String value = filteredField.getValue(row);
+        return isMatching(value, filterInfo.getFilterPattern());
+    }
+
+    private static boolean isMatching(String value, String filterPattern)
+    {
+        return value.toLowerCase().startsWith(filterPattern.toLowerCase());
+    }
+
     private final <T> void sortData(final List<T> data, final SortInfo<T> sortInfo)
     {
         assert data != null : "Unspecified data.";
@@ -151,7 +192,7 @@ public final class CachedResultSetManager<K> implements IResultSetManager<K>, Se
     {
         assert resultConfig != null : "Unspecified result configuration";
         assert dataProvider != null : "Unspecified data retriever";
-        final List<T> data;
+        List<T> data;
         K dataKey = resultConfig.getResultSetKey();
         if (dataKey == null)
         {
@@ -166,13 +207,15 @@ public final class CachedResultSetManager<K> implements IResultSetManager<K>, Se
             data = cast(results.get(dataKey));
         }
         assert data != null : "Unspecified data";
+        final int totalLength = data.size();
+        data = filterData(data, resultConfig.getFilterInfos());
         final int size = data.size();
         final int offset = getOffset(size, resultConfig.getOffset());
         final int limit = getLimit(size, resultConfig.getLimit(), offset);
         final SortInfo<T> sortInfo = resultConfig.getSortInfo();
         sortData(data, sortInfo);
         final List<T> list = subList(data, offset, limit);
-        return new DefaultResultSet<K, T>(dataKey, list, size);
+        return new DefaultResultSet<K, T>(dataKey, list, totalLength);
     }
 
     public final synchronized void removeResultSet(final K resultSetKey)
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/SampleRow.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/SampleRow.java
index 64bebcc643afa95646e6690d52d0bd912a1787a7..a4c34ef8f4c340befe68606b733f32f1738a41a5 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/SampleRow.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample/columns/SampleRow.java
@@ -60,18 +60,18 @@ public class SampleRow extends Row
 
     public SampleRow experiment(final String projectCode, final String experimentCode)
     {
-        withCell(CommonSampleColDefKind.PROJECT_FOR_SAMPLE, projectCode);
-        withCell(CommonSampleColDefKind.EXPERIMENT_FOR_SAMPLE, experimentCode);
+        withCell(CommonSampleColDefKind.PROJECT, projectCode);
+        withCell(CommonSampleColDefKind.EXPERIMENT, experimentCode);
         final String experimentIdentifier = groupIdentifier + projectCode + "/" + experimentCode;
-        withCell(CommonSampleColDefKind.EXPERIMENT_IDENTIFIER_FOR_SAMPLE, experimentIdentifier);
+        withCell(CommonSampleColDefKind.EXPERIMENT_IDENTIFIER, experimentIdentifier);
         return this;
     }
 
     public SampleRow noExperiment()
     {
-        withCell(CommonSampleColDefKind.PROJECT_FOR_SAMPLE, null);
-        withCell(CommonSampleColDefKind.EXPERIMENT_FOR_SAMPLE, null);
-        withCell(CommonSampleColDefKind.EXPERIMENT_IDENTIFIER_FOR_SAMPLE, null);
+        withCell(CommonSampleColDefKind.PROJECT, null);
+        withCell(CommonSampleColDefKind.EXPERIMENT, null);
+        withCell(CommonSampleColDefKind.EXPERIMENT_IDENTIFIER, null);
         return this;
     }