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 7def895059d1c7d8df8d0f18572dcb8d1e84d15b..3c72faff56988c68194d9a3f56d4c259029b6f51 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
@@ -56,8 +56,9 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Grantee;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomColumn;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Group;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IFilterOrColumnUpdates;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IGroupUpdates;
@@ -545,7 +546,10 @@ public interface ICommonClientService extends IClientService
     /** Deletes the specified data set. */
     public void deleteDataSet(String singleData, String reason) throws UserFailureException;
 
-    /** Deletes the specified samples. NOTE: this is a stale version used only for samples with abundance. */
+    /**
+     * Deletes the specified samples. NOTE: this is a stale version used only for samples with
+     * abundance.
+     */
     public void deleteSamples(List<TechId> sampleIds, String reason) throws UserFailureException;
 
     /** Deletes the specified samples. */
@@ -743,34 +747,70 @@ public interface ICommonClientService extends IClientService
     public void removePersonsFromAuthorizationGroup(TechId authorizationGroupId,
             List<String> personsCodes) throws UserFailureException;
 
+    // -- custom grid filters
+
     /**
-     * Lists filters available for given grid.
+     * Lists custom grid filters available for given grid.
      */
     public List<GridCustomFilter> listFilters(String gridId) throws UserFailureException;
 
     /**
-     * Returns {@link GridCustomFilter}s for given criteria.
+     * Returns {@link GridCustomFilter}s for given grid and display criteria.
      */
     public ResultSet<GridCustomFilter> listFilters(String gridId,
-            DefaultResultSetConfig<String, GridCustomFilter> resultSetConfig) throws UserFailureException;
+            DefaultResultSetConfig<String, GridCustomFilter> resultSetConfig)
+            throws UserFailureException;
 
     /**
-     * Returns a key which can be used be the export servlet (and eventually
-     * {@link #getExportTable(String, String)}) to reference the export criteria in an easy way.
+     * Like {@link #prepareExportSamples(TableExportCriteria)}, but for custom grid filters.
      */
     public String prepareExportFilters(final TableExportCriteria<GridCustomFilter> criteria)
             throws UserFailureException;
 
     /**
-     * Registers a new filter.
+     * Registers a new grid custom filter.
      */
     public void registerFilter(NewColumnOrFilter filter) throws UserFailureException;
 
-    /** Deletes the specified filters. */
+    /** Deletes the specified grid custom filters. */
     public void deleteFilters(List<TechId> filterIds) throws UserFailureException;
 
     /**
-     * Updates filter.
+     * Updates grid custom filter.
      */
     public void updateFilter(final IFilterOrColumnUpdates updates) throws UserFailureException;
+
+    // -- custom grid columns
+
+    /**
+     * Lists custom grid columns available for given grid.
+     */
+    public List<GridCustomColumn> listColumns(String gridId) throws UserFailureException;
+
+    /**
+     * Returns {@link GridCustomColumn}s for given grid and display criteria.
+     */
+    public ResultSet<GridCustomColumn> listColumns(String gridId,
+            DefaultResultSetConfig<String, GridCustomColumn> resultSetConfig)
+            throws UserFailureException;
+
+    /**
+     * Like {@link #prepareExportSamples(TableExportCriteria)}, but for custom grid filters.
+     */
+    public String prepareExportColumns(final TableExportCriteria<GridCustomColumn> criteria)
+            throws UserFailureException;
+
+    /**
+     * Registers a new grid custom column.
+     */
+    public void registerColumn(NewColumnOrFilter newColumn) throws UserFailureException;
+
+    /** Deletes the specified grid custom columns. */
+    public void deleteColumns(List<TechId> columnIds) throws UserFailureException;
+
+    /**
+     * Updates grid custom column.
+     */
+    public void updateColumn(IFilterOrColumnUpdates updates) throws UserFailureException;
+
 }
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 b7a64c9e3e982a87544746ceb3bd0f09b58f264d..4430bfc3b651d08151416b533f148d1f116034ff 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
@@ -58,8 +58,9 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Grantee;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomColumn;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Group;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IFilterOrColumnUpdates;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IGroupUpdates;
@@ -663,6 +664,8 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
     public void removePersonsFromAuthorizationGroup(TechId create, List<String> extractCodes,
             AsyncCallback<Void> callback);
 
+    // -- custom grid filters
+
     /**
      * @see ICommonClientService#listFilters(String)
      */
@@ -671,7 +674,8 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
     /**
      * @see ICommonClientService#listFilters(String, DefaultResultSetConfig)
      */
