[libgda] Allow to specify display preferences on table's colums



commit 64fce91185fc7b905a7e35febe25bb739f457bbf
Author: Vivien Malerba <malerba gnome-db org>
Date:   Mon Jan 11 21:16:32 2010 +0100

    Allow to specify display preferences on table's colums

 doc/C/tmpl/gdaui-basic-form.sgml                 |   20 +
 libgda-ui/data-entries/gdaui-entry-combo.c       |    5 +-
 libgda-ui/data-entries/gdaui-entry-number.c      |   10 +-
 libgda-ui/data-entries/gdaui-numeric-entry.c     |   28 +-
 libgda-ui/data-entries/plugins/libmain.c         |   13 -
 libgda-ui/gdaui-combo.c                          |    4 +-
 libgda-ui/gdaui-plugin.h                         |    1 +
 libgda/gda-set.c                                 |    4 +-
 libgda/gda-util.c                                |    7 +-
 po/POTFILES.in                                   |    1 +
 tools/browser/browser-connection-priv.h          |    2 +
 tools/browser/browser-connection.c               |  322 ++++++++-
 tools/browser/browser-connection.h               |   21 +-
 tools/browser/browser-window.c                   |    2 +-
 tools/browser/doc/gda-browser-sections.txt       |    4 +
 tools/browser/doc/tmpl/browser-connection.sgml   |   50 ++
 tools/browser/marshal.list                       |    1 +
 tools/browser/query-exec/query-result.c          |   71 ++-
 tools/browser/schema-browser/Makefile.am         |    2 +
 tools/browser/schema-browser/table-info.c        |   10 +
 tools/browser/schema-browser/table-preferences.c |  864 ++++++++++++++++++++++
 tools/browser/schema-browser/table-preferences.h |   56 ++
 22 files changed, 1462 insertions(+), 36 deletions(-)
---
diff --git a/doc/C/tmpl/gdaui-basic-form.sgml b/doc/C/tmpl/gdaui-basic-form.sgml
index 66c68d8..04c0a8d 100644
--- a/doc/C/tmpl/gdaui-basic-form.sgml
+++ b/doc/C/tmpl/gdaui-basic-form.sgml
@@ -284,3 +284,23 @@ which can be described by the following DTD.
 @Returns: 
 
 
+<!-- ##### FUNCTION gdaui_basic_form_set_layout_from_file ##### -->
+<para>
+
+</para>
+
+ form: 
+ file_name: 
+ form_name: 
+
+
+<!-- ##### FUNCTION gdaui_basic_form_get_place_holder ##### -->
+<para>
+
+</para>
+
+ form: 
+ placeholder_id: 
+ Returns: 
+
+
diff --git a/libgda-ui/data-entries/gdaui-entry-combo.c b/libgda-ui/data-entries/gdaui-entry-combo.c
index 6825e50..35550dd 100644
--- a/libgda-ui/data-entries/gdaui-entry-combo.c
+++ b/libgda-ui/data-entries/gdaui-entry-combo.c
@@ -80,8 +80,8 @@ struct  _GdauiEntryComboPriv {
         GtkWidget              *combo_entry;
 	GSList                 *combo_nodes; /* list of ComboNode structures */
 
-	GdauiSet             *paramlist; // useless?
-	GdauiSetSource       *source;	
+	GdauiSet               *paramlist;
+	GdauiSetSource         *source;	
 	
 	gboolean                data_valid;
 	gboolean                null_forced;
@@ -287,6 +287,7 @@ void _gdaui_entry_combo_construct (GdauiEntryCombo* combo, GdauiSet *paramlist,
 	entry = gdaui_combo_new_with_model (GDA_DATA_MODEL (source->source->data_model), 
 					    combo->priv->source->shown_n_cols, 
 					    combo->priv->source->shown_cols_index);
+	g_object_set (G_OBJECT (entry), "as-list", TRUE, NULL);
 	g_signal_connect (G_OBJECT (entry), "changed",
 			  G_CALLBACK (combo_contents_changed_cb), combo);
 
diff --git a/libgda-ui/data-entries/gdaui-entry-number.c b/libgda-ui/data-entries/gdaui-entry-number.c
index dc77c68..4bc128a 100644
--- a/libgda-ui/data-entries/gdaui-entry-number.c
+++ b/libgda-ui/data-entries/gdaui-entry-number.c
@@ -487,10 +487,14 @@ set_entry_options (GdauiEntryNumber *mgstr, const gchar *options)
 				mgstr->priv->thousand_sep = 0;
 		}
 		str = gda_quark_list_find (params, "NB_DECIMALS");
-		if (str) 
-			mgstr->priv->nb_decimals = atoi (str);
-		str = gda_quark_list_find (params, "CURRENCY");
 		if (str) {
+			if (*str)
+				mgstr->priv->nb_decimals = atoi (str);
+			else
+				mgstr->priv->nb_decimals = 0;
+		}
+		str = gda_quark_list_find (params, "CURRENCY");
+		if (str && *str) {
 			g_free (mgstr->priv->currency);
 			mgstr->priv->currency = g_strdup_printf ("%s ", str);
 		}
diff --git a/libgda-ui/data-entries/gdaui-numeric-entry.c b/libgda-ui/data-entries/gdaui-numeric-entry.c
index 9c0a0fa..a6946e0 100644
--- a/libgda-ui/data-entries/gdaui-numeric-entry.c
+++ b/libgda-ui/data-entries/gdaui-numeric-entry.c
@@ -375,7 +375,7 @@ text_unformat (GdauiNumericEntry *entry, gchar *str, gint *pos)
  * Retunrs: a new string
  */
 static gchar *
-text_reformat (GdauiNumericEntry *entry, gchar *str, gint *pos)
+text_reformat (GdauiNumericEntry *entry, gchar *str, gint *pos, gboolean allow_sep_ending)
 {
 	g_assert (str);
 	GString *string;
@@ -451,8 +451,28 @@ text_reformat (GdauiNumericEntry *entry, gchar *str, gint *pos)
 				for (i = nb_dec; i < entry->priv->nb_decimals; i++)
 					g_string_append_c (string, '0');
 			}
-			else if (nb_dec > entry->priv->nb_decimals)
+			else if (nb_dec > entry->priv->nb_decimals) {
 				g_string_truncate (string, len - (nb_dec - entry->priv->nb_decimals));
+				if (!allow_sep_ending &&
+				    (string->str[string->len - 1] == entry->priv->decimal_sep)) {
+					/* we don't want numbers terminated by entry->priv->decimal_sep */
+					g_string_truncate (string, string->len - 1);
+				}
+			}
+		}
+	}
+	else if ((! entry->priv->num_attr.is_int) &&
+		 dec_pos >= 0) {
+		/* remove all the '0' which are useless */
+		while ((string->str[string->len - 1] == entry->priv->decimal_sep) ||
+		       (string->str[string->len - 1] == '0')) {
+			if (string->str[string->len - 1] == entry->priv->decimal_sep) {
+				if (!allow_sep_ending)
+					g_string_truncate (string, string->len - 1);
+				break;
+			}
+			else
+				g_string_truncate (string, string->len - 1);
 		}
 	}
 
@@ -573,7 +593,7 @@ gdaui_numeric_entry_assume_insert (GdauiEntry *entry, const gchar *text, gint te
 		/*g_print ("ERROR!\n");*/
 		return;
 	}
-	ntext = text_reformat (fentry, string->str, virt_pos);
+	ntext = text_reformat (fentry, string->str, virt_pos, (text[text_length-1] == fentry->priv->decimal_sep));
 	g_string_free (string, TRUE);
 	/*g_print ("NEW: [%s]\n", ntext);*/
 
@@ -629,7 +649,7 @@ gdaui_numeric_entry_assume_delete (GdauiEntry *entry, gint virt_start_pos, gint
 		}
 	}
 	else {
-		ntext = text_reformat (fentry, string->str, &cursor_pos);
+		ntext = text_reformat (fentry, string->str, &cursor_pos, FALSE);
 		g_string_free (string, TRUE);
 	}
 	/*g_print ("NEW: [%s]\n", ntext);*/
diff --git a/libgda-ui/data-entries/plugins/libmain.c b/libgda-ui/data-entries/plugins/libmain.c
index b5f6949..18d991a 100644
--- a/libgda-ui/data-entries/plugins/libmain.c
+++ b/libgda-ui/data-entries/plugins/libmain.c
@@ -183,19 +183,6 @@ plugin_init (GError **error)
 	}
 	g_free (file);
 
-	/* CGRID */
-	plugin = g_new0 (GdauiPlugin, 1);
-	plugin->plugin_name = "cgrid";
-	plugin->plugin_descr = "ComboGrid entry";
-	plugin->plugin_file = NULL; /* always leave NULL */
-	plugin->nb_g_types = 1;
-	plugin->valid_g_types = g_new (GType, plugin->nb_g_types);
-	plugin->valid_g_types [0] = G_TYPE_STRING;;
-	plugin->options_xml_spec = NULL;
-	plugin->entry_create_func = plugin_entry_cgrid_create_func;
-	plugin->cell_create_func = plugin_cell_renderer_cgrid_create_func;
-	retlist = g_slist_append (retlist, plugin);
-
 	return retlist;
 }
 
diff --git a/libgda-ui/gdaui-combo.c b/libgda-ui/gdaui-combo.c
index 1b5039b..7f3cc11 100644
--- a/libgda-ui/gdaui-combo.c
+++ b/libgda-ui/gdaui-combo.c
@@ -214,7 +214,7 @@ gdaui_combo_set_property (GObject *object,
 			gtk_rc_parse_string ("style \"gdaui-combo-as-list-style\"\n"
 					     "{\n"
 					     "GtkComboBox::appears-as-list = 1\n"
-					     "GtkComboBox::arrow-size = 10\n"
+					     "GtkComboBox::arrow-size = 5\n"
 					     "}\n"
 					     "widget \"*.gdaui-combo-as-list-style\" style \"gdaui-combo-as-list-style\"");
 		}