-    public void listFilters(String gridId, DefaultResultSetConfig<String, GridCustomFilter> resultSetConfig,
+    public void listFilters(String gridId,
+            DefaultResultSetConfig<String, GridCustomFilter> resultSetConfig,
             AsyncCallback<ResultSet<GridCustomFilter>> callback);
 
     /**
@@ -687,5 +691,38 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
     public void deleteFilters(List<TechId> filterIds, AsyncCallback<Void> asyncCallback);
 
     /** @see ICommonClientService#updateFilter(IFilterOrColumnUpdates) */
-    public void updateFilter(IFilterOrColumnUpdates updates, AsyncCallback<Void> registrationCallback);
+    public void updateFilter(IFilterOrColumnUpdates updates,
+            AsyncCallback<Void> registrationCallback);
+
+    // -- custom grid columns
+
+    /**
+     * @see ICommonClientService#listColumns(String)
+     */
+    public void listColumns(String gridId, AsyncCallback<List<GridCustomColumn>> callback);
+
+    /**
+     * @see ICommonClientService#listColumns(String, DefaultResultSetConfig)
+     */
+    public void listColumns(String gridId,
+            DefaultResultSetConfig<String, GridCustomColumn> resultSetConfig,
+            AsyncCallback<ResultSet<GridCustomColumn>> callback);
+
+    /**
+     * @see ICommonClientService#prepareExportColumns(TableExportCriteria)
+     */
+    public void prepareExportColumns(final TableExportCriteria<GridCustomColumn> criteria,
+            AsyncCallback<String> asyncCallback);
+
+    /** @see ICommonClientService#registerColumn(NewColumnOrFilter) */
+    public void registerColumn(NewColumnOrFilter newColumn, AsyncCallback<Void> registrationCallback);
+
+    /** @see ICommonClientService#deleteColumns(List) */
+    public void deleteColumns(List<TechId> columnIds, AsyncCallback<Void> asyncCallback);
+
+    /** @see ICommonClientService#updateColumn(IFilterOrColumnUpdates) */
+    public void updateColumn(IFilterOrColumnUpdates updates,
+            AsyncCallback<Void> registrationCallback);
+
+    // --
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
index e8e7797ca7ac77444b4e4a07b7c3e5c288c7e896..5c38735d293caf658451eee2ba39684642fd6838 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
@@ -797,9 +797,13 @@ public abstract class Dict
 
     public static final String EXPRESSION = "expression";
 
+    public static final String COLUMN = "column";
+
     public static final String COLUMNS = "columns";
 
-    public static final String CUSTOM_FILTERS = "custom_filters";
+    public static final String GRID_CUSTOM_FILTERS = "grid_custom_filters";
+
+    public static final String GRID_CUSTOM_COLUMNS = "grid_custom_columns";
 
     public static final String APPLY_FILTER = "apply_filter";
 
@@ -807,6 +811,8 @@ public abstract class Dict
 
     public static final String ADD_NEW_FILTER = "add_new_filter";
 
+    public static final String ADD_NEW_COLUMN = "add_new_column";
+
     public static final String HOW_TO_ADDRESS = "how_to_address";
 
     public static final String INSERT_COLUMNS = "insert_columns";
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 36829570aceba397bfc550e823b0777714118960..f56b87e369be5070a744c0a9960395e4823e9f66 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
@@ -19,7 +19,7 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.application.framework
 /**
  * Enum for all generic {@link IDisplayTypeIDGenerator}s.
  * 
- * @author     Franz-Josef Elmer
+ * @author Franz-Josef Elmer
  */
 public enum DisplayTypeIDGenerator implements IDisplayTypeIDGenerator
 {
@@ -49,6 +49,8 @@ public enum DisplayTypeIDGenerator implements IDisplayTypeIDGenerator
 
     FILTER_BROWSER_GRID("filter-browser-grid"),
 
+    CUSTOM_GRID_COLUMN_GRID("custom-grid-column-browser-grid"),
+
     AUTHORIZATION_GROUP_BROWSER_GRID("authorization-group-browser-grid"),
 
     PERSON_BROWSER_GRID("person-browser-grid"),
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/CustomGridColumnColDefKind.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/CustomGridColumnColDefKind.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c370ff11b084376b4083346c8561e2494f00f90
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/CustomGridColumnColDefKind.java
@@ -0,0 +1,115 @@
+/*
+ * 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;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
+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.IColumnDefinitionKind;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.framework.renderers.SimpleYesNoRenderer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomColumn;
+
+/**
+ * Column definitions for the grid custom columns.<br>
+ * It's very similar to the column definition enum for filters, but the code cannot be common
+ * because enums can inherit only from interfaces.
+ * 
+ * @author Tomasz Pylak
+ */
+public enum CustomGridColumnColDefKind implements IColumnDefinitionKind<GridCustomColumn>
+{
+    CODE(new AbstractColumnDefinitionKind<GridCustomColumn>(Dict.CODE)
+        {
+            @Override
+            public String tryGetValue(GridCustomColumn entity)
+            {
+                return entity.getCode();
+            }
+        }),
+
+    NAME(new AbstractColumnDefinitionKind<GridCustomColumn>(Dict.NAME)
+        {
+            @Override
+            public String tryGetValue(GridCustomColumn entity)
+            {
+                return entity.getName();
+            }
+        }),
+
+    DESCRIPTION(new AbstractColumnDefinitionKind<GridCustomColumn>(Dict.DESCRIPTION)
+        {
+            @Override
+            public String tryGetValue(GridCustomColumn entity)
+            {
+                return entity.getDescription();
+            }
+        }),
+
+    EXPRESSION(new AbstractColumnDefinitionKind<GridCustomColumn>(Dict.EXPRESSION, true)
+        {
+            @Override
+            public String tryGetValue(GridCustomColumn entity)
+            {
+                return entity.getExpression();
+            }
+        }),
+
+    PUBLIC(new AbstractColumnDefinitionKind<GridCustomColumn>(Dict.IS_PUBLIC, true)
+        {
+            @Override
+            public String tryGetValue(GridCustomColumn entity)
+            {
+                return SimpleYesNoRenderer.render(entity.isPublic());
+            }
+        }),
+
+    REGISTRATOR(new AbstractColumnDefinitionKind<GridCustomColumn>(Dict.REGISTRATOR, true)
+        {
+            @Override
+            public String tryGetValue(GridCustomColumn entity)
+            {
+                return renderRegistrator(entity);
+            }
+        }),
+
+    REGISTRATION_DATE(new AbstractColumnDefinitionKind<GridCustomColumn>(Dict.REGISTRATION_DATE,
+            AbstractColumnDefinitionKind.DATE_COLUMN_WIDTH, true)
+        {
+            @Override
+            public String tryGetValue(GridCustomColumn entity)
+            {
+                return renderRegistrationDate(entity);
+            }
+        });
+
+    private final AbstractColumnDefinitionKind<GridCustomColumn> columnDefinitionKind;
+
+    private CustomGridColumnColDefKind(
+            AbstractColumnDefinitionKind<GridCustomColumn> columnDefinitionKind)
+    {
+        this.columnDefinitionKind = columnDefinitionKind;
+    }
+
+    public String id()
+    {
+        return name();
+    }
+
+    public AbstractColumnDefinitionKind<GridCustomColumn> getDescriptor()
+    {
+        return columnDefinitionKind;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/FilterColDefKind.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/CustomGridFilterColDefKind.java
similarity index 94%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/FilterColDefKind.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/CustomGridFilterColDefKind.java
index 5e3de872978d0cdf28f46f1dea6031307e3d2b56..ffd2ad952649e348081a0258cc342e450381192f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/FilterColDefKind.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/columns/specific/CustomGridFilterColDefKind.java
@@ -27,7 +27,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
  * 
  * @author Izabela Adamczyk
  */
-public enum FilterColDefKind implements IColumnDefinitionKind<GridCustomFilter>
+public enum CustomGridFilterColDefKind implements IColumnDefinitionKind<GridCustomFilter>
 {
     NAME(new AbstractColumnDefinitionKind<GridCustomFilter>(Dict.NAME)
         {
@@ -86,7 +86,8 @@ public enum FilterColDefKind implements IColumnDefinitionKind<GridCustomFilter>
 
     private final AbstractColumnDefinitionKind<GridCustomFilter> columnDefinitionKind;
 
-    private FilterColDefKind(AbstractColumnDefinitionKind<GridCustomFilter> columnDefinitionKind)
+    private CustomGridFilterColDefKind(
+            AbstractColumnDefinitionKind<GridCustomFilter> columnDefinitionKind)
     {
         this.columnDefinitionKind = columnDefinitionKind;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AddFilterDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AddFilterDialog.java
deleted file mode 100644
index 6d43588560b1bbc0b5bc597f66c4c7fa2a072ece..0000000000000000000000000000000000000000
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AddFilterDialog.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.filter;
-
-import java.util.List;
-
-import com.extjs.gxt.ui.client.widget.Window;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
-import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ColumnDataModel;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedAction;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewColumnOrFilter;
-
-/**
- * {@link Window} containing filter registration form.
- * 
- * @author Izabela Adamczyk
- * @author Piotr Buczek
- */
-public class AddFilterDialog extends AbstractGridCustomExpressionEditRegisterDialog
-{
-    private final IViewContext<ICommonClientServiceAsync> viewContext;
-
-    public AddFilterDialog(final IViewContext<ICommonClientServiceAsync> viewContext,
-            final IDelegatedAction postRegistrationCallback, String gridId,
-            List<ColumnDataModel> columnModels)
-    {
-        super(viewContext, viewContext.getMessage(Dict.ADD_NEW_FILTER), postRegistrationCallback,
-                gridId, columnModels);
-        this.viewContext = viewContext;
-    }
-
-    @Override
-    protected void register(AsyncCallback<Void> registrationCallback)
-    {
-        NewColumnOrFilter filter = new NewColumnOrFilter();
-        filter.setGridId(gridId);
-        filter.setDescription(extractDescription());
-        filter.setExpression(extractExpression());
-        filter.setName(extractName());
-        filter.setPublic(extractIsPublic());
-        viewContext.getService().registerFilter(filter, registrationCallback);
-    }
-
-}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/EditFilterDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/EditFilterDialog.java
deleted file mode 100644
index 5506f46e621b221ec411d5b5ae045d57a2e70b54..0000000000000000000000000000000000000000
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/EditFilterDialog.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.filter;
-
-import java.util.List;
-
-import com.extjs.gxt.ui.client.widget.Window;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
-import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ColumnDataModel;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedAction;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
-
-/**
- * {@link Window} containing filter edition form.
- * 
- * @author Piotr Buczek
- */
-public class EditFilterDialog extends AbstractGridCustomExpressionEditRegisterDialog
-{
-    private final IViewContext<ICommonClientServiceAsync> viewContext;
-
-    private final GridCustomFilter filter;
-
-    public EditFilterDialog(final IViewContext<ICommonClientServiceAsync> viewContext,
-            final IDelegatedAction postRegistrationCallback, String gridId,
-            List<ColumnDataModel> columnModels, GridCustomFilter filter)
-    {
-        super(viewContext, viewContext.getMessage(Dict.EDIT_TITLE, viewContext
-                .getMessage(Dict.FILTER), filter.getName()), postRegistrationCallback, gridId,
-                columnModels);
-        this.viewContext = viewContext;
-        this.filter = filter;
-        initializeValues();
-    }
-
-    private void initializeValues()
-    {
-        initializeDescription(filter.getDescription());
-        initializeExpression(filter.getExpression());
-        initializeName(filter.getName());
-        initializePublic(filter.isPublic());
-    }
-
-    @Override
-    protected void register(AsyncCallback<Void> registrationCallback)
-    {
-        filter.setDescription(extractDescription());
-        filter.setExpression(extractExpression());
-        filter.setName(extractName());
-        filter.setPublic(extractIsPublic());
-        viewContext.getService().updateFilter(filter, registrationCallback);
-    }
-
-}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/GridCustomColumnGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/GridCustomColumnGrid.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7d5aa25544ed353623639bfd6c0d00cb2f809e2
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/GridCustomColumnGrid.java
@@ -0,0 +1,289 @@
+/*
+ * 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.filter;
+
+import java.util.List;
+
+import com.extjs.gxt.ui.client.event.ComponentEvent;
+import com.extjs.gxt.ui.client.event.SelectionListener;
+import com.extjs.gxt.ui.client.widget.Dialog;
+import com.extjs.gxt.ui.client.widget.Window;
+import com.extjs.gxt.ui.client.widget.button.Button;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+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.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.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.IColumnDefinitionKind;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.specific.CustomGridColumnColDefKind;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.common.AbstractGridCustomExpressionEditOrRegisterDialog;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.AbstractSimpleBrowserGrid;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ColumnDataModel;
+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.IBrowserGridActionInvoker;
+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.dto.DefaultResultSetConfig;
+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.shared.basic.IColumnDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractGridExpression;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomColumn;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewColumnOrFilter;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind.ObjectKind;
+
+/**
+ * Allows to display, update, delete and create new custom grid columns.
+ * 
+ * @author Tomasz Pylak
+ */
+public class GridCustomColumnGrid extends AbstractSimpleBrowserGrid<GridCustomColumn>
+{
+    private static final String BROWSER_ID =
+            GenericConstants.ID_PREFIX + "custom-grid-column-browser";
+
+    public static IDisposableComponent create(IViewContext<ICommonClientServiceAsync> viewContext,
+            String gridDisplayId, List<ColumnDataModel> columnModels)
+    {
+        return new GridCustomColumnGrid(viewContext, gridDisplayId, columnModels)
+                .asDisposableWithoutToolbar();
+    }
+
+    static final String createAddButtonId(String gridDisplayId)
+    {
+        return createGridId(gridDisplayId) + "_ADD_BUTTON";
+    }
+
+    static final String createGridId(String gridDisplayId)
+    {
+        return createBrowserId(gridDisplayId) + "_grid";
+    }
+
+    private static final String createBrowserId(String gridDisplayId)
+    {
+        return BROWSER_ID + (gridDisplayId != null ? ("_" + gridDisplayId) : "");
+    }
+
+    protected final String gridDisplayId;
+
+    private final List<ColumnDataModel> columnModels;
+
+    private void extendBottomToolbar()
+    {
+        addEntityOperationsLabel();
+        final Button addButton =
+                new Button(viewContext.getMessage(Dict.BUTTON_ADD, viewContext
+                        .getMessage(Dict.COLUMN)), new SelectionListener<ComponentEvent>()
+                    {
+                        @Override
+                        public void componentSelected(ComponentEvent ce)
+                        {
+                            createAddDialog().show();
+                        }
+
+                    });
+        addButton.setId(createAddButtonId(gridDisplayId));
+        addButton(addButton);
+        final Button editButton =
+                createSelectedItemButton(viewContext.getMessage(Dict.BUTTON_EDIT),
+                        new ISelectedEntityInvoker<BaseEntityModel<GridCustomColumn>>()
+                            {
+                                public void invoke(BaseEntityModel<GridCustomColumn> selectedItem)
+                                {
+                                    final GridCustomColumn selected = selectedItem.getBaseObject();
+                                    createEditDialog(selected).show();
+                                }
+
+                            });
+        addButton(editButton);
+        Button deleteButton =
+                createSelectedItemsButton(viewContext.getMessage(Dict.BUTTON_DELETE),
+                        new AbstractCreateDialogListener()
+                            {
+                                @Override
+                                protected Dialog createDialog(List<GridCustomColumn> selected,
+                                        IBrowserGridActionInvoker invoker)
+                                {
+                                    return new DeletionConfirmationDialog(viewContext, selected,
+                                            createDeletionCallback(invoker));
+                                }
+                            });
+        addButton(deleteButton);
+        allowMultipleSelection();
+        addEntityOperationsSeparator();
+    }
+
+    private Window createAddDialog()
+    {
+        return new AddDialog(viewContext, createRefreshGridAction(), gridDisplayId, columnModels);
+    }
+
+    private Window createEditDialog(AbstractGridExpression updatedItem)
+    {
+        return new EditDialog(viewContext, createRefreshGridAction(), gridDisplayId, columnModels,
+                updatedItem);
+    }
+
+    private static class AddDialog extends AbstractGridCustomExpressionEditOrRegisterDialog
+    {
+        private final IViewContext<ICommonClientServiceAsync> viewContext;
+
+        public AddDialog(final IViewContext<ICommonClientServiceAsync> viewContext,
+                final IDelegatedAction postRegistrationCallback, String gridId,
+                List<ColumnDataModel> columnModels)
+        {
+            super(viewContext, viewContext.getMessage(Dict.ADD_NEW_COLUMN),
+                    postRegistrationCallback, gridId, columnModels);
+            this.viewContext = viewContext;
+        }
+
+        @Override
+        protected void register(AsyncCallback<Void> registrationCallback)
+        {
+            NewColumnOrFilter newItem = getNewItemInfo();
+            viewContext.getService().registerColumn(newItem, registrationCallback);
+        }
+    }
+
+    private static class EditDialog extends AbstractGridCustomExpressionEditOrRegisterDialog
+    {
+        private final IViewContext<ICommonClientServiceAsync> viewContext;
+
+        private final AbstractGridExpression itemToUpdate;
+
+        public EditDialog(final IViewContext<ICommonClientServiceAsync> viewContext,
+                final IDelegatedAction postRegistrationCallback, String gridId,
+                List<ColumnDataModel> columnModels, AbstractGridExpression itemToUpdate)
+        {
+            super(viewContext, viewContext.getMessage(Dict.EDIT_TITLE, viewContext
+                    .getMessage(Dict.COLUMN), itemToUpdate.getName()), postRegistrationCallback,
+                    gridId, columnModels);
+            this.viewContext = viewContext;
+            this.itemToUpdate = itemToUpdate;
+            initializeValues(itemToUpdate);
+        }
+
+        @Override
+        protected void register(AsyncCallback<Void> registrationCallback)
+        {
+            update(itemToUpdate);
+            viewContext.getService().updateColumn(itemToUpdate, registrationCallback);
+        }
+    }
+
+    private static class DeletionConfirmationDialog extends
+            AbstractDataConfirmationDialog<List<GridCustomColumn>>
+    {
+        private static final int LABEL_WIDTH = 60;
+
+        private static final int FIELD_WIDTH = 180;
+
+        private final IViewContext<ICommonClientServiceAsync> viewContext;
+
+        private final AbstractAsyncCallback<Void> callback;
+
+        public DeletionConfirmationDialog(IViewContext<ICommonClientServiceAsync> viewContext,
+                List<GridCustomColumn> data, AbstractAsyncCallback<Void> callback)
+        {
+            super(viewContext, data, viewContext.getMessage(Dict.DELETE_CONFIRMATION_TITLE));
+            this.callback = callback;
+            this.viewContext = viewContext;
+        }
+
+        @Override
+        protected void extendForm()
+        {
+            formPanel.setLabelWidth(LABEL_WIDTH);
+            formPanel.setFieldWidth(FIELD_WIDTH);
+        }
+
+        @Override
+        protected String createMessage()
+        {
+            return "Do you really want to delete selected (" + data.size() + ") column(s)?";
+        }
+
+        @Override
+        protected void executeConfirmedAction()
+        {
+            viewContext.getCommonService().deleteColumns(TechId.createList(data), callback);
+        }
+
+    }
+
+    private GridCustomColumnGrid(IViewContext<ICommonClientServiceAsync> viewContext,
+            String gridDisplayId, List<ColumnDataModel> columnModels)
+    {
+        super(viewContext, createBrowserId(gridDisplayId), createGridId(gridDisplayId),
+                DisplayTypeIDGenerator.CUSTOM_GRID_COLUMN_GRID);
+        this.gridDisplayId = gridDisplayId;
+        this.columnModels = columnModels;
+        extendBottomToolbar();
+    }
+
+    @Override
+    protected IColumnDefinitionKind<GridCustomColumn>[] getStaticColumnsDefinition()
+    {
+        return CustomGridColumnColDefKind.values();
+    }
+
+    @Override
+    protected void listEntities(DefaultResultSetConfig<String, GridCustomColumn> resultSetConfig,
+            AbstractAsyncCallback<ResultSet<GridCustomColumn>> callback)
+    {
+        viewContext.getService().listColumns(gridDisplayId, resultSetConfig, callback);
+    }
+
+    @Override
+    protected void prepareExportEntities(TableExportCriteria<GridCustomColumn> exportCriteria,
+            AbstractAsyncCallback<String> callback)
+    {
+        viewContext.getService().prepareExportColumns(exportCriteria, callback);
+    }
+
+    @Override
+    protected List<IColumnDefinition<GridCustomColumn>> getInitialFilters()
+    {
+        return asColumnFilters(new CustomGridColumnColDefKind[]
+            { CustomGridColumnColDefKind.NAME, CustomGridColumnColDefKind.PUBLIC });
+    }
+
+    @Override
+    protected ColumnDefsAndConfigs<GridCustomColumn> createColumnsDefinition()
+    {
+        ColumnDefsAndConfigs<GridCustomColumn> schema = super.createColumnsDefinition();
+        schema.setGridCellRendererFor(CustomGridColumnColDefKind.DESCRIPTION.id(),
+                createMultilineStringCellRenderer());
+        schema.setGridCellRendererFor(CustomGridColumnColDefKind.EXPRESSION.id(),
+                createMultilineStringCellRenderer());
+        return schema;
+    }
+
+    public DatabaseModificationKind[] getRelevantModifications()
+    {
+        return new DatabaseModificationKind[]
+            { DatabaseModificationKind.createOrDelete(ObjectKind.GRID_CUSTOM_COLUMN),
+                    DatabaseModificationKind.edit(ObjectKind.GRID_CUSTOM_COLUMN) };
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/GridCustomFilterGrid.java
similarity index 54%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterGrid.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/GridCustomFilterGrid.java
index 76831928a63d3c8ff2f5405f9334f3d01ed4f862..a65c9156c4e7060e4ef8d98e73bb141bbf59fcfd 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/GridCustomFilterGrid.java
@@ -23,6 +23,7 @@ import com.extjs.gxt.ui.client.event.SelectionListener;
 import com.extjs.gxt.ui.client.widget.Dialog;
 import com.extjs.gxt.ui.client.widget.Window;
 import com.extjs.gxt.ui.client.widget.button.Button;
+import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
@@ -32,87 +33,76 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewConte
 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.IColumnDefinitionKind;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.specific.FilterColDefKind;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.specific.CustomGridFilterColDefKind;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.common.AbstractGridCustomExpressionEditOrRegisterDialog;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.AbstractSimpleBrowserGrid;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ColumnDataModel;
 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.IBrowserGridActionInvoker;
 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.IMessageProvider;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedAction;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
 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.shared.basic.IColumnDefinition;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractGridExpression;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewColumnOrFilter;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind.ObjectKind;
 
 /**
- * Grid displaying filters.
+ * Allows to display, update, delete and create new custom grid filters.
  * 
- * @author Izabela Adamczyk
+ * @author Tomasz Pylak
  */
-public class FilterGrid extends AbstractSimpleBrowserGrid<GridCustomFilter>
+public class GridCustomFilterGrid extends AbstractSimpleBrowserGrid<GridCustomFilter>
 {
-    // browser consists of the grid and the paging toolbar
-    public static final String BROWSER_ID = GenericConstants.ID_PREFIX + "filter-browser";
+    private static final String BROWSER_ID = GenericConstants.ID_PREFIX + "filter-browser";
 
-    private static final String GRID_SUFFIX = "_grid";
-
-    private final String gridId;
-
-    private final List<ColumnDataModel> columnModels;
-
-    public static IDisposableComponent create(
-            final IViewContext<ICommonClientServiceAsync> viewContext, final String gridId,
-            List<ColumnDataModel> columnModels)
+    public static IDisposableComponent create(IViewContext<ICommonClientServiceAsync> viewContext,
+            String gridDisplayId, List<ColumnDataModel> columnModels)
     {
-        final FilterGrid grid = new FilterGrid(viewContext, gridId, columnModels);
-        grid.extendBottomToolbar();
-        return grid.asDisposableWithoutToolbar();
+        return new GridCustomFilterGrid(viewContext, gridDisplayId, columnModels)
+                .asDisposableWithoutToolbar();
     }
 
-    private FilterGrid(IViewContext<ICommonClientServiceAsync> viewContext, String gridId,
-            List<ColumnDataModel> columnModels)
+    static final String createAddButtonId(String gridDisplayId)
     {
-        super(viewContext, createBrowserId(gridId), createGridId(gridId),
-                DisplayTypeIDGenerator.FILTER_BROWSER_GRID);
-        this.gridId = gridId;
-        this.columnModels = columnModels;
+        return createGridId(gridDisplayId) + "_ADD_BUTTON";
     }
 
-    public static final String createAddButtonId(String gridId)
+    static final String createGridId(String gridDisplayId)
     {
-        return createGridId(gridId) + "_ADD_BUTTON";
+        return createBrowserId(gridDisplayId) + "_grid";
     }
 
-    public static final String createGridId(String gridId)
+    private static final String createBrowserId(String gridDisplayId)
     {
-        return createBrowserId(gridId) + GRID_SUFFIX;
+        return BROWSER_ID + (gridDisplayId != null ? ("_" + gridDisplayId) : "");
     }
 
-    private static final String createBrowserId(String gridId)
-    {
-        return BROWSER_ID + (gridId != null ? ("_" + gridId) : "");
-    }
+    protected final String gridDisplayId;
+
+    private final List<ColumnDataModel> columnModels;
 
     private void extendBottomToolbar()
     {
         addEntityOperationsLabel();
         final Button addButton =
-                new Button(viewContext.getMessage(Dict.BUTTON_ADD, "Filter"),
-                        new SelectionListener<ComponentEvent>()
-                            {
-                                @Override
-                                public void componentSelected(ComponentEvent ce)
-                                {
-                                    createAddDialog().show();
-                                }
-
-                            });
-        addButton.setId(createAddButtonId(gridId));
+                new Button(viewContext.getMessage(Dict.BUTTON_ADD, viewContext
+                        .getMessage(Dict.FILTER)), new SelectionListener<ComponentEvent>()
+                    {
+                        @Override
+                        public void componentSelected(ComponentEvent ce)
+                        {
+                            createAddDialog().show();
+                        }
+
+                    });
+        addButton.setId(createAddButtonId(gridDisplayId));
         addButton(addButton);
         final Button editButton =
                 createSelectedItemButton(viewContext.getMessage(Dict.BUTTON_EDIT),
@@ -120,8 +110,8 @@ public class FilterGrid extends AbstractSimpleBrowserGrid<GridCustomFilter>
                             {
                                 public void invoke(BaseEntityModel<GridCustomFilter> selectedItem)
                                 {
-                                    final GridCustomFilter filter = selectedItem.getBaseObject();
-                                    createEditDialog(filter).show();
+                                    final GridCustomFilter selected = selectedItem.getBaseObject();
+                                    createEditDialog(selected).show();
                                 }
 
                             });
@@ -131,11 +121,11 @@ public class FilterGrid extends AbstractSimpleBrowserGrid<GridCustomFilter>
                         new AbstractCreateDialogListener()
                             {
                                 @Override
-                                protected Dialog createDialog(List<GridCustomFilter> filters,
+                                protected Dialog createDialog(List<GridCustomFilter> selected,
                                         IBrowserGridActionInvoker invoker)
                                 {
-                                    return new FilterListDeletionConfirmationDialog(viewContext,
-                                            filters, createDeletionCallback(invoker));
+                                    return new DeletionConfirmationDialog(viewContext, selected,
+                                            createDeletionCallback(invoker));
                                 }
                             });
         addButton(deleteButton);
@@ -145,75 +135,79 @@ public class FilterGrid extends AbstractSimpleBrowserGrid<GridCustomFilter>
 
     private Window createAddDialog()
     {
-        return new AddFilterDialog(viewContext, createRefreshGridAction(), gridId, columnModels);
+        return new AddDialog(viewContext, createRefreshGridAction(), gridDisplayId, columnModels);
     }
 
-    private Window createEditDialog(GridCustomFilter filter)
+    private Window createEditDialog(AbstractGridExpression updatedItem)
     {
-        return new EditFilterDialog(viewContext, createRefreshGridAction(), gridId, columnModels,
-                filter);
+        return new EditDialog(viewContext, createRefreshGridAction(), gridDisplayId, columnModels,
+                updatedItem);
     }
 
-    @Override
-    protected IColumnDefinitionKind<GridCustomFilter>[] getStaticColumnsDefinition()
+    private static class AddDialog extends AbstractGridCustomExpressionEditOrRegisterDialog
     {
-        return FilterColDefKind.values();
-    }
+        private final IViewContext<ICommonClientServiceAsync> viewContext;
 
-    @Override
-    protected ColumnDefsAndConfigs<GridCustomFilter> createColumnsDefinition()
-    {
-        ColumnDefsAndConfigs<GridCustomFilter> schema = super.createColumnsDefinition();
-        schema.setGridCellRendererFor(FilterColDefKind.DESCRIPTION.id(),
-                createMultilineStringCellRenderer());
-        schema.setGridCellRendererFor(FilterColDefKind.EXPRESSION.id(),
-                createMultilineStringCellRenderer());
-        return schema;
-    }
+        public AddDialog(final IViewContext<ICommonClientServiceAsync> viewContext,
+                final IDelegatedAction postRegistrationCallback, String gridId,
+                List<ColumnDataModel> columnModels)
+        {
+            super(viewContext, viewContext.getMessage(Dict.ADD_NEW_FILTER),
+                    postRegistrationCallback, gridId, columnModels);
+            this.viewContext = viewContext;
+        }
 
-    @Override
-    protected void listEntities(DefaultResultSetConfig<String, GridCustomFilter> resultSetConfig,
-            AbstractAsyncCallback<ResultSet<GridCustomFilter>> callback)
-    {
-        viewContext.getService().listFilters(gridId, resultSetConfig, callback);
+        @Override
+        protected void register(AsyncCallback<Void> registrationCallback)
+        {
+            NewColumnOrFilter newItem = getNewItemInfo();
+            viewContext.getService().registerFilter(newItem, registrationCallback);
+        }
     }
 
-    @Override
-    protected void prepareExportEntities(TableExportCriteria<GridCustomFilter> exportCriteria,
-            AbstractAsyncCallback<String> callback)
+    private static class EditDialog extends AbstractGridCustomExpressionEditOrRegisterDialog
     {
-        viewContext.getService().prepareExportFilters(exportCriteria, callback);
-    }
+        private final IViewContext<ICommonClientServiceAsync> viewContext;
 
-    @Override
-    protected List<IColumnDefinition<GridCustomFilter>> getInitialFilters()
-    {
-        return asColumnFilters(new FilterColDefKind[]
-            { FilterColDefKind.NAME, FilterColDefKind.PUBLIC });
-    }
+        private final AbstractGridExpression itemToUpdate;
 
-    public DatabaseModificationKind[] getRelevantModifications()
-    {
-        return new DatabaseModificationKind[]
-            { DatabaseModificationKind.createOrDelete(ObjectKind.GRID_CUSTOM_FILTER),
-                    DatabaseModificationKind.edit(ObjectKind.GRID_CUSTOM_FILTER) };
+        public EditDialog(final IViewContext<ICommonClientServiceAsync> viewContext,
+                final IDelegatedAction postRegistrationCallback, String gridId,
+                List<ColumnDataModel> columnModels, AbstractGridExpression itemToUpdate)
+        {
+            super(viewContext, viewContext.getMessage(Dict.EDIT_TITLE, viewContext
+                    .getMessage(Dict.FILTER), itemToUpdate.getName()), postRegistrationCallback,
+                    gridId, columnModels);
+            this.viewContext = viewContext;
+            this.itemToUpdate = itemToUpdate;
+            initializeValues(itemToUpdate);
+        }
+
+        @Override
+        protected void register(AsyncCallback<Void> registrationCallback)
+        {
+            update(itemToUpdate);
+            viewContext.getService().updateFilter(itemToUpdate, registrationCallback);
+        }
     }
 
-    // it would be better to implement AbstractDataListDeletionConfirmationDialog with 'reason'
-    public class FilterListDeletionConfirmationDialog extends
+    private static class DeletionConfirmationDialog extends
             AbstractDataConfirmationDialog<List<GridCustomFilter>>
     {
         private static final int LABEL_WIDTH = 60;
 
         private static final int FIELD_WIDTH = 180;
 
+        private final IViewContext<ICommonClientServiceAsync> viewContext;
+
         private final AbstractAsyncCallback<Void> callback;
 
-        public FilterListDeletionConfirmationDialog(IMessageProvider messageProvider,
+        public DeletionConfirmationDialog(IViewContext<ICommonClientServiceAsync> viewContext,
                 List<GridCustomFilter> data, AbstractAsyncCallback<Void> callback)
         {
-            super(messageProvider, data, messageProvider.getMessage(Dict.DELETE_CONFIRMATION_TITLE));
+            super(viewContext, data, viewContext.getMessage(Dict.DELETE_CONFIRMATION_TITLE));
             this.callback = callback;
+            this.viewContext = viewContext;
         }
 
         @Override
@@ -237,4 +231,58 @@ public class FilterGrid extends AbstractSimpleBrowserGrid<GridCustomFilter>
 
     }
 
+    private GridCustomFilterGrid(IViewContext<ICommonClientServiceAsync> viewContext,
+            String gridDisplayId, List<ColumnDataModel> columnModels)
+    {
+        super(viewContext, createBrowserId(gridDisplayId), createGridId(gridDisplayId),
+                DisplayTypeIDGenerator.FILTER_BROWSER_GRID);
+        this.gridDisplayId = gridDisplayId;
+        this.columnModels = columnModels;
+        extendBottomToolbar();
+    }
+
+    @Override
+    protected IColumnDefinitionKind<GridCustomFilter>[] getStaticColumnsDefinition()
+    {
+        return CustomGridFilterColDefKind.values();
+    }
+
+    @Override
+    protected void listEntities(DefaultResultSetConfig<String, GridCustomFilter> resultSetConfig,
+            AbstractAsyncCallback<ResultSet<GridCustomFilter>> callback)
+    {
+        viewContext.getService().listFilters(gridDisplayId, resultSetConfig, callback);
+    }
+
+    @Override
+    protected void prepareExportEntities(TableExportCriteria<GridCustomFilter> exportCriteria,
+            AbstractAsyncCallback<String> callback)
+    {
+        viewContext.getService().prepareExportFilters(exportCriteria, callback);
+    }
+
+    @Override
+    protected List<IColumnDefinition<GridCustomFilter>> getInitialFilters()
+    {
+        return asColumnFilters(new CustomGridFilterColDefKind[]
+            { CustomGridFilterColDefKind.NAME, CustomGridFilterColDefKind.PUBLIC });
+    }
+
+    @Override
+    protected ColumnDefsAndConfigs<GridCustomFilter> createColumnsDefinition()
+    {
+        ColumnDefsAndConfigs<GridCustomFilter> schema = super.createColumnsDefinition();
+        schema.setGridCellRendererFor(CustomGridFilterColDefKind.DESCRIPTION.id(),
+                createMultilineStringCellRenderer());
+        schema.setGridCellRendererFor(CustomGridFilterColDefKind.EXPRESSION.id(),
+                createMultilineStringCellRenderer());
+        return schema;
+    }
+
+    public DatabaseModificationKind[] getRelevantModifications()
+    {
+        return new DatabaseModificationKind[]
+            { DatabaseModificationKind.createOrDelete(ObjectKind.GRID_CUSTOM_FILTER),
+                    DatabaseModificationKind.edit(ObjectKind.GRID_CUSTOM_FILTER) };
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AbstractGridCustomExpressionEditRegisterDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/AbstractGridCustomExpressionEditOrRegisterDialog.java
similarity index 77%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AbstractGridCustomExpressionEditRegisterDialog.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/AbstractGridCustomExpressionEditOrRegisterDialog.java
index 23c38960dc714add04d04ac1fee433bfced8c1eb..b9ba367f829b3ec87e6a6fca52865a2f51e5571e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AbstractGridCustomExpressionEditRegisterDialog.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/AbstractGridCustomExpressionEditOrRegisterDialog.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter;
+package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.common;
+
+import static ch.systemsx.cisd.openbis.generic.client.web.client.application.util.lang.StringEscapeUtils.unescapeHtml;
 
 import java.util.List;
 
@@ -36,7 +38,8 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.field.M
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ColumnDataModel;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.AbstractRegistrationDialog;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedAction;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.lang.StringEscapeUtils;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractGridExpression;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewColumnOrFilter;
 
 /**
  * A {@link Window} extension for registering and editing grid custom filters or columns.
@@ -44,7 +47,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.lang.
  * @author Izabela Adamczyk
  * @author Piotr Buczek
  */
-abstract public class AbstractGridCustomExpressionEditRegisterDialog extends
+abstract public class AbstractGridCustomExpressionEditOrRegisterDialog extends
         AbstractRegistrationDialog
 {
 
@@ -76,7 +79,7 @@ abstract public class AbstractGridCustomExpressionEditRegisterDialog extends
 
     protected final String gridId;
 
-    public AbstractGridCustomExpressionEditRegisterDialog(
+    public AbstractGridCustomExpressionEditOrRegisterDialog(
             final IViewContext<ICommonClientServiceAsync> viewContext, final String title,
             final IDelegatedAction postRegistrationCallback, final String gridId,
             final List<ColumnDataModel> columnModels)
@@ -101,6 +104,14 @@ abstract public class AbstractGridCustomExpressionEditRegisterDialog extends
         setWidth(form.getLabelWidth() + form.getFieldWidth() + 50);
     }
 
+    protected void initializeValues(AbstractGridExpression gridExpression)
+    {
+        descriptionField.setValue(unescapeHtml(gridExpression.getDescription()));
+        expressionField.setValue(unescapeHtml(gridExpression.getExpression()));
+        nameField.setValue(unescapeHtml(gridExpression.getName()));
+        publicField.setValue(gridExpression.isPublic());
+    }
+
     private LabelField createInsertColumnsLink(final String label,
             final List<ColumnDataModel> columnModels)
     {
@@ -110,7 +121,7 @@ abstract public class AbstractGridCustomExpressionEditRegisterDialog extends
             {
                 public void handleEvent(BaseEvent be)
                 {
-                    FilterColumnChooserDialog.show(viewContext, columnModels, gridId,
+                    GridColumnChooserDialog.show(viewContext, columnModels, gridId,
                             asExpressionHolder(expressionField));
                 }
             });
@@ -119,7 +130,7 @@ abstract public class AbstractGridCustomExpressionEditRegisterDialog extends
 
     public static String createId(String gridId, String suffix)
     {
-        return GenericConstants.ID_PREFIX + "filter-edit-register-" + gridId + suffix;
+        return GenericConstants.ID_PREFIX + "grid-expression-edit-register-" + gridId + suffix;
     }
 
     private MultilineVarcharField createExpressionField()
@@ -130,44 +141,24 @@ abstract public class AbstractGridCustomExpressionEditRegisterDialog extends
         return field;
     }
 
-    protected final void initializeDescription(String description)
-    {
-        descriptionField.setValue(StringEscapeUtils.unescapeHtml(description));
-    }
-
-    protected final void initializeExpression(String expression)
-    {
-        expressionField.setValue(StringEscapeUtils.unescapeHtml(expression));
-    }
-
-    protected final void initializeName(String name)
-    {
-        nameField.setValue(StringEscapeUtils.unescapeHtml(name));
-    }
-
-    protected final void initializePublic(boolean isPublic)
-    {
-        publicField.setValue(isPublic);
-    }
-
-    protected final String extractDescription()
-    {
-        return descriptionField.getValue();
-    }
-
-    protected final String extractExpression()
-    {
-        return expressionField.getValue();
-    }
-
-    protected final String extractName()
+    // constructs an item from the information provided by the user
+    protected NewColumnOrFilter getNewItemInfo()
     {
-        return nameField.getValue();
+        NewColumnOrFilter newItem = new NewColumnOrFilter();
+        newItem.setGridId(gridId);
+        newItem.setDescription(descriptionField.getValue());
+        newItem.setExpression(expressionField.getValue());
+        newItem.setName(nameField.getValue());
+        newItem.setPublic(publicField.getValue());
+        return newItem;
     }
 
-    protected final boolean extractIsPublic()
+    protected void update(final AbstractGridExpression gridExpression)
     {
-        return publicField.getValue();
+        gridExpression.setDescription(descriptionField.getValue());
+        gridExpression.setExpression(expressionField.getValue());
+        gridExpression.setName(nameField.getValue());
+        gridExpression.setPublic(publicField.getValue());
     }
 
     private static final IExpressionHolder asExpressionHolder(
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterColumnChooser.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/GridColumnChooser.java
similarity index 88%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterColumnChooser.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/GridColumnChooser.java
index 0f2751a5e6e9aaef26823a227523dfba6c72a616..4284b5de020cc6d36c18a6f95bdd57cfde4a5495 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterColumnChooser.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/GridColumnChooser.java
@@ -1,4 +1,4 @@
-package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter;
+package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.common;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -17,17 +17,18 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.Co
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMessageProvider;
 
 /**
- * Allows to select columns which should be used in the filter. Chosen value is a string that can be
- * used in an expression to address selected columns.
+ * Allows to select grid columns which should be used in the grid custom filter or column
+ * expression. Chosen value is a string that can be used in an expression to address selected grid
+ * columns.
  * 
  * @author Izabela Adamczyk
  */
-class FilterColumnChooser
+class GridColumnChooser
 {
 
     private final Grid<ColumnDataModel> grid;
 
-    public FilterColumnChooser(List<ColumnDataModel> list, IMessageProvider messageProvider)
+    public GridColumnChooser(List<ColumnDataModel> list, IMessageProvider messageProvider)
     {
         List<ColumnConfig> configs = new ArrayList<ColumnConfig>();
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterColumnChooserDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/GridColumnChooserDialog.java
similarity index 83%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterColumnChooserDialog.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/GridColumnChooserDialog.java
index 8e3c9ca0440d61f3f213e2557a8f5a73581a67a9..5df62ebeacc56b3702bbc021cbae3b4809397697 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/FilterColumnChooserDialog.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/GridColumnChooserDialog.java
@@ -1,4 +1,4 @@
-package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter;
+package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.common;
 
 import java.util.List;
 
@@ -18,21 +18,22 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewConte
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ColumnDataModel;
 
 /**
- * {@link Dialog} displaying {@link FilterColumnChooser}.
+ * {@link Dialog} displaying {@link GridColumnChooser}. Used to insert selected columns into an
+ * expression to build the custom grid filter or column.
  * 
  * @author Izabela Adamczyk
  */
-class FilterColumnChooserDialog extends Dialog
+class GridColumnChooserDialog extends Dialog
 {
     private final IViewContext<ICommonClientServiceAsync> viewContext;
 
     public static void show(IViewContext<ICommonClientServiceAsync> viewContext,
             List<ColumnDataModel> columnModels, String gridId, IExpressionHolder expressionField)
     {
-        new FilterColumnChooserDialog(viewContext, gridId).show(columnModels, expressionField);
+        new GridColumnChooserDialog(viewContext, gridId).show(columnModels, expressionField);
     }
 
-    private FilterColumnChooserDialog(IViewContext<ICommonClientServiceAsync> viewContext,
+    private GridColumnChooserDialog(IViewContext<ICommonClientServiceAsync> viewContext,
             String gridId)
     {
         this.viewContext = viewContext;
@@ -44,15 +45,14 @@ class FilterColumnChooserDialog extends Dialog
     }
 
     /**
-     * Shows window containing {@link FilterColumnChooser} based on given {@link ColumnModel}.
+     * Shows window containing {@link GridColumnChooser} based on given {@link ColumnModel}.
      */
     private void show(final List<ColumnDataModel> columnModels,
             final IExpressionHolder expressionField)
     {
         assert columnModels != null : "columnModels not specified";
         removeAll();
-        final FilterColumnChooser columnChooser =
-                new FilterColumnChooser(columnModels, viewContext);
+        final GridColumnChooser columnChooser = new GridColumnChooser(columnModels, viewContext);
         final Component columnChooserComponent = columnChooser.getComponent();
         add(columnChooserComponent);
 
@@ -79,7 +79,7 @@ class FilterColumnChooserDialog extends Dialog
     }
 
     private void insertColumnsIntoExpression(IExpressionHolder expressionField,
-            FilterColumnChooser columnChooser)
+            GridColumnChooser columnChooser)
     {
         String expression = expressionField.getValue() != null ? expressionField.getValue() : "";
         int cursor = expressionField.getCursorPos();
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/IExpressionHolder.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/IExpressionHolder.java
similarity index 94%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/IExpressionHolder.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/IExpressionHolder.java
index 88bc7da0f787e17c4e4fa365bbc1e59e358a6892..64b03aae701d249e5f1ab0762e4aa66317c9496b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/IExpressionHolder.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/common/IExpressionHolder.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter;
+package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.common;
 
 /**
  * Allows to access the expression value and the cursor position.
  * 
  * @author Izabela Adamczyk
  */
-public interface IExpressionHolder
+interface IExpressionHolder
 {
     public String getValue();
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/ColumnSettingsDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/ColumnSettingsDialog.java
index 3ffa358371e96047d76dbc3c7796465934c58496..f88681e6bf8ac2136a47aafee0bed7b0b98b5b4a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/ColumnSettingsDialog.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/grid/ColumnSettingsDialog.java
@@ -4,6 +4,7 @@ import java.util.List;
 
 import com.extjs.gxt.ui.client.event.ComponentEvent;
 import com.extjs.gxt.ui.client.event.SelectionListener;
+import com.extjs.gxt.ui.client.widget.Component;
 import com.extjs.gxt.ui.client.widget.Dialog;
 import com.extjs.gxt.ui.client.widget.TabItem;
 import com.extjs.gxt.ui.client.widget.TabPanel;
@@ -15,7 +16,8 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAs
 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.ui.filter.FilterGrid;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.GridCustomColumnGrid;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.GridCustomFilterGrid;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IResultUpdater;
 
 /**
@@ -29,6 +31,8 @@ public class ColumnSettingsDialog extends Dialog
 
     public static final String FILTERS_TAB = GenericConstants.ID_PREFIX + "filters-tab";
 
+    public static final String COLUMNS_TAB = GenericConstants.ID_PREFIX + "columns-tab";
+
     private final IViewContext<ICommonClientServiceAsync> viewContext;
 
     private final String gridDisplayId;
@@ -58,21 +62,26 @@ public class ColumnSettingsDialog extends Dialog
     {
         assert columnModels != null : "columnModels not specified";
         removeAll();
-        final ColumnSettingsChooser columnChooser =
-                new ColumnSettingsChooser(columnModels, viewContext);
-        final IDisposableComponent filters =
-                FilterGrid.create(viewContext, gridDisplayId, columnModels);
         TabPanel panel = new TabPanel();
         panel.setId(TAB_PANEL_ID_PREFIX + gridDisplayId);
-        TabItem columnsTab = new TabItem(viewContext.getMessage(Dict.COLUMNS));
-        columnsTab.setLayout(new FitLayout());
-        columnsTab.add(columnChooser.getComponent());
+
+        final ColumnSettingsChooser columnChooser =
+                new ColumnSettingsChooser(columnModels, viewContext);
+        TabItem columnsTab = createTabItem(columnChooser.getComponent(), Dict.COLUMNS, "");
         panel.add(columnsTab);
-        TabItem filtersTab = new TabItem(viewContext.getMessage(Dict.CUSTOM_FILTERS));
-        filtersTab.setId(FILTERS_TAB + gridDisplayId);
-        filtersTab.setLayout(new FitLayout());
-        filtersTab.add(filters.getComponent());
-        panel.add(filtersTab);
+
+        final IDisposableComponent filters =
+                GridCustomFilterGrid.create(viewContext, gridDisplayId, columnModels);
+        TabItem customFiltersTab =
+                createTabItem(filters.getComponent(), Dict.GRID_CUSTOM_FILTERS, FILTERS_TAB);
+        panel.add(customFiltersTab);
+
+        final IDisposableComponent columns =
+                GridCustomColumnGrid.create(viewContext, gridDisplayId, columnModels);
+        TabItem customColumnsTab =
+                createTabItem(columns.getComponent(), Dict.GRID_CUSTOM_COLUMNS, COLUMNS_TAB);
+        panel.add(customColumnsTab);
+
         add(panel);
         super.show();
         Button okButton = getButtonBar().getButtonById("ok");
@@ -84,9 +93,18 @@ public class ColumnSettingsDialog extends Dialog
                 {
                     resultUpdater.update(columnChooser.getModels());
                     filters.dispose();
+                    columns.dispose();
                     hide();
                 }
             });
     }
 
+    private TabItem createTabItem(final Component component, String titleDictKey, String tabIdPrefix)
+    {
+        TabItem customColumnsTab = new TabItem(viewContext.getMessage(titleDictKey));
+        customColumnsTab.setId(tabIdPrefix + gridDisplayId);
+        customColumnsTab.setLayout(new FitLayout());
+        customColumnsTab.add(component);
+        return customColumnsTab;
+    }
 }
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 074aaa2310c6b900e1983061ae5fa7987bc2c692..ae7d005f18f5070ae9aa0caf4596ee2b6da310d0 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
@@ -96,8 +96,9 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentTypePropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Grantee;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomColumn;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.GridCustomFilter;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Group;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IFilterOrColumnUpdates;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IGroupUpdates;
@@ -2131,15 +2132,14 @@ public final class CommonClientService extends AbstractClientService implements
         }
     }
 
+    // -- custom grid filters
+
     public List<GridCustomFilter> listFilters(String gridId)
             throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
     {
-
         try
         {
-            final String sessionToken = getSessionToken();
-            final List<GridCustomFilter> types = commonServer.listFilters(sessionToken, gridId);
-            return types;
+            return commonServer.listFilters(getSessionToken(), gridId);
         } catch (final UserFailureException e)
         {
             throw UserFailureExceptionTranslator.translate(e);
@@ -2171,8 +2171,7 @@ public final class CommonClientService extends AbstractClientService implements
         assert filter != null : "Unspecified filter.";
         try
         {
-            final String sessionToken = getSessionToken();
-            commonServer.registerFilter(sessionToken, filter);
+            commonServer.registerFilter(getSessionToken(), filter);
         } catch (final UserFailureException e)
         {
             throw UserFailureExceptionTranslator.translate(e);
@@ -2184,8 +2183,7 @@ public final class CommonClientService extends AbstractClientService implements
     {
         try
         {
-            final String sessionToken = getSessionToken();
-            commonServer.deleteFilters(sessionToken, filterIds);
+            commonServer.deleteFilters(getSessionToken(), filterIds);
         } catch (final UserFailureException e)
         {
             throw UserFailureExceptionTranslator.translate(e);
@@ -2196,11 +2194,82 @@ public final class CommonClientService extends AbstractClientService implements
             throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
     {
         assert updates != null : "Unspecified updates.";
+        try
+        {
+            commonServer.updateFilter(getSessionToken(), updates);
+        } catch (final UserFailureException e)
+        {
+            throw UserFailureExceptionTranslator.translate(e);
+        }
+    }
+
+    // -- grid custom columns
 
+    public List<GridCustomColumn> listColumns(String gridId)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
         try
         {
-            final String sessionToken = getSessionToken();
-            commonServer.updateFilter(sessionToken, updates);
+            return commonServer.listGridCustomColumns(getSessionToken(), gridId);
+        } catch (final UserFailureException e)
+        {
+            throw UserFailureExceptionTranslator.translate(e);
+        }
+    }
+
+    public ResultSet<GridCustomColumn> listColumns(final String gridId,
+            DefaultResultSetConfig<String, GridCustomColumn> resultSetConfig)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        return listEntities(resultSetConfig, new IOriginalDataProvider<GridCustomColumn>()
+            {
+                public List<GridCustomColumn> getOriginalData() throws UserFailureException
+                {
+                    return listColumns(gridId);
+                }
+            });
+    }
+
+    public String prepareExportColumns(TableExportCriteria<GridCustomColumn> criteria)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        return prepareExportEntities(criteria);
+    }
+
+    public void registerColumn(NewColumnOrFilter newColumn)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        assert newColumn != null : "Unspecified grid custom column.";
+        try
+        {
+            commonServer.registerGridCustomColumn(getSessionToken(), newColumn);
+        } catch (final UserFailureException e)
+        {
+            throw UserFailureExceptionTranslator.translate(e);
+        }
+
+    }
+
+    public void deleteColumns(List<TechId> columnIds)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        try
+        {
+            commonServer.deleteGridCustomColumns(getSessionToken(), columnIds);
+        } catch (final UserFailureException e)
+        {
+            throw UserFailureExceptionTranslator.translate(e);
+        }
+
+    }
+
+    public void updateColumn(IFilterOrColumnUpdates updates)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        assert updates != null : "Unspecified grid custom updates.";
+        try
+        {
+            commonServer.updateGridCustomColumn(getSessionToken(), updates);
         } catch (final UserFailureException e)
         {
             throw UserFailureExceptionTranslator.translate(e);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DatabaseVersionHolder.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DatabaseVersionHolder.java
index 3b2a9e74f19fdccf292a9c45bece72118447f7ef..6140be9862d66c85f6b8d63d8b13d4f81b734162 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DatabaseVersionHolder.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DatabaseVersionHolder.java
@@ -24,7 +24,7 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.db;
 public final class DatabaseVersionHolder
 {
     /** Current version of the database. */
-    private static final String DATABASE_VERSION = "042";
+    private static final String DATABASE_VERSION = "043";
 
     private DatabaseVersionHolder()
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AbstractGridExpression.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AbstractGridExpression.java
index dcc243931ef1819fa98318dfeda89070cd7aaa39..2430e399cd120ff82ecfb6c0e6a4fec360835590 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AbstractGridExpression.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AbstractGridExpression.java
@@ -31,6 +31,8 @@ public abstract class AbstractGridExpression extends AbstractRegistrationHolder
 {
     private static final long serialVersionUID = ServiceVersionHolder.VERSION;
 
+    private String name; // name for filters, label for columns
+
     private String expression;
 
     private boolean isPublic;
@@ -47,6 +49,16 @@ public abstract class AbstractGridExpression extends AbstractRegistrationHolder
     {
     }
 
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
     public String getExpression()
     {
         return expression;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/GridCustomColumn.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/GridCustomColumn.java
index 8fa78f6f997625faa35410fcedb6d89ac0cd2400..c3cc927c3110646f09a92e021a182519893cfd20 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/GridCustomColumn.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/GridCustomColumn.java
@@ -28,8 +28,6 @@ public class GridCustomColumn extends AbstractGridExpression
 
     private String code;
 
-    private String label;
-
     public String getCode()
     {
         return code;
@@ -39,20 +37,4 @@ public class GridCustomColumn extends AbstractGridExpression
     {
         this.code = code;
     }
-
-    public String getLabel()
-    {
-        return label;
-    }
-
-    public void setLabel(String label)
-    {
-        this.label = label;
-    }
-
-    public String getName()
-    {
-        return label;
-    }
-
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/GridCustomFilter.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/GridCustomFilter.java
index d7365f6f940449be9febd352b039a959b481e8f1..9ccb7f8bfae86eeaa524015d9d1877c95f7df93e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/GridCustomFilter.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/GridCustomFilter.java
@@ -30,24 +30,12 @@ public class GridCustomFilter extends AbstractGridExpression
     /** Name of the standard filter kind which is available for all grids */
     public static final String COLUMN_FILTER = "Column Filter";
 
-    private String name;
-
     private Set<String> parameters;
 
     public GridCustomFilter()
     {
     }
 
-    public String getName()
-    {
-        return name;
-    }
-
-    public void setName(String name)
-    {
-        this.name = name;
-    }
-
     public Set<String> getParameters()
     {
         return parameters;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/IFilterOrColumnUpdates.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/IFilterOrColumnUpdates.java
index 55de852339bf77f1b1c0002c184aca15f7f58fd0..4f9f0c8f5a34e526de0ee05226131c1178a8f95a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/IFilterOrColumnUpdates.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/IFilterOrColumnUpdates.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.shared.basic.dto;
 
+import com.google.gwt.user.client.rpc.IsSerializable;
+
 import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
 
 /**
@@ -23,7 +25,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
  * 
  * @author Piotr Buczek
  */
-public interface IFilterOrColumnUpdates extends IIdHolder
+public interface IFilterOrColumnUpdates extends IIdHolder, IsSerializable
 {
     String getDescription();
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/GridCustomExpressionTranslator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/GridCustomExpressionTranslator.java
index 004e0080748647d4393686c4f2c00e5464d51a76..0e53eb605dfc51094d72b58dcc11fe36f06358b4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/GridCustomExpressionTranslator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/GridCustomExpressionTranslator.java
@@ -68,7 +68,7 @@ public final class GridCustomExpressionTranslator
             }
             final GridCustomColumn result = new GridCustomColumn();
             result.setCode(escapeHtml(original.getCode()));
-            result.setLabel(escapeHtml(original.getLabel()));
+            result.setName(escapeHtml(original.getLabel()));
 
             translateGridExpression(original, result);
             return result;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
index 1030a1792a4ebaed18b4e5cddac1ff6a6b5bb43e..08cb89b3d54f19e2d260ef7b022cea3a38bccc74 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
@@ -504,12 +504,15 @@ samples_radio_group_label: "Samples",
  name: "Name",
  is_public: "Is Public?",
  expression: "Expression",
+ column: "Column",
  columns: "Columns",
- grid_settings_title: "Table settings",
- custom_filters: "Custom filters",
+ grid_settings_title: "Table Settings",
+ grid_custom_filters: "Custom Filters",
+ grid_custom_columns: "Custom Columns",
  apply_filter: "Apply",
  reset_filter: "Reset",
- add_new_filter: "Add a New Filter",
+ add_new_filter: "Add a New Filter",
+ add_new_column: "Add a New Column",
  how_to_address: "How To Address", 
  insert_columns: "Insert Columns", 
  
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/FilterTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/FilterTest.java
index 813ea03bae3941775eb3189f29c195b24355203e..a6076baec0086bdcc1280593f94379a4ec4054fb 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/FilterTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/FilterTest.java
@@ -18,7 +18,7 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.application;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.framework.DisplayTypeIDGenerator;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.TopMenu.ActionMenuKind;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.specific.FilterColDefKind;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.columns.specific.CustomGridFilterColDefKind;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.AddFilterCommand;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.ApplyFilterCommand;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.CheckFiltersTableCommand;
@@ -63,10 +63,10 @@ public class FilterTest extends AbstractGWTTestCase
 
         // Check new filter
         CheckFiltersTableCommand filtersTable = new CheckFiltersTableCommand(gridDisplayId);
-        filtersTable.expectedRow(new Row().withCell(FilterColDefKind.NAME.id(), NAME));
+        filtersTable.expectedRow(new Row().withCell(CustomGridFilterColDefKind.NAME.id(), NAME));
         filtersTable
-                .expectedRow(new Row().withCell(FilterColDefKind.DESCRIPTION.id(), DESCRIPTION));
-        filtersTable.expectedRow(new Row().withCell(FilterColDefKind.EXPRESSION.id(), EXPRESSION));
+                .expectedRow(new Row().withCell(CustomGridFilterColDefKind.DESCRIPTION.id(), DESCRIPTION));
+        filtersTable.expectedRow(new Row().withCell(CustomGridFilterColDefKind.EXPRESSION.id(), EXPRESSION));
         remoteConsole.prepare(filtersTable.expectedSize(1));
 
         // Apply filter
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AddFilterCommand.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AddFilterCommand.java
index 3a3791251ac7617b0a8c66d5b3b061c524e64845..a06133f91263523e8798ca299dd2c5e361b8ba62 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AddFilterCommand.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/AddFilterCommand.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.filter.common.AbstractGridCustomExpressionEditOrRegisterDialog;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.AbstractSaveDialog;
 import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.CheckTableCommand;
 import ch.systemsx.cisd.openbis.generic.client.web.client.testframework.GWTTestUtil;
@@ -41,7 +42,7 @@ public final class AddFilterCommand extends CheckTableCommand
     public AddFilterCommand(String gridDisplayId, String name, String description,
             String expression, boolean isPublic)
     {
-        super(FilterGrid.createGridId(gridDisplayId));
+        super(GridCustomFilterGrid.createGridId(gridDisplayId));
         this.gridDisplayId = gridDisplayId;
         this.name = name;
         this.description = description;
@@ -52,17 +53,22 @@ public final class AddFilterCommand extends CheckTableCommand
     @Override
     public final void execute()
     {
-        GWTTestUtil.clickButtonWithID(FilterGrid.createAddButtonId(gridDisplayId));
+        GWTTestUtil.clickButtonWithID(GridCustomFilterGrid.createAddButtonId(gridDisplayId));
         GWTTestUtil.getTextFieldWithID(
-                AddFilterDialog.createId(gridDisplayId, AddFilterDialog.NAME_FIELD)).setValue(name);
+                AbstractGridCustomExpressionEditOrRegisterDialog.createId(gridDisplayId,
+                        AbstractGridCustomExpressionEditOrRegisterDialog.NAME_FIELD))
+                .setValue(name);
         GWTTestUtil.getTextAreaWithId(
-                AddFilterDialog.createId(gridDisplayId, AddFilterDialog.DESCRIPTION_FIELD))
+                AbstractGridCustomExpressionEditOrRegisterDialog.createId(gridDisplayId,
+                        AbstractGridCustomExpressionEditOrRegisterDialog.DESCRIPTION_FIELD))
                 .setValue(description);
         GWTTestUtil.getTextAreaWithId(
-                AddFilterDialog.createId(gridDisplayId, AddFilterDialog.EXPRESSION_FIELD))
+                AbstractGridCustomExpressionEditOrRegisterDialog.createId(gridDisplayId,
+                        AbstractGridCustomExpressionEditOrRegisterDialog.EXPRESSION_FIELD))
                 .setValue(expression);
         GWTTestUtil.getCheckboxWithId(
-                (AddFilterDialog.createId(gridDisplayId, AddFilterDialog.PUBLIC_FIELD))).setValue(
+                (AbstractGridCustomExpressionEditOrRegisterDialog.createId(gridDisplayId,
+                        AbstractGridCustomExpressionEditOrRegisterDialog.PUBLIC_FIELD))).setValue(
                 isPublic);
         GWTTestUtil.clickButtonWithID(AbstractSaveDialog.SAVE_BUTTON_ID);
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/CheckFiltersTableCommand.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/CheckFiltersTableCommand.java
index 44d450d9a70f9eecce3a8e8b39380ccf13628d22..fb991dd6769d58d6808ad0072558c3e92d49e9ba 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/CheckFiltersTableCommand.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/filter/CheckFiltersTableCommand.java
@@ -33,7 +33,7 @@ public class CheckFiltersTableCommand extends CheckTableCommand
 
     public CheckFiltersTableCommand(String gridDisplayId)
     {
-        super(FilterGrid.createGridId(gridDisplayId));
+        super(GridCustomFilterGrid.createGridId(gridDisplayId));
         addCallbackClass(AbstractSaveDialog.SaveDialogCallback.class);
         this.gridDisplayId = gridDisplayId;
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/GridCustomColumnDAOTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/GridCustomColumnDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3054b3ae0f6129a45077bfca5353420fb9703016
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/GridCustomColumnDAOTest.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.server.dataaccess.db;
+
+import java.util.List;
+
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IGridCustomColumnDAO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.GridCustomColumnPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+
+/**
+ * Test cases for corresponding {@link GridCustomColumnDAO} class.
+ * 
+ * @author Tomasz Pylak
+ */
+@Test(groups =
+    { "db", "column" })
+public final class GridCustomColumnDAOTest extends AbstractDAOTest
+{
+    public void testCreateAndListColumn() throws Exception
+    {
+        IGridCustomColumnDAO dao = daoFactory.getGridCustomColumnDAO();
+        AssertJUnit.assertEquals(0, dao.listAllEntities().size());
+        GridCustomColumnPE column =
+                create("NAME", "GRID", "DESCRIPTION", "EXPRESSION", true, getSystemPerson());
+        dao.createColumn(column);
+        List<GridCustomColumnPE> columns = dao.listAllEntities();
+        AssertJUnit.assertEquals(1, columns.size());
+        AssertJUnit.assertEquals(column, columns.get(0));
+    }
+
+    private static final GridCustomColumnPE create(String name, String grid, String desc,
+            String expr, boolean isPublic, PersonPE registrator)
+    {
+        GridCustomColumnPE record = new GridCustomColumnPE();
+        record.setCode(name + "_xxx");
+        record.setLabel(name);
+        record.setDescription(desc);
+        record.setExpression(expr);
+        record.setGridId(grid);
+        record.setPublic(isPublic);
+        record.setRegistrator(registrator);
+        return record;
+    }
+
+}