@@ -462,7 +462,7 @@ gdaui_combo_set_model (GdauiCombo *combo, GdaDataModel *model, gint n_cols, gint
 			g_object_set_data (G_OBJECT (renderer), "data-handler", dh);
 			g_object_set_data (G_OBJECT (renderer), "colnum", GINT_TO_POINTER (index));
 			g_object_set ((GObject*) renderer, "width-chars",
-				      combo->priv->cols_width [index], NULL);
+				      combo->priv->cols_width [index] + 1, NULL);
 			
 			gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
 			gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), renderer,
diff --git a/libgda-ui/gdaui-plugin.h b/libgda-ui/gdaui-plugin.h
index c5bce00..0bd60f2 100644
--- a/libgda-ui/gdaui-plugin.h
+++ b/libgda-ui/gdaui-plugin.h
@@ -23,6 +23,7 @@
 
 #include <gtk/gtk.h>
 #include <libgda/gda-value.h>
+#include <libgda-ui/gdaui-data-entry.h>
 #include "gdaui-decl.h"
 
 typedef GdauiDataEntry   *(*GdauiEntryCreateFunc)(GdaDataHandler *, GType, const gchar *);
diff --git a/libgda/gda-set.c b/libgda/gda-set.c
index 315fd8c..cfe4c71 100644
--- a/libgda/gda-set.c
+++ b/libgda/gda-set.c
@@ -776,9 +776,9 @@ gda_set_new_from_spec_node (xmlNodePtr xml_spec, GError **error)
 				}
 				else  {
 					sources = g_slist_prepend (sources, model);
-					str = (gchar*)xmlGetProp(cur, (xmlChar*)"name");
+					str = (gchar*)xmlGetProp(cur, (xmlChar*) "name");
 					if (str) 
-						g_object_set_data_full (G_OBJECT (model), "name", str, g_free);
+						g_object_set_data_full (G_OBJECT (model), "name", str, xmlFree);
 				}
 			}
 		}
diff --git a/libgda/gda-util.c b/libgda/gda-util.c
index 5b6e6e8..4a964a4 100644
--- a/libgda/gda-util.c
+++ b/libgda/gda-util.c
@@ -541,9 +541,6 @@ gda_utility_holder_load_attributes (GdaHolder *holder, xmlNodePtr node, GSList *
 	else
 		gda_holder_set_not_null (holder, FALSE);
 	
-	str = xmlGetProp (node, BAD_CAST "source");
-	if (str) 
-		g_object_set_data_full (G_OBJECT (holder), "source", str, xmlFree);
 	str = xmlGetProp (node, BAD_CAST "plugin");
 	if (str) {
 		GValue *value;
@@ -554,6 +551,10 @@ gda_utility_holder_load_attributes (GdaHolder *holder, xmlNodePtr node, GSList *
 		xmlFree (str);
 	}
 
+	str = xmlGetProp (node, BAD_CAST "source");
+	if (str) 
+		g_object_set_data_full (G_OBJECT (holder), "source", str, xmlFree);
+
 	/* set restricting source if specified */
 	if (str && sources) {
 		gchar *ptr1, *ptr2 = NULL, *tok;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3ae6f91..1eff538 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -244,6 +244,7 @@ tools/browser/schema-browser/perspective-main.c
 tools/browser/schema-browser/relations-diagram.c
 tools/browser/schema-browser/schema-browser-perspective.c
 tools/browser/schema-browser/table-columns.c
+tools/browser/schema-browser/table-contents.c
 tools/browser/schema-browser/table-info.c
 tools/command-exec.c
 tools/gda-list-config.c
diff --git a/tools/browser/browser-connection-priv.h b/tools/browser/browser-connection-priv.h
index f7b741a..4371893 100644
--- a/tools/browser/browser-connection-priv.h
+++ b/tools/browser/browser-connection-priv.h
@@ -43,6 +43,8 @@ struct _BrowserConnectionPrivate {
 
 	gboolean  busy;
 	gchar    *busy_reason;
+
+	GdaConnection *store_cnc;
 };
 
 void browser_connection_set_busy_state (BrowserConnection *bcnc, gboolean busy, const gchar *busy_reason);
diff --git a/tools/browser/browser-connection.c b/tools/browser/browser-connection.c
index e44fef8..dc2b914 100644
--- a/tools/browser/browser-connection.c
+++ b/tools/browser/browser-connection.c
@@ -54,10 +54,11 @@ enum {
 	META_CHANGED,
 	FAV_CHANGED,
 	TRANSACTION_STATUS_CHANGED,
+	TABLE_COLUMN_PREF_CHANGED,
 	LAST_SIGNAL
 };
 
-gint browser_connection_signals [LAST_SIGNAL] = { 0, 0, 0, 0 };
+gint browser_connection_signals [LAST_SIGNAL] = { 0, 0, 0, 0, 0 };
 
 /* wrapper jobs handling */
 static gboolean check_for_wrapper_result (BrowserConnection *bcnc);
@@ -204,11 +205,20 @@ browser_connection_class_init (BrowserConnectionClass *klass)
                               NULL, NULL,
                               g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
                               0);
+	browser_connection_signals [TABLE_COLUMN_PREF_CHANGED] =
+		g_signal_new ("table-column-pref-changed",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (BrowserConnectionClass, table_column_pref_changed),
+                              NULL, NULL,
+			      _marshal_VOID__POINTER_POINTER_STRING_STRING, G_TYPE_NONE,
+                              4, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
 
 	klass->busy = browser_connection_set_busy_state;
 	klass->meta_changed = NULL;
 	klass->favorites_changed = NULL;
 	klass->transaction_status_changed = NULL;
+	klass->table_column_pref_changed = NULL;
 
 	/* Properties */
         object_class->set_property = browser_connection_set_property;
@@ -242,6 +252,8 @@ browser_connection_init (BrowserConnection *bcnc)
 	bcnc->priv->mstruct = NULL;
 
 	bcnc->priv->bfav = NULL;
+
+	bcnc->priv->store_cnc = NULL;
 }
 
 static void
@@ -412,6 +424,9 @@ browser_connection_dispose (GObject *object)
 
 	bcnc = BROWSER_CONNECTION (object);
 	if (bcnc->priv) {
+		if (bcnc->priv->store_cnc)
+			g_object_unref (bcnc->priv->store_cnc);
+
 		if (bcnc->priv->executed_statements)
 			g_hash_table_destroy (bcnc->priv->executed_statements);
 
@@ -1017,6 +1032,25 @@ browser_connection_execution_get_result (BrowserConnection *bcnc, guint exec_id,
 	return retval;
 }
 
+/**
+ * browser_connection_normalize_sql_statement
+ * @bcnc: a #BrowserConnection
+ * @sqlst: a #GdaSqlStatement
+ * @error: a place to store errors, or %NULL
+ *
+ * See gda_sql_statement_normalize().
+ *
+ * Returns: %TRUE if no error occurred
+ */
+gboolean
+browser_connection_normalize_sql_statement (BrowserConnection *bcnc,
+					    GdaSqlStatement *sqlst, GError **error)
+{
+	g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
+	
+	return gda_sql_statement_normalize (sqlst, bcnc->priv->cnc, error);
+}
+
 
 /*
  * DOES NOT emit any signal
@@ -1033,3 +1067,289 @@ browser_connection_set_busy_state (BrowserConnection *bcnc, gboolean busy, const
 	if (busy_reason)
 		bcnc->priv->busy_reason = g_strdup (busy_reason);
 }
+
+/*
+ *
+ * Preferences
+ *
+ */
+#define DBTABLE_PREFERENCES_TABLE_NAME "gda_sql_dbtable_preferences"
+#define DBTABLE_PREFERENCES_TABLE_DESC \
+        "<table name=\"" DBTABLE_PREFERENCES_TABLE_NAME "\"> "                            \
+        "   <column name=\"table_schema\" pkey=\"TRUE\"/>"             \
+        "   <column name=\"table_name\" pkey=\"TRUE\"/>"                              \
+        "   <column name=\"table_column\" nullok=\"TRUE\" pkey=\"TRUE\"/>"                              \
+        "   <column name=\"att_name\"/>"                          \
+        "   <column name=\"att_value\"/>"                           \
+        "</table>"
+
+static gboolean
+meta_store_addons_init (BrowserConnection *bcnc, GError **error)
+{
+	GError *lerror = NULL;
+	GdaMetaStore *store;
+
+	if (!bcnc->priv->cnc) {
+		g_set_error (error, 0, 0,
+			     _("Connection not yet opened"));
+		return FALSE;
+	}
+	store = gda_connection_get_meta_store (bcnc->priv->cnc);
+	if (!gda_meta_store_schema_add_custom_object (store, DBTABLE_PREFERENCES_TABLE_DESC, &lerror)) {
+                g_set_error (error, 0, 0, "%s",
+                             _("Can't initialize dictionary to store table preferences"));
+		g_warning ("Can't initialize dictionary to store dbtable_preferences :%s",
+			   lerror && lerror->message ? lerror->message : "No detail");
+		if (lerror)
+			g_error_free (lerror);
+                return FALSE;
+        }
+
+	bcnc->priv->store_cnc = g_object_ref (gda_meta_store_get_internal_connection (store));
+	return TRUE;
+}
+
+
+/**
+ * browser_connection_set_table_column_attribute
+ * @bcnc:
+ * @dbo:
+ * @column:
+ * @attr_name: attribute name, not %NULL
+ * @value: value to set, or %NULL to unset
+ * @error:
+ *
+ *
+ * Returns: %TRUE if no error occurred
+ */
+gboolean
+browser_connection_set_table_column_attribute (BrowserConnection *bcnc,
+					       GdaMetaTable *table,
+					       GdaMetaTableColumn *column,
+					       const gchar *attr_name,
+					       const gchar *value, GError **error)
+{
+	GdaConnection *store_cnc;
+
+	g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
+	g_return_val_if_fail (table, FALSE);
+	g_return_val_if_fail (column, FALSE);
+	g_return_val_if_fail (attr_name, FALSE);
+
+	if (! bcnc->priv->store_cnc &&
+	    ! meta_store_addons_init (bcnc, error))
+		return FALSE;
+
+	store_cnc = bcnc->priv->store_cnc;
+	if (! gda_lockable_trylock (GDA_LOCKABLE (store_cnc))) {
+		g_set_error (error, 0, 0, "%s",
+                             _("Can't initialize transaction to access favorites"));
+		return FALSE;
+	}
+	/* begin a transaction */
+	if (! gda_connection_begin_transaction (store_cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL)) {
+		g_set_error (error, 0, 0, "%s",
+                             _("Can't initialize transaction to access favorites"));
+		gda_lockable_unlock (GDA_LOCKABLE (store_cnc));
+                return FALSE;
+	}
+
+	/* delete existing attribute */
+	GdaStatement *stmt;
+	GdaSqlBuilder *builder;
+	GdaSet *params;
+	guint op_ids[4];
+	GdaMetaDbObject *dbo = (GdaMetaDbObject *) table;
+
+	params = gda_set_new_inline (5, "schema", G_TYPE_STRING, dbo->obj_schema,
+				     "name", G_TYPE_STRING, dbo->obj_name,
+				     "column", G_TYPE_STRING, column->column_name,
+				     "attname", G_TYPE_STRING, attr_name,
+				     "attvalue", G_TYPE_STRING, value);
+
+	builder = gda_sql_builder_new (GDA_SQL_STATEMENT_DELETE);
+	gda_sql_builder_set_table (builder, DBTABLE_PREFERENCES_TABLE_NAME);
+	op_ids[0] = gda_sql_builder_add_cond (builder, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+					      gda_sql_builder_add_id (builder, 0, "table_schema"),
+					      gda_sql_builder_add_param (builder, 0, "schema", G_TYPE_STRING,
+									 FALSE), 0);
+	op_ids[1] = gda_sql_builder_add_cond (builder, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+					      gda_sql_builder_add_id (builder, 0, "table_name"),
+					      gda_sql_builder_add_param (builder, 0, "name", G_TYPE_STRING,
+									 FALSE), 0);
+	op_ids[2] = gda_sql_builder_add_cond (builder, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+					      gda_sql_builder_add_id (builder, 0, "table_column"),
+					      gda_sql_builder_add_param (builder, 0, "column", G_TYPE_STRING,
+									 FALSE), 0);
+	op_ids[3] = gda_sql_builder_add_cond (builder, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+					      gda_sql_builder_add_id (builder, 0, "att_name"),
+					      gda_sql_builder_add_param (builder, 0, "attname", G_TYPE_STRING,
+									 FALSE), 0);
+	gda_sql_builder_set_where (builder,
+				   gda_sql_builder_add_cond_v (builder, 0, GDA_SQL_OPERATOR_TYPE_AND,
+							       op_ids, 4));
+	stmt = gda_sql_builder_get_statement (builder, error);
+	g_object_unref (G_OBJECT (builder));
+	if (!stmt)
+		goto err;
+	if (gda_connection_statement_execute_non_select (store_cnc, stmt, params, NULL, error) == -1) {
+		g_object_unref (stmt);
+		goto err;
+	}
+	g_object_unref (stmt);		
+
+	/* insert new attribute if necessary */
+	if (value) {
+		builder = gda_sql_builder_new (GDA_SQL_STATEMENT_INSERT);
+		gda_sql_builder_set_table (builder, DBTABLE_PREFERENCES_TABLE_NAME);
+		gda_sql_builder_add_field_id (builder,
+					      gda_sql_builder_add_id (builder, 0, "table_schema"),
+					      gda_sql_builder_add_param (builder, 0, "schema", G_TYPE_STRING, FALSE));
+		gda_sql_builder_add_field_id (builder,
+					      gda_sql_builder_add_id (builder, 0, "table_name"),
+					      gda_sql_builder_add_param (builder, 0, "name", G_TYPE_STRING, FALSE));
+		gda_sql_builder_add_field_id (builder,
+					      gda_sql_builder_add_id (builder, 0, "table_column"),
+					      gda_sql_builder_add_param (builder, 0, "column", G_TYPE_STRING, FALSE));
+		gda_sql_builder_add_field_id (builder,
+					      gda_sql_builder_add_id (builder, 0, "att_name"),
+					      gda_sql_builder_add_param (builder, 0, "attname", G_TYPE_STRING, FALSE));
+		gda_sql_builder_add_field_id (builder,
+					      gda_sql_builder_add_id (builder, 0, "att_value"),
+					      gda_sql_builder_add_param (builder, 0, "attvalue", G_TYPE_STRING, FALSE));
+		stmt = gda_sql_builder_get_statement (builder, error);
+		g_object_unref (G_OBJECT (builder));
+		if (!stmt)
+			goto err;
+		if (gda_connection_statement_execute_non_select (store_cnc, stmt, params, NULL, error) == -1) {
+			g_object_unref (stmt);
+			goto err;
+		}
+		g_object_unref (stmt);
+	}
+
+	if (! gda_connection_commit_transaction (store_cnc, NULL, NULL)) {
+		g_set_error (error, 0, 0, "%s",
+                             _("Can't commit transaction to access favorites"));
+		goto err;
+	}
+
+	g_object_unref (params);
+	gda_lockable_unlock (GDA_LOCKABLE (store_cnc));
+	/*
+	g_print ("%s(table=>%s, column=>%s, value=>%s)\n", __FUNCTION__, GDA_META_DB_OBJECT (table)->obj_full_name,
+		 column->column_name, value);
+	*/
+	g_signal_emit (bcnc, browser_connection_signals [TABLE_COLUMN_PREF_CHANGED], 0,
+		       table, column, attr_name, value);
+
+	return TRUE;
+
+ err:
+	g_object_unref (params);
+	gda_lockable_unlock (GDA_LOCKABLE (store_cnc));
+	gda_connection_rollback_transaction (store_cnc, NULL, NULL);
+	return FALSE;
+}
+
+/**
+ * browser_connection_get_table_column_attribute
+ * @bcnc:
+ * @dbo:
+ * @column: may be %NULL
+ * @attr_name: attribute name, not %NULL
+ * @error:
+ *
+ *
+ * Returns: the requested attribute, or %NULL if not set or if an error occurred
+ */
+gchar *
+browser_connection_get_table_column_attribute  (BrowserConnection *bcnc,
+						GdaMetaTable *table,
+						GdaMetaTableColumn *column,
+						const gchar *attr_name,
+						GError **error)
+{
+	GdaConnection *store_cnc;
+	gchar *retval = NULL;
+
+	g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
+	g_return_val_if_fail (table, FALSE);
+	g_return_val_if_fail (column, FALSE);
+	g_return_val_if_fail (attr_name, FALSE);
+
+	if (! bcnc->priv->store_cnc &&
+	    ! meta_store_addons_init (bcnc, error))
+		return FALSE;
+
+	store_cnc = bcnc->priv->store_cnc;
+	if (! gda_lockable_trylock (GDA_LOCKABLE (store_cnc))) {
+		g_set_error (error, 0, 0, "%s",
+                             _("Can't initialize transaction to access favorites"));
+		return FALSE;
+	}
+
+	/* SELECT */
+	GdaStatement *stmt;
+	GdaSqlBuilder *builder;
+	GdaSet *params;
+	guint op_ids[4];
+	GdaDataModel *model;
+	const GValue *cvalue;
+	GdaMetaDbObject *dbo = (GdaMetaDbObject *) table;
+
+	params = gda_set_new_inline (4, "schema", G_TYPE_STRING, dbo->obj_schema,
+				     "name", G_TYPE_STRING, dbo->obj_name,
+				     "column", G_TYPE_STRING, column->column_name,
+				     "attname", G_TYPE_STRING, attr_name);
+
+	builder = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
+	gda_sql_builder_select_add_target_id (builder, 0,
+					      gda_sql_builder_add_id (builder, 0, DBTABLE_PREFERENCES_TABLE_NAME),
+					      NULL);
+	gda_sql_builder_select_add_field (builder, "att_value", NULL, NULL);
+	op_ids[0] = gda_sql_builder_add_cond (builder, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+					      gda_sql_builder_add_id (builder, 0, "table_schema"),
+					      gda_sql_builder_add_param (builder, 0, "schema", G_TYPE_STRING,
+									 FALSE), 0);
+	op_ids[1] = gda_sql_builder_add_cond (builder, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+					      gda_sql_builder_add_id (builder, 0, "table_name"),
+					      gda_sql_builder_add_param (builder, 0, "name", G_TYPE_STRING,
+									 FALSE), 0);
+	op_ids[2] = gda_sql_builder_add_cond (builder, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+					      gda_sql_builder_add_id (builder, 0, "table_column"),
+					      gda_sql_builder_add_param (builder, 0, "column", G_TYPE_STRING,
+									 FALSE), 0);
+	op_ids[3] = gda_sql_builder_add_cond (builder, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+					      gda_sql_builder_add_id (builder, 0, "att_name"),
+					      gda_sql_builder_add_param (builder, 0, "attname", G_TYPE_STRING,
+									 FALSE), 0);
+	gda_sql_builder_set_where (builder,
+				   gda_sql_builder_add_cond_v (builder, 0, GDA_SQL_OPERATOR_TYPE_AND,
+							       op_ids, 4));
+	stmt = gda_sql_builder_get_statement (builder, error);
+	g_object_unref (G_OBJECT (builder));
+	if (!stmt)
+		goto out;
+
+	model = gda_connection_statement_execute_select (store_cnc, stmt, params, error);
+	g_object_unref (stmt);
+	if (!model)
+		goto out;
+
+	/*gda_data_model_dump (model, NULL);*/
+	if (gda_data_model_get_n_rows (model) == 0)
+		goto out;
+
+	cvalue = gda_data_model_get_value_at (model, 0, 0, error);
+	if (cvalue)
+		retval = g_value_dup_string (cvalue);
+
+ out:
+	if (model)
+		g_object_unref (model);
+	g_object_unref (params);
+	gda_lockable_unlock (GDA_LOCKABLE (store_cnc));
+
+	return retval;
+}
diff --git a/tools/browser/browser-connection.h b/tools/browser/browser-connection.h
index 7a38d03..0d057ba 100644
--- a/tools/browser/browser-connection.h
+++ b/tools/browser/browser-connection.h
@@ -52,6 +52,9 @@ struct _BrowserConnectionClass
 	void                    (*meta_changed) (BrowserConnection *bcnc, GdaMetaStruct *mstruct);
 	void                    (*favorites_changed) (BrowserConnection *bcnc);
 	void                    (*transaction_status_changed) (BrowserConnection *bcnc);
+	void                    (*table_column_pref_changed) (BrowserConnection *bcnc, GdaMetaTable *table,
+							      GdaMetaTableColumn *column,
+							      const gchar *attr_name, const gchar *value);
 };
 
 GType               browser_connection_get_type               (void) G_GNUC_CONST;
@@ -72,7 +75,7 @@ gchar             **browser_connection_get_completions        (BrowserConnection
 							       gint start, gint end);
 
 /*
- * statements's execution
+ * statements's manipulations
  */
 GdaSqlParser       *browser_connection_create_parser          (BrowserConnection *bcnc);
 gchar              *browser_connection_render_pretty_sql      (BrowserConnection *bcnc,
@@ -86,6 +89,8 @@ guint               browser_connection_execute_statement      (BrowserConnection
 GObject            *browser_connection_execution_get_result   (BrowserConnection *bcnc,
 							       guint exec_id,
 							       GdaSet **last_insert_row, GError **error);
+gboolean            browser_connection_normalize_sql_statement(BrowserConnection *bcnc,
+							       GdaSqlStatement *sqlst, GError **error);
 
 /*
  * transactions
@@ -95,6 +100,20 @@ gboolean              browser_connection_begin (BrowserConnection *bcnc, GError
 gboolean              browser_connection_commit (BrowserConnection *bcnc, GError **error);
 gboolean              browser_connection_rollback (BrowserConnection *bcnc, GError **error);
 
+/*
+ * preferences
+ */
+#define BROWSER_CONNECTION_COLUMN_PLUGIN "PLUGIN"
+gboolean             browser_connection_set_table_column_attribute (BrowserConnection *bcnc,
+								    GdaMetaTable *table,
+								    GdaMetaTableColumn *column,
+								    const gchar *attr_name,
+								    const gchar *value, GError **error);
+gchar               *browser_connection_get_table_column_attribute (BrowserConnection *bcnc,
+								    GdaMetaTable *table,
+								    GdaMetaTableColumn *column,
+								    const gchar *attr_name,
+								    GError **error);
 
 G_END_DECLS
 
diff --git a/tools/browser/browser-window.c b/tools/browser/browser-window.c
index 2b1249b..9298984 100644
--- a/tools/browser/browser-window.c
+++ b/tools/browser/browser-window.c
@@ -303,7 +303,7 @@ browser_window_new (BrowserConnection *bcnc, BrowserPerspectiveFactory *factory)
 	str = g_strdup_printf (_("Connection: %s"), cncname);
 	gtk_window_set_title (GTK_WINDOW (bwin), str);
 	g_free (str);
-	gtk_window_set_default_size ((GtkWindow*) bwin, 700, 600);
+	gtk_window_set_default_size ((GtkWindow*) bwin, 900, 650);
 	g_signal_connect (G_OBJECT (bwin), "delete-event",
                           G_CALLBACK (delete_event), bwin);
 	/* icon */
diff --git a/tools/browser/doc/gda-browser-sections.txt b/tools/browser/doc/gda-browser-sections.txt
index 043dba4..1424209 100644
--- a/tools/browser/doc/gda-browser-sections.txt
+++ b/tools/browser/doc/gda-browser-sections.txt
@@ -83,11 +83,15 @@ browser_connection_create_parser
 browser_connection_render_pretty_sql
 browser_connection_execute_statement
 browser_connection_execution_get_result
+browser_connection_normalize_sql_statement
 <SUBSECTION>
 browser_connection_begin
 browser_connection_commit
 browser_connection_rollback
 browser_connection_get_transaction_status
+<SUBSECTION>
+browser_connection_set_table_column_attribute
+browser_connection_get_table_column_attribute
 <SUBSECTION Standard>
 BROWSER_CONNECTION
 BROWSER_IS_CONNECTION
diff --git a/tools/browser/doc/tmpl/browser-connection.sgml b/tools/browser/doc/tmpl/browser-connection.sgml
index 429a386..1c12eea 100644
--- a/tools/browser/doc/tmpl/browser-connection.sgml
+++ b/tools/browser/doc/tmpl/browser-connection.sgml
@@ -39,6 +39,7 @@ An opened connection
 @bfav: 
 @busy: 
 @busy_reason: 
+ store_cnc: 
 
 <!-- ##### STRUCT BrowserConnection ##### -->
 <para>
@@ -70,6 +71,17 @@ An opened connection
 @browserconnection: the object which received the signal.
 @arg1: 
 
+<!-- ##### SIGNAL BrowserConnection::table-column-pref-changed ##### -->
+<para>
+
+</para>
+
+ browserconnection: the object which received the signal.
+ arg1: 
+ arg2: 
+ arg3: 
+ arg4: 
+
 <!-- ##### SIGNAL BrowserConnection::transaction-status-changed ##### -->
 <para>
 
@@ -220,6 +232,17 @@ An opened connection
 @Returns: 
 
 
+<!-- ##### FUNCTION browser_connection_normalize_sql_statement ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ sqlst: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION browser_connection_begin ##### -->
 <para>
 
@@ -259,3 +282,30 @@ An opened connection
 @Returns: 
 
 
+<!-- ##### FUNCTION browser_connection_set_table_column_attribute ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ table: 
+ column: 
+ attr_name: 
+ value: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION browser_connection_get_table_column_attribute ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ table: 
+ column: 
+ attr_name: 
+ error: 
+ Returns: 
+
+
diff --git a/tools/browser/marshal.list b/tools/browser/marshal.list
index 6496113..8dd613e 100644
--- a/tools/browser/marshal.list
+++ b/tools/browser/marshal.list
@@ -23,3 +23,4 @@
 #   BOOL        deprecated alias for BOOLEAN
 
 VOID:BOOLEAN,STRING
+VOID:POINTER,POINTER,STRING,STRING
diff --git a/tools/browser/query-exec/query-result.c b/tools/browser/query-exec/query-result.c
index 36bd887..4c4dc66 100644
--- a/tools/browser/query-exec/query-result.c
+++ b/tools/browser/query-exec/query-result.c
@@ -23,7 +23,9 @@
 #include <glib/gi18n-lib.h>
 #include <string.h>
 #include "query-result.h"
+#include "../browser-window.h"
 #include <libgda-ui/libgda-ui.h>
+#include <libgda/sql-parser/gda-sql-parser.h>
 
 struct _QueryResultPrivate {
 	QueryEditor *history;
@@ -41,7 +43,7 @@ static void query_result_finalize   (GObject *object);
 static GObjectClass *parent_class = NULL;
 
 static GtkWidget *make_widget_for_notice (void);
-static GtkWidget *make_widget_for_data_model (GdaDataModel *model);
+static GtkWidget *make_widget_for_data_model (GdaDataModel *model, QueryResult *qres, const gchar *sql);
 static GtkWidget *make_widget_for_set (GdaSet *set);
 static GtkWidget *make_widget_for_error (GError *error);
 
@@ -162,7 +164,6 @@ query_result_new (QueryEditor *history)
 			  G_CALLBACK (history_cleared_cb), result);
 	result->priv->history = g_object_ref (history);
 
-
 	return GTK_WIDGET (result);
 }
 
@@ -301,7 +302,8 @@ query_result_show_history_item (QueryResult *qres, QueryEditorHistoryItem *hitem
 		if (!child) {
 			if (hitem->result) {
 				if (GDA_IS_DATA_MODEL (hitem->result))
-					child = make_widget_for_data_model (GDA_DATA_MODEL (hitem->result));
+					child = make_widget_for_data_model (GDA_DATA_MODEL (hitem->result),
+									    qres, hitem->sql);
 				else if (GDA_IS_SET (hitem->result))
 					child = make_widget_for_set (GDA_SET (hitem->result));
 				else
@@ -328,7 +330,7 @@ make_widget_for_notice (void)
 }
 
 static GtkWidget *
-make_widget_for_data_model (GdaDataModel *model)
+make_widget_for_data_model (GdaDataModel *model, QueryResult *qres, const gchar *sql)
 {
 	GtkWidget *grid;
 	grid = gdaui_grid_new (model);
@@ -336,6 +338,67 @@ make_widget_for_data_model (GdaDataModel *model)
 	g_object_set (G_OBJECT (grid), "info-flags",
 		      GDAUI_DATA_PROXY_INFO_CHUNCK_CHANGE_BUTTONS | 
 		      GDAUI_DATA_PROXY_INFO_CURRENT_ROW, NULL);
+
+	if (sql) {
+		BrowserConnection *bcnc;
+		bcnc = browser_window_get_connection ((BrowserWindow*) gtk_widget_get_toplevel ((GtkWidget*) qres));
+		if (!bcnc)
+			goto out;
+
+		GdaSqlParser *parser;
+		GdaStatement *stmt;
+		parser = browser_connection_create_parser (bcnc);
+		stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
+		g_object_unref (parser);
+		if (!stmt)
+			goto out;
+
+		GdaSqlStatement *sqlst;
+		g_object_get ((GObject*) stmt, "structure", &sqlst, NULL);
+		g_object_unref (stmt);
+		
+		if ((sqlst->stmt_type != GDA_SQL_STATEMENT_SELECT) ||
+		    !browser_connection_normalize_sql_statement (bcnc, sqlst, NULL)) {
+			gda_sql_statement_free (sqlst);
+			goto out;
+		}
+
+		GdaSet *set;
+		set = (GdaSet*) gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (grid));
+
+		GdaSqlStatementSelect *sel;
+		GSList *list;
+		gint pos;
+		sel = (GdaSqlStatementSelect*) sqlst->contents;
+		for (pos = 0, list = sel->expr_list; list; pos ++, list = list->next) {
+			GdaSqlSelectField *field = (GdaSqlSelectField*) list->data;
+			if (! field->validity_meta_object ||
+			    (field->validity_meta_object->obj_type != GDA_META_DB_TABLE) ||
+			    !field->validity_meta_table_column)
+				continue;
+
+			gchar *plugin;
+			plugin = browser_connection_get_table_column_attribute (bcnc,
+										GDA_META_TABLE (field->validity_meta_object),
+										field->validity_meta_table_column,
+										BROWSER_CONNECTION_COLUMN_PLUGIN, NULL);
+			if (!plugin)
+				continue;
+
+			GdaHolder *holder;
+			holder = gda_set_get_nth_holder (set, pos);
+			if (holder) {
+				GValue *value;
+				value = gda_value_new_from_string (plugin, G_TYPE_STRING);
+				gda_holder_set_attribute_static (holder, GDAUI_ATTRIBUTE_PLUGIN, value);
+				gda_value_free (value);
+			}
+				
+		}
+
+		gda_sql_statement_free (sqlst);
+	}
+ out:
 	return grid;
 }
 
diff --git a/tools/browser/schema-browser/Makefile.am b/tools/browser/schema-browser/Makefile.am
index 08a1ac4..1553c5f 100644
--- a/tools/browser/schema-browser/Makefile.am
+++ b/tools/browser/schema-browser/Makefile.am
@@ -28,6 +28,8 @@ libperspective_la_SOURCES = \
 	table-info.h \
 	table-columns.c \
 	table-columns.h \
+	table-preferences.c \
+	table-preferences.h \
 	mgr-columns.c \
 	mgr-columns.h
 
diff --git a/tools/browser/schema-browser/table-info.c b/tools/browser/schema-browser/table-info.c
index 694d9ec..a53bfe4 100644
--- a/tools/browser/schema-browser/table-info.c
+++ b/tools/browser/schema-browser/table-info.c
@@ -27,6 +27,7 @@
 #include "../support.h"
 #include "../cc-gray-bar.h"
 #include "table-columns.h"
+#include "table-preferences.h"
 #ifdef HAVE_GOOCANVAS
 #include "table-relations.h"
 #endif
@@ -374,6 +375,15 @@ table_info_new (BrowserConnection *bcnc,
 		gtk_notebook_append_page (GTK_NOTEBOOK (sub_nb), page, label);
 	}
 #endif
+	page = table_preferences_new (tinfo);
+	if (page) {
+		label = gtk_label_new ("");
+		str = g_strdup_printf ("<small>%s</small>", _("Preferences"));
+		gtk_label_set_markup (GTK_LABEL (label), str);
+		g_free (str);
+		gtk_widget_show (page);
+		gtk_notebook_append_page (GTK_NOTEBOOK (sub_nb), page, label);
+	}
 	gtk_notebook_set_current_page (GTK_NOTEBOOK (sub_nb), 0);
 
 	/* show everything */
diff --git a/tools/browser/schema-browser/table-preferences.c b/tools/browser/schema-browser/table-preferences.c
new file mode 100644
index 0000000..d4f8634
--- /dev/null
+++ b/tools/browser/schema-browser/table-preferences.c
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <libgda/gda-tree.h>
+#include "table-info.h"
+#include "table-preferences.h"
+#include <libgda-ui/gdaui-tree-store.h>
+#include "../support.h"
+#include "../cc-gray-bar.h"
+#include "schema-browser-perspective.h"
+#include "../query-exec/query-editor.h"
+#include <libgda-ui/gdaui-plugin.h>
+#include <libgda-ui/gdaui-basic-form.h>
+#include <libgda-ui/gdaui-easy.h>
+
+struct _TablePreferencesPrivate {
+	BrowserConnection *bcnc;
+	TableInfo *tinfo;
+	GtkListStore *columns_store;
+	GtkTreeView *columns_treeview;
+
+	GdaMetaTable *current_table;
+	GdaMetaTableColumn *current_column;
+
+	/* field properties */
+	GtkWidget *field_props;
+	GtkTreeModel *plugins_model;
+	gboolean save_plugin_changes;
+	GtkWidget *plugins_combo;
+	GtkWidget *options_vbox;
+	GtkWidget *options_none;
+	GtkWidget *options_wid;
+	GtkWidget *preview_vbox;
+	GtkWidget *preview_none;
+	GtkWidget *preview_wid;
+};
+
+static void table_preferences_class_init (TablePreferencesClass *klass);
+static void table_preferences_init       (TablePreferences *tpreferences, TablePreferencesClass *klass);
+static void table_preferences_dispose   (GObject *object);
+
+static GtkWidget *create_column_properties (TablePreferences *tpref);
+static void       update_column_properties (TablePreferences *tpref);
+static void meta_changed_cb (BrowserConnection *bcnc, GdaMetaStruct *mstruct, TablePreferences *tpreferences);
+static void plugins_combo_changed_cb (GtkComboBox *combo, TablePreferences *tpref);
+
+enum {
+	LAST_SIGNAL
+};
+
+static guint table_preferences_signals[LAST_SIGNAL] = { };
+static GObjectClass *parent_class = NULL;
+extern GHashTable *gdaui_plugins_hash;
+
+/*
+ * TablePreferences class implementation
+ */
+
+static void
+table_preferences_class_init (TablePreferencesClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->dispose = table_preferences_dispose;
+}
+
+
+static void
+table_preferences_init (TablePreferences *tpreferences, TablePreferencesClass *klass)
+{
+	tpreferences->priv = g_new0 (TablePreferencesPrivate, 1);
+}
+
+static void
+table_preferences_dispose (GObject *object)
+{
+	TablePreferences *tpref = (TablePreferences *) object;
+
+	/* free memory */
+	if (tpref->priv) {
+		if (tpref->priv->bcnc) {
+			g_signal_handlers_disconnect_by_func (tpref->priv->bcnc,
+							      G_CALLBACK (meta_changed_cb), tpref);
+			g_object_unref (tpref->priv->bcnc);
+		}
+
+		if (tpref->priv->columns_store)
+			g_object_unref (G_OBJECT (tpref->priv->columns_store));
+
+		if (tpref->priv->plugins_model)
+			g_object_unref (G_OBJECT (tpref->priv->plugins_model));
+
+		g_free (tpref->priv);
+		tpref->priv = NULL;
+	}
+
+	parent_class->dispose (object);
+}
+
+GType
+table_preferences_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo preferences = {
+			sizeof (TablePreferencesClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) table_preferences_class_init,
+			NULL,
+			NULL,
+			sizeof (TablePreferences),
+			0,
+			(GInstanceInitFunc) table_preferences_init
+		};
+		type = g_type_register_static (GTK_TYPE_VBOX, "TablePreferences", &preferences, 0);
+	}
+	return type;
+}
+
+enum
+{
+	COLUMN_POINTER,
+	COLUMN_GTYPE,
+	COLUMN_PLUGIN,
+        NUM_COLUMNS
+};
+
+static void
+meta_changed_cb (BrowserConnection *bcnc, GdaMetaStruct *mstruct, TablePreferences *tpref)
+{
+	gtk_list_store_clear (tpref->priv->columns_store);
+
+	tpref->priv->current_table = NULL;
+	tpref->priv->current_column = NULL;
+
+	if (!mstruct)
+		return;
+
+	GdaMetaDbObject *dbo;
+	GValue *schema_v = NULL, *name_v;
+	const gchar *str;
+	
+	str = table_info_get_table_schema (tpref->priv->tinfo);
+	if (str)
+		g_value_set_string ((schema_v = gda_value_new (G_TYPE_STRING)), str);
+	str = table_info_get_table_name (tpref->priv->tinfo);
+	g_value_set_string ((name_v = gda_value_new (G_TYPE_STRING)), str);
+	dbo = gda_meta_struct_get_db_object (mstruct, NULL, schema_v, name_v);
+	if (schema_v)
+		gda_value_free (schema_v);
+	gda_value_free (name_v);
+
+	if (dbo) {
+		GdaMetaTable *mtable = GDA_META_TABLE (dbo);
+		GSList *list;
+
+		tpref->priv->current_table = mtable;
+		for (list = mtable->columns; list; list = list->next) {
+			GdaMetaTableColumn *column = GDA_META_TABLE_COLUMN (list->data);
+			GtkTreeIter iter;
+			gchar *eprops;
+			GError *error = NULL;
+			eprops = browser_connection_get_table_column_attribute (tpref->priv->bcnc,
+										tpref->priv->current_table,
+										column,
+										BROWSER_CONNECTION_COLUMN_PLUGIN,
+										&error);
+			if (error) {
+				TO_IMPLEMENT; /* FIXME: add a notice somewhere in the UI */
+				g_warning ("Error: %s\n", error->message);
+				g_clear_error (&error);
+			}
+
+			gtk_list_store_append (tpref->priv->columns_store, &iter);
+			gtk_list_store_set (tpref->priv->columns_store, &iter,
+					    COLUMN_POINTER, column,
+					    COLUMN_GTYPE, column->gtype,
+					    COLUMN_PLUGIN, eprops,
+					    -1);
+			g_free (eprops);
+		}
+	}
+}
+
+static void
+table_column_pref_changed_cb (BrowserConnection *bcnc, GdaMetaTable *table,
+			      GdaMetaTableColumn *column,
+			      const gchar *attr_name, const gchar *value, TablePreferences *tpref)
+{
+	GtkTreeIter iter;
+	GdaMetaTableColumn *mcol;
+	gboolean valid;
+	GtkTreeModel *model;
+	
+	if (strcmp (attr_name, BROWSER_CONNECTION_COLUMN_PLUGIN))
+		return;
+
+	model = GTK_TREE_MODEL (tpref->priv->columns_store);
+	for (valid = gtk_tree_model_get_iter_first (model, &iter);
+	     valid;
+	     valid = gtk_tree_model_iter_next (model, &iter)) {
+		gtk_tree_model_get (model, &iter, COLUMN_POINTER, &mcol, -1);
+		if (mcol == column) {
+			gtk_list_store_set (tpref->priv->columns_store, &iter, COLUMN_PLUGIN,
+					    value, -1);
+			return;
+		}
+	}
+}
+
+static void
+cell_name_data_func (GtkTreeViewColumn *tree_column,
+		     GtkCellRenderer *cell,
+		     GtkTreeModel *tree_model,
+		     GtkTreeIter *iter,
+		     gpointer data)
+{
+	gchar *plugin;
+	GdaMetaTableColumn *column;
+        gchar *str;
+        gchar *m1, *m2;
+
+        gtk_tree_model_get (tree_model, iter, COLUMN_POINTER, &column, COLUMN_PLUGIN, &plugin, -1);
+        m1 = g_markup_escape_text (column->column_name, -1);
+        if (plugin) {
+		for (str = plugin; *str && (*str != ':'); str++);
+		*str = 0;
+
+		m2 = g_markup_escape_text (plugin, -1);
+                str = g_strdup_printf ("%s\n<small>%s</small>", m1, m2);
+	}
+        else {
+		m2 = g_markup_escape_text (_("default"), -1);
+                str = g_strdup_printf ("%s\n<small><i>%s</i></small>", m1, m2);
+	}
+
+        g_free (plugin);
+        g_free (m1);
+        g_free (m2);
+
+        g_object_set ((GObject*) cell, "markup", str, NULL);
+        g_free (str);
+}
+
+static void
+selection_changed_cb (GtkTreeSelection *select, TablePreferences *tpref)
+{
+        GtkTreeIter iter;
+	GtkTreeModel *model;
+
+        if (gtk_tree_selection_get_selected (select, &model, &iter)) {
+		GdaMetaTableColumn *column;
+		gtk_tree_model_get (model, &iter, COLUMN_POINTER, &column, -1);
+		tpref->priv->current_column = column;
+        }
+	else
+		tpref->priv->current_column = NULL;
+
+	update_column_properties (tpref);
+}
+
+static void
+columns_model_row_changed_cb (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter,
+			      TablePreferences *tpref)
+{
+	tpref->priv->save_plugin_changes = FALSE;
+	plugins_combo_changed_cb (GTK_COMBO_BOX (tpref->priv->plugins_combo), tpref);
+	tpref->priv->save_plugin_changes = TRUE;
+}
+
+/**
+ * table_preferences_new
+ *
+ * Returns: a new #GtkWidget
+ */
+GtkWidget *
+table_preferences_new (TableInfo *tinfo)
+{
+	TablePreferences *tpref;
+
+	g_return_val_if_fail (IS_TABLE_INFO (tinfo), NULL);
+
+	tpref = TABLE_PREFERENCES (g_object_new (TABLE_PREFERENCES_TYPE, NULL));
+
+	tpref->priv->tinfo = tinfo;
+	tpref->priv->bcnc = g_object_ref (table_info_get_connection (tinfo));
+	g_signal_connect (tpref->priv->bcnc, "meta-changed",
+			  G_CALLBACK (meta_changed_cb), tpref);
+	g_signal_connect (tpref->priv->bcnc, "table-column-pref-changed",
+			  G_CALLBACK (table_column_pref_changed_cb), tpref);
+	
+	/* top vbox */
+	GtkWidget *top_vbox;
+	top_vbox = gtk_vbox_new (FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (tpref), top_vbox, TRUE, TRUE, 0);
+
+	/* Field's display properties */
+	GtkWidget *table;
+
+	table = gtk_table_new (2, 2, FALSE);
+	gtk_box_pack_start (GTK_BOX (top_vbox), table, TRUE, TRUE, 0);
+	gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+	gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+	gtk_container_set_border_width (GTK_CONTAINER (table), 6);
+
+	/* left column */
+	GtkWidget *label;
+	gchar *str;
+	label = gtk_label_new ("");
+	str = g_strdup_printf ("<b>%s:</b>", _("Table's fields"));
+	gtk_label_set_markup (GTK_LABEL (label), str);
+	g_free (str);
+	gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+
+	GtkWidget *sw, *treeview;
+	sw = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+					     GTK_SHADOW_ETCHED_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+					GTK_POLICY_NEVER,
+					GTK_POLICY_AUTOMATIC);
+	gtk_table_attach (GTK_TABLE (table), sw, 0, 1, 1, 2, GTK_FILL, GTK_FILL | GTK_EXPAND, 0, 0);
+
+	tpref->priv->columns_store = gtk_list_store_new (NUM_COLUMNS,
+							 G_TYPE_POINTER, G_TYPE_GTYPE,
+							 G_TYPE_STRING);
+	treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tpref->priv->columns_store));
+	tpref->priv->columns_treeview = GTK_TREE_VIEW (treeview);
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+	gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
+	gtk_container_add (GTK_CONTAINER (sw), treeview);
+
+	/* treeview's columns */
+	GtkTreeViewColumn *col;
+	GtkCellRenderer *cell;
+	cell = gtk_cell_renderer_text_new ();
+	col = gtk_tree_view_column_new ();
+	gtk_tree_view_column_pack_start (col, cell, TRUE);
+	gtk_tree_view_column_set_cell_data_func (col, cell,
+						 (GtkTreeCellDataFunc) cell_name_data_func, NULL, NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), col);
+	
+	/* selection handling */
+	GtkTreeSelection *select;
+	select = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+	gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
+	g_signal_connect (G_OBJECT (select), "changed",
+			  G_CALLBACK (selection_changed_cb), tpref);
+
+
+	/* right column */
+	label = gtk_label_new ("");
+	str = g_strdup_printf ("<b>%s:</b>", _("Field's display preferences"));
+	gtk_label_set_markup (GTK_LABEL (label), str);
+	g_free (str);
+	gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+	gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
+
+	tpref->priv->field_props = create_column_properties (tpref);
+	gtk_table_attach_defaults (GTK_TABLE (table), tpref->priv->field_props, 1, 2, 1, 2);
+
+	/* show all */
+	gtk_widget_show_all (top_vbox);
+
+	/*
+	 * initial update
+	 */
+	GdaMetaStruct *mstruct;
+	mstruct = browser_connection_get_meta_struct (tpref->priv->bcnc);
+	if (mstruct)
+		meta_changed_cb (tpref->priv->bcnc, mstruct, tpref);
+	selection_changed_cb (select, tpref);
+
+	g_signal_connect (tpref->priv->columns_store, "row-changed",
+			  G_CALLBACK (columns_model_row_changed_cb), tpref);
+
+	return (GtkWidget*) tpref;
+}
+
+enum {
+	PL_COLUMN_PLUGIN,
+	PL_COLUMN_DESCR,
+	PL_NUM_COLUMNS
+};
+
+enum {
+	GT_COLUMN_GTYPE,
+	GT_COLUMN_DESCR,
+	GT_NUM_COLUMNS
+};
+
+typedef struct {
+	GType type;
+	GtkListStore *store;
+} ForeachData;
+static void plugin_hash_foreach_func (const gchar *plugin_name, GdauiPlugin *plugin, ForeachData *fdata);
+
+static GtkWidget *
+create_column_properties (TablePreferences *tpref)
+{
+	GtkWidget *combo, *label, *table;
+	GtkCellRenderer *renderer;
+
+	table = gtk_table_new (3, 2, FALSE);
+	gtk_table_set_row_spacings (GTK_TABLE (table), 5);
+	gtk_table_set_col_spacings (GTK_TABLE (table), 5);
+
+	/* plugins combo */
+	tpref->priv->plugins_model = GTK_TREE_MODEL (gtk_list_store_new (PL_NUM_COLUMNS,
+									 G_TYPE_POINTER, G_TYPE_STRING));
+	ForeachData data;
+	data.type = 0;
+	data.store = GTK_LIST_STORE (tpref->priv->plugins_model);
+	g_hash_table_foreach (gdaui_plugins_hash, (GHFunc) plugin_hash_foreach_func, &data);
+
+	combo = gtk_combo_box_new_with_model (tpref->priv->plugins_model);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+	tpref->priv->plugins_combo = combo;
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
+	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
+					"text", PL_COLUMN_DESCR, 
+					NULL);
+	g_signal_connect (G_OBJECT (combo), "changed",
+			  G_CALLBACK (plugins_combo_changed_cb), tpref);
+
+	gtk_table_attach (GTK_TABLE (table), combo, 
+			  1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
+	
+	label = gtk_label_new (_("Data entry type:"));
+	gtk_widget_set_tooltip_text (label, _("Defines how data for the selected column\n"
+					      "will be displayed in forms. Leave 'Default' to have\n"
+					      "the default display"));
+	gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+	
+	/* plugin options */
+	tpref->priv->options_vbox = gtk_vbox_new (FALSE, 0);
+	gtk_table_attach (GTK_TABLE (table), tpref->priv->options_vbox, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
+	tpref->priv->options_none = gtk_label_new (_("none"));
+	gtk_misc_set_alignment (GTK_MISC (tpref->priv->options_none), 0., -1);
+	gtk_box_pack_start (GTK_BOX (tpref->priv->options_vbox), tpref->priv->options_none, FALSE, FALSE, 0);
+
+	label = gtk_label_new (_("Options:"));
+	gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
+
+	/* plugin preview */
+	tpref->priv->preview_vbox = gtk_vbox_new (FALSE, 0);
+	gtk_table_attach (GTK_TABLE (table), tpref->priv->preview_vbox, 1, 2, 2, 3, GTK_FILL, 0, 0, 0);
+	tpref->priv->preview_none = gtk_label_new (_("none"));
+	gtk_misc_set_alignment (GTK_MISC (tpref->priv->preview_none), 0., -1);
+	gtk_box_pack_start (GTK_BOX (tpref->priv->preview_vbox), tpref->priv->preview_none, FALSE, FALSE, 0);
+
+	label = gtk_label_new (_("Preview:"));
+	gtk_widget_set_tooltip_text (label, _("Free form to test the configured\n"
+					      "data entry"));
+	gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
+
+	gtk_widget_show_all (table);
+
+	return table;
+}
+
+static void
+plugin_hash_foreach_func (const gchar *plugin_name, GdauiPlugin *plugin, ForeachData *fdata)
+{
+	gboolean add_it = FALSE;
+	if ((plugin->nb_g_types == 0) || (!plugin->plugin_file && !plugin->options_xml_spec))
+		return;
+
+	if (! fdata->type)
+		add_it = TRUE;
+	else {
+		gint i;
+		for (i = 0; i < plugin->nb_g_types; i++) {
+			if (fdata->type == plugin->valid_g_types[i]) {
+				add_it = TRUE;
+				break;
+			}
+		}
+	}
+
+	if (add_it) {
+		GtkTreeIter iter;
+		gtk_list_store_append (fdata->store, &iter);
+		gtk_list_store_set (fdata->store, &iter,
+				    PL_COLUMN_PLUGIN, plugin,
+				    PL_COLUMN_DESCR, plugin->plugin_descr,
+				    -1);
+	}
+}
+
+static void
+update_column_properties (TablePreferences *tpref)
+{
+	GtkTreeIter iter;
+	GtkListStore *store;
+
+	store = GTK_LIST_STORE (tpref->priv->plugins_model);
+	gtk_list_store_clear (store);
+	gtk_list_store_append (store, &iter);
+	gtk_list_store_set (store, &iter,
+			    PL_COLUMN_PLUGIN, NULL,
+			    PL_COLUMN_DESCR, "Default",
+			    -1);
+
+	if (tpref->priv->current_column) {
+		ForeachData data;
+		data.type = tpref->priv->current_column->gtype;
+		data.store = store;
+		g_hash_table_foreach (gdaui_plugins_hash, (GHFunc) plugin_hash_foreach_func, &data);
+		gtk_widget_set_sensitive (tpref->priv->field_props, TRUE);
+	}
+	else
+		gtk_widget_set_sensitive (tpref->priv->field_props, FALSE);
+
+	if (! tpref->priv->current_table ||
+	    ! tpref->priv->current_column) {
+		gtk_combo_box_set_active (GTK_COMBO_BOX (tpref->priv->plugins_combo), 0);
+		return;
+	}
+
+	/* load existing preference */
+	gchar *eprops;
+	GError *error = NULL;
+	tpref->priv->save_plugin_changes = FALSE;
+	eprops = browser_connection_get_table_column_attribute (tpref->priv->bcnc,
+								tpref->priv->current_table,
+								tpref->priv->current_column,
+								BROWSER_CONNECTION_COLUMN_PLUGIN, &error);
+	if (error) {
+		TO_IMPLEMENT; /* FIXME: add a notice somewhere in the UI */
+		g_warning ("Error: %s\n", error->message);
+		g_clear_error (&error);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (tpref->priv->plugins_combo), 0);
+	}
+	else if (eprops) {
+		gchar *options;
+		for (options = eprops; *options && (*options != ':'); options++);
+		if (*options) {
+			*options = 0;
+			options++;
+		}
+		else
+			options = NULL;
+
+		GtkTreeIter iter;
+		gboolean valid;
+		for (valid = gtk_tree_model_get_iter_first (tpref->priv->plugins_model, &iter);
+		     valid;
+		     valid = gtk_tree_model_iter_next (tpref->priv->plugins_model, &iter)) {
+			GdauiPlugin *plugin;
+			gtk_tree_model_get (tpref->priv->plugins_model, &iter, PL_COLUMN_PLUGIN, &plugin, -1);
+			if (plugin && !strcmp (plugin->plugin_name, eprops)) {
+				gtk_combo_box_set_active_iter (GTK_COMBO_BOX (tpref->priv->plugins_combo), &iter);
+				break;
+			}
+		}
+
+		g_free (eprops);
+	}
+	else
+		gtk_combo_box_set_active (GTK_COMBO_BOX (tpref->priv->plugins_combo), 0);
+	tpref->priv->save_plugin_changes = TRUE;
+}
+
+static void set_preview_widget (TablePreferences *tpref);
+static void options_form_param_changed_cb (GdauiBasicForm *form, GdaHolder *param, gboolean is_user_modif,
+					   TablePreferences *tpref);
+
+static void
+plugins_combo_changed_cb (GtkComboBox *combo, TablePreferences *tpref)
+{
+	GtkTreeIter iter;
+	GtkWidget *old_options = NULL;
+
+	if (tpref->priv->options_wid) {
+		old_options = tpref->priv->options_wid;
+		tpref->priv->options_wid = NULL;
+	}
+	
+	if (gtk_combo_box_get_active_iter (combo, &iter)) {
+		GdauiPlugin *plugin;
+		GtkTreeModel *model;
+		GError *error = NULL;
+
+		model = gtk_combo_box_get_model (combo);
+		gtk_tree_model_get (model, &iter, PL_COLUMN_PLUGIN, &plugin, -1);
+		if (plugin && plugin->options_xml_spec) {
+			GdaSet *plist;
+			
+			plist = gda_set_new_from_spec_string (plugin->options_xml_spec, &error);
+			if (!plist) {
+				g_warning ("Cannot parse XML spec for plugin options: %s",
+					   error && error->message ? error->message : "No detail");
+				g_clear_error (&error);
+			}
+			else {
+				if (!old_options ||
+				    (g_object_get_data (G_OBJECT (old_options), "plugin") != plugin)) {
+					tpref->priv->options_wid = gdaui_basic_form_new (plist);
+					g_object_set_data (G_OBJECT (tpref->priv->options_wid), "plugin", plugin);
+					g_signal_connect (G_OBJECT (tpref->priv->options_wid), "holder-changed",
+							  G_CALLBACK (options_form_param_changed_cb), tpref);
+
+					gtk_box_pack_start (GTK_BOX (tpref->priv->options_vbox),
+							    tpref->priv->options_wid, TRUE, TRUE, 0);
+				}
+				else {
+					tpref->priv->options_wid = old_options;
+					old_options = NULL;
+				}
+				g_object_unref (plist);
+			}
+
+			if (tpref->priv->options_wid) {
+				plist = gdaui_basic_form_get_data_set (GDAUI_BASIC_FORM (tpref->priv->options_wid));
+				gtk_widget_hide (tpref->priv->options_none);
+				gtk_widget_show (tpref->priv->options_wid);
+
+				if (plist && !tpref->priv->save_plugin_changes) {
+					/* load plugin options */
+					GtkTreeSelection *select;
+					GtkTreeIter citer;
+
+					select = gtk_tree_view_get_selection (tpref->priv->columns_treeview);
+					if (gtk_tree_selection_get_selected (select, NULL, &citer)) {
+						gchar *plugin_str;
+
+						gtk_tree_model_get (GTK_TREE_MODEL (tpref->priv->columns_store),
+								    &citer, COLUMN_PLUGIN, &plugin_str, -1);
+						/*g_print ("%p PLUGIN_STR:[%s]\n", tpref, plugin_str);*/
+						if (plugin_str) {
+							GdaQuarkList *ql;
+							GSList *list;
+							gchar *tmp;
+							for (tmp = plugin_str; *tmp && (*tmp != ':'); tmp++);
+							if (*tmp == ':') {
+								ql = gda_quark_list_new_from_string (tmp+1);
+								for (list = plist->holders; list; list = list->next) {
+									GdaHolder *holder = GDA_HOLDER (list->data);
+									const gchar *cstr;
+									cstr = gda_quark_list_find (ql, gda_holder_get_id (holder));
+									if (cstr)
+										gda_holder_set_value_str (holder, NULL, cstr, NULL);
+									else
+										gda_holder_set_value (holder, NULL, NULL);
+								}
+								gda_quark_list_free (ql);
+							}
+							g_free (plugin_str);
+						}
+					}
+				}
+			}
+		}
+
+		if (tpref->priv->save_plugin_changes &&
+		    tpref->priv->current_table &&
+		    tpref->priv->current_column &&
+		    ! browser_connection_set_table_column_attribute (tpref->priv->bcnc,
+								     tpref->priv->current_table,
+								     tpref->priv->current_column,
+								     BROWSER_CONNECTION_COLUMN_PLUGIN,
+								     plugin ? plugin->plugin_name : NULL,
+								     &error)) {
+			TO_IMPLEMENT; /* FIXME: add a notice somewhere in the UI */
+			g_warning ("Error: %s\n", error && error->message ? error->message : _("No detail"));
+			g_clear_error (&error);
+		}
+
+		set_preview_widget (tpref);
+	}
+
+	if (old_options)
+		gtk_widget_destroy (old_options);
+
+	if (! tpref->priv->options_wid)
+		gtk_widget_show (tpref->priv->options_none);
+}
+
+static void
+options_form_param_changed_cb (GdauiBasicForm *form, GdaHolder *param, gboolean is_user_modif,
+			       TablePreferences *tpref)
+{
+	GtkTreeIter iter;
+
+	if (tpref->priv->save_plugin_changes &&
+	    gtk_combo_box_get_active_iter (GTK_COMBO_BOX (tpref->priv->plugins_combo), &iter)) {
+		GdauiPlugin *plugin;
+		GError *error = NULL;
+		GString *plugin_all = NULL;
+
+		gtk_tree_model_get (tpref->priv->plugins_model, &iter, PL_COLUMN_PLUGIN, &plugin, -1);
+		if (plugin) {
+			plugin_all = g_string_new (plugin->plugin_name);
+			if (tpref->priv->options_wid) {
+				GdaSet *plist;
+				GSList *list;
+				gboolean first = TRUE;
+				plist = gdaui_basic_form_get_data_set (GDAUI_BASIC_FORM (tpref->priv->options_wid));
+				for (list = plist->holders; list; list = list->next) {
+					GdaHolder *holder;
+					const GValue *cvalue;
+					gchar *str, *r1, *r2;
+					holder = GDA_HOLDER (list->data);
+					if (! gda_holder_is_valid (holder))
+						continue;
+
+					cvalue = gda_holder_get_value (holder);
+					if (G_VALUE_TYPE (cvalue) == GDA_TYPE_NULL)
+						continue;
+					if (first) {
+						g_string_append_c (plugin_all, ':');
+						first = FALSE;
+					}
+					else
+						g_string_append_c (plugin_all, ';');
+					str = gda_value_stringify (cvalue);
+					r1 = gda_rfc1738_encode (str);
+					g_free (str);
+					r2 = gda_rfc1738_encode (gda_holder_get_id (holder));
+					g_string_append_printf (plugin_all, "%s=%s", r2, r1);
+					g_free (r1);
+					g_free (r2);
+				}
+			}
+		}
+		
+		g_signal_handlers_block_by_func (tpref->priv->columns_store,
+						 G_CALLBACK (columns_model_row_changed_cb), tpref);
+		if (tpref->priv->current_table &&
+		    tpref->priv->current_column &&
+		    ! browser_connection_set_table_column_attribute (tpref->priv->bcnc,
+								     tpref->priv->current_table,
+								     tpref->priv->current_column,
+								     BROWSER_CONNECTION_COLUMN_PLUGIN,
+								     plugin_all ? plugin_all->str : NULL,
+								     &error)) {
+			TO_IMPLEMENT; /* FIXME: add a notice somewhere in the UI */
+			g_warning ("Error: %s\n", error && error->message ? error->message : _("No detail"));
+			g_clear_error (&error);
+		}
+		g_signal_handlers_unblock_by_func (tpref->priv->columns_store,
+						   G_CALLBACK (columns_model_row_changed_cb), tpref);
+
+		if (plugin_all)
+			g_string_free (plugin_all, TRUE);
+	}
+	set_preview_widget (tpref);
+}
+
+static void
+set_preview_widget (TablePreferences *tpref)
+{
+	GtkWidget *preview;
+	GtkTreeIter iter;
+
+	if (!tpref->priv->current_column)
+		return;
+
+	if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (tpref->priv->plugins_combo), &iter)) {
+		GdauiPlugin *plugin;
+		GtkTreeModel *model;
+		GType gtype;
+
+		gtype = tpref->priv->current_column->gtype;
+		
+		model = tpref->priv->plugins_model;
+		gtk_tree_model_get (model, &iter, PL_COLUMN_PLUGIN, &plugin, -1);
+		if (plugin) {
+			GString *string = NULL;
+			if (tpref->priv->options_wid) {
+				GdaSet *plist;
+				GSList *list;
+				
+				plist = gdaui_basic_form_get_data_set (GDAUI_BASIC_FORM (tpref->priv->options_wid));
+				for (list = plist->holders; list; list = list->next) {
+					GdaHolder *holder;
+					holder = GDA_HOLDER (list->data);
+					if (gda_holder_is_valid (holder)) {
+						const GValue *cvalue;
+						cvalue = gda_holder_get_value (holder);
+						if (cvalue && (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL)) {
+							gchar *str = gda_value_stringify (cvalue);
+							gchar *r1, *r2;
+							if (!string)
+								string = g_string_new ("");
+							else
+								g_string_append_c (string, ';');
+							r1 = gda_rfc1738_encode (gda_holder_get_id (holder));
+							r2 = gda_rfc1738_encode (str);
+							g_free (str);
+							g_string_append_printf (string, "%s=%s", r1, r2);
+							g_free (r1);
+							g_free (r2);
+						}
+					}
+				}
+			}
+			if (string) {
+				g_string_prepend_c (string, ':');
+				g_string_prepend (string, plugin->plugin_name);
+				preview = GTK_WIDGET (gdaui_new_data_entry (gtype, string->str));
+				g_string_free (string, TRUE);
+			}
+			else
+				preview = GTK_WIDGET (gdaui_new_data_entry (gtype, plugin->plugin_name));
+		}
+		else
+			preview = GTK_WIDGET (gdaui_new_data_entry (gtype, NULL));
+	}
+
+	GValue *prev_value = NULL;
+	if (tpref->priv->preview_wid) {
+		prev_value = gdaui_data_entry_get_value (GDAUI_DATA_ENTRY (tpref->priv->preview_wid));
+		gtk_widget_destroy (tpref->priv->preview_wid);
+		gtk_widget_show (tpref->priv->preview_none);
+		tpref->priv->preview_wid = NULL;
+	}
+	if (preview) {
+		if (prev_value &&
+		    (G_VALUE_TYPE (prev_value) == gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (preview))))
+			gdaui_data_entry_set_value (GDAUI_DATA_ENTRY (preview), prev_value);
+		gdaui_data_entry_set_attributes (GDAUI_DATA_ENTRY (preview),
+						 0, GDA_VALUE_ATTR_ACTIONS_SHOWN);
+		tpref->priv->preview_wid = preview;
+		gtk_box_pack_start (GTK_BOX (tpref->priv->preview_vbox), preview, TRUE, TRUE, 0);
+		gtk_widget_hide (tpref->priv->preview_none);
+		gtk_widget_show (tpref->priv->preview_wid);
+	}
+	if (prev_value)
+		gda_value_free (prev_value);
+}
diff --git a/tools/browser/schema-browser/table-preferences.h b/tools/browser/schema-browser/table-preferences.h
new file mode 100644
index 0000000..c52c560
--- /dev/null
+++ b/tools/browser/schema-browser/table-preferences.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TABLE_PREFERENCES_H__
+#define __TABLE_PREFERENCES_H__
+
+
+#include "table-info.h"
+
+G_BEGIN_DECLS
+
+#define TABLE_PREFERENCES_TYPE            (table_preferences_get_type())
+#define TABLE_PREFERENCES(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, TABLE_PREFERENCES_TYPE, TablePreferences))
+#define TABLE_PREFERENCES_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, TABLE_PREFERENCES_TYPE, TablePreferencesClass))
+#define IS_TABLE_PREFERENCES(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, TABLE_PREFERENCES_TYPE))
+#define IS_TABLE_PREFERENCES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TABLE_PREFERENCES_TYPE))
+
+typedef struct _TablePreferences        TablePreferences;
+typedef struct _TablePreferencesClass   TablePreferencesClass;
+typedef struct _TablePreferencesPrivate TablePreferencesPrivate;
+
+struct _TablePreferences {
+	GtkVBox               parent;
+	TablePreferencesPrivate *priv;
+};
+
+struct _TablePreferencesClass {
+	GtkVBoxClass          parent_class;
+};
+
+GType                    table_preferences_get_type (void) G_GNUC_CONST;
+
+GtkWidget               *table_preferences_new      (TableInfo *tinfo);
+
+G_END_DECLS
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]