[libgda] Support variables in GdaBrowser's data manager



commit 975e6912a4dc351e1a45ca68d0cb8cd0d2db3b57
Author: Vivien Malerba <malerba gnome-db org>
Date:   Wed Mar 24 21:44:26 2010 +0100

    Support variables in GdaBrowser's data manager

 tools/browser/browser-connection-priv.h        |    3 +-
 tools/browser/browser-connection.c             |  100 +++++++++++++-
 tools/browser/browser-connection.h             |    7 +
 tools/browser/data-manager/data-console.c      |   46 ++++++-
 tools/browser/data-manager/data-source.c       |  113 +++++++++++++--
 tools/browser/data-manager/data-source.h       |    1 +
 tools/browser/data-manager/spec-editor.c       |  174 +++++++++++++++++++-----
 tools/browser/data-manager/spec-editor.h       |    4 +
 tools/browser/doc/gda-browser-sections.txt     |    3 +
 tools/browser/doc/tmpl/browser-connection.sgml |   20 +++-
 tools/browser/query-exec/query-console.c       |   47 +------
 11 files changed, 417 insertions(+), 101 deletions(-)
---
diff --git a/tools/browser/browser-connection-priv.h b/tools/browser/browser-connection-priv.h
index 4371893..0cce524 100644
--- a/tools/browser/browser-connection-priv.h
+++ b/tools/browser/browser-connection-priv.h
@@ -32,7 +32,6 @@ struct _BrowserConnectionPrivate {
 	GdaConnection *cnc;
 	gchar         *dict_file_name;
         GdaSqlParser  *parser;
-        GSList        *variables; /* list of BrowserVariable pointer, owned here */
 
 	GdaDsnInfo     dsn_info;
 	GMutex        *p_mstruct_mutex;
@@ -45,6 +44,8 @@ struct _BrowserConnectionPrivate {
 	gchar    *busy_reason;
 
 	GdaConnection *store_cnc;
+
+	GdaSet        *variables;
 };
 
 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 0afa9cb..bbe5ff3 100644
--- a/tools/browser/browser-connection.c
+++ b/tools/browser/browser-connection.c
@@ -255,6 +255,8 @@ browser_connection_init (BrowserConnection *bcnc)
 	bcnc->priv->bfav = NULL;
 
 	bcnc->priv->store_cnc = NULL;
+
+	bcnc->priv->variables = NULL;
 }
 
 static void
@@ -425,6 +427,9 @@ browser_connection_dispose (GObject *object)
 
 	bcnc = BROWSER_CONNECTION (object);
 	if (bcnc->priv) {
+		if (bcnc->priv->variables)
+			g_object_unref (bcnc->priv->variables);
+
 		if (bcnc->priv->store_cnc)
 			g_object_unref (bcnc->priv->store_cnc);
 
@@ -459,10 +464,6 @@ browser_connection_dispose (GObject *object)
 		}
 		if (bcnc->priv->parser)
 			g_object_unref (bcnc->priv->parser);
-		if (bcnc->priv->variables) {
-			g_slist_foreach (bcnc->priv->variables, (GFunc) g_object_unref, NULL);
-			g_slist_free (bcnc->priv->variables);
-		}
 		if (bcnc->priv->bfav) {
 			g_signal_handlers_disconnect_by_func (bcnc->priv->bfav,
 							      G_CALLBACK (fav_changed_cb), bcnc);
@@ -1399,3 +1400,94 @@ browser_connection_get_table_column_attribute  (BrowserConnection *bcnc,
 
 	return retval;
 }
+
+/**
+ * browser_connection_keep_variables
+ * @bcnc: a #BrowserConnection object
+ * @set: a #GdaSet containing variables for which a copy has to be done
+ *
+ * Makes a copy of the variables in @set and keep them in @bcnc. Retreive them
+ * using browser_connection_load_variables()
+ */
+void
+browser_connection_keep_variables (BrowserConnection *bcnc, GdaSet *set)
+{
+	g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
+	if (!set)
+		return;
+	g_return_if_fail (GDA_IS_SET (set));
+
+	if (! bcnc->priv->variables) {
+		bcnc->priv->variables = gda_set_copy (set);
+		return;
+	}
+
+	GSList *list;
+	for (list = set->holders; list; list = list->next) {
+		GdaHolder *nh, *eh;
+		nh = GDA_HOLDER (list->data);
+		eh = gda_set_get_holder (bcnc->priv->variables, gda_holder_get_id (nh));
+		if (eh) {
+			if (gda_holder_get_g_type (nh) == gda_holder_get_g_type (eh)) {
+				const GValue *cvalue;
+				cvalue = gda_holder_get_value (nh);
+				gda_holder_set_value (eh, cvalue, NULL);
+			}
+			else {
+				gda_set_remove_holder (bcnc->priv->variables, eh);
+				eh = gda_holder_copy (nh);
+				gda_set_add_holder (bcnc->priv->variables, eh);
+				g_object_unref (eh);
+			}
+		}
+		else {
+			eh = gda_holder_copy (nh);
+			gda_set_add_holder (bcnc->priv->variables, eh);
+			g_object_unref (eh);
+		}
+	}
+}
+
+/**
+ * browser_connection_load_variables
+ * @bcnc: a #BrowserConnection object
+ * @set: a #GdaSet which will in the end contain (if any) variables stored in @bcnc
+ *
+ * For each #GdaHolder in @set, set the value if one is available in @bcnc.
+ */
+void
+browser_connection_load_variables (BrowserConnection *bcnc, GdaSet *set)
+{
+	g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
+	if (!set)
+		return;
+	g_return_if_fail (GDA_IS_SET (set));
+
+	if (! bcnc->priv->variables)
+		return;
+
+	GSList *list;
+	for (list = set->holders; list; list = list->next) {
+		GdaHolder *nh, *eh;
+		nh = GDA_HOLDER (list->data);
+		eh = gda_set_get_holder (bcnc->priv->variables, gda_holder_get_id (nh));
+		if (eh) {
+			if (gda_holder_get_g_type (nh) == gda_holder_get_g_type (eh)) {
+				const GValue *cvalue;
+				cvalue = gda_holder_get_value (eh);
+				gda_holder_set_value (nh, cvalue, NULL);
+			}
+			else if (g_value_type_transformable (gda_holder_get_g_type (eh),
+							     gda_holder_get_g_type (nh))) {
+				const GValue *evalue;
+				GValue *nvalue;
+				evalue = gda_holder_get_value (eh);
+				nvalue = gda_value_new (gda_holder_get_g_type (nh));
+				if (g_value_transform (evalue, nvalue))
+					gda_holder_take_value (nh, nvalue, NULL);
+				else
+					gda_value_free (nvalue);
+			}
+		}
+	}	
+}
diff --git a/tools/browser/browser-connection.h b/tools/browser/browser-connection.h
index 3c89947..327239f 100644
--- a/tools/browser/browser-connection.h
+++ b/tools/browser/browser-connection.h
@@ -118,6 +118,13 @@ gchar               *browser_connection_get_table_column_attribute (BrowserConne
 								    const gchar *attr_name,
 								    GError **error);
 
+/*
+ * Variables used at various places and for which a copy of the last recent value
+ * is stored in the BrowserConnection object
+ */
+void                 browser_connection_keep_variables (BrowserConnection *bcnc, GdaSet *set);
+void                 browser_connection_load_variables (BrowserConnection *bcnc, GdaSet *set);
+
 G_END_DECLS
 
 #endif
diff --git a/tools/browser/data-manager/data-console.c b/tools/browser/data-manager/data-console.c
index 79cb246..b8c22a4 100644
--- a/tools/browser/data-manager/data-console.c
+++ b/tools/browser/data-manager/data-console.c
@@ -52,6 +52,7 @@ struct _DataConsolePrivate {
 	GtkWidget *data;
 	GtkActionGroup *agroup;
 
+	gboolean toggling;
 	GtkToggleButton *params_toggle;
 	GtkWidget *params_top;
 	GtkWidget *params_form_box;
@@ -168,6 +169,7 @@ static void editor_clear_clicked_cb (GtkButton *button, DataConsole *dconsole);
 static void variables_clicked_cb (GtkToggleButton *button, DataConsole *dconsole);
 static void execute_clicked_cb (GtkButton *button, DataConsole *dconsole);
 static void spec_editor_toggled_cb (GtkToggleButton *button, DataConsole *dconsole);
+static void spec_editor_changed_cb (SpecEditor *sped, DataConsole *dconsole);
 
 /**
  * data_console_new
@@ -250,6 +252,8 @@ data_console_new (BrowserConnection *bcnc)
 	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
 
 	dconsole->priv->sped = spec_editor_new (dconsole->priv->bcnc);
+	g_signal_connect (dconsole->priv->sped, "changed",
+			  G_CALLBACK (spec_editor_changed_cb), dconsole);
 	gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (dconsole->priv->sped), TRUE, TRUE, 0);
 
 #define DEFAULT_XML \
@@ -276,7 +280,7 @@ data_console_new (BrowserConnection *bcnc)
 "    </query>\n" \
 "</data>"
 
-	spec_editor_set_xml_text (dconsole->priv->sped, DEFAULT_XML);
+	//spec_editor_set_xml_text (dconsole->priv->sped, DEFAULT_XML);
 
 	/* buttons */
 	GtkWidget *bbox, *button;
@@ -363,6 +367,35 @@ spec_editor_toggled_cb (GtkToggleButton *button, DataConsole *dconsole)
 }
 
 static void
+spec_editor_changed_cb (SpecEditor *sped, DataConsole *dconsole)
+{
+	if (dconsole->priv->params_form) {
+		gtk_widget_destroy (dconsole->priv->params_form);
+		dconsole->priv->params_form = NULL;
+	}
+
+	GdaSet *params;
+	gboolean show_variables = FALSE;
+	params = spec_editor_get_params (sped);
+	if (params) {
+		dconsole->priv->params_form = gdaui_basic_form_new (params);
+		g_object_set ((GObject*) dconsole->priv->params_form,
+			      "show-actions", TRUE, NULL);
+		show_variables = TRUE;
+	}
+	else {
+		dconsole->priv->params_form = gtk_label_new ("");
+                gtk_label_set_markup (GTK_LABEL (dconsole->priv->params_form), VARIABLES_HELP);
+	}
+	gtk_container_add (GTK_CONTAINER (dconsole->priv->params_form_box),
+			   dconsole->priv->params_form);
+	gtk_widget_show (dconsole->priv->params_form);
+
+	/* force showing variables */
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dconsole->priv->params_toggle), show_variables);
+}
+
+static void
 editor_clear_clicked_cb (GtkButton *button, DataConsole *dconsole)
 {
 	spec_editor_set_xml_text (dconsole->priv->sped, "");
@@ -405,9 +438,14 @@ compose_mode_toggled_cb (GtkToggleAction *action, DataConsole *dconsole)
 {
 	gint pagenb;
 
+	if (dconsole->priv->toggling) {
+		dconsole->priv->toggling = FALSE;
+		return;
+	}
+
 	pagenb = gtk_notebook_get_current_page (GTK_NOTEBOOK (dconsole->priv->notebook));
 	if (pagenb == PAGE_XML) {
-		/* parse XML and create the data */
+		/* Get Data sources */
 		GArray *sources_array;
 		GError *lerror = NULL;
 		sources_array = spec_editor_get_sources_array (dconsole->priv->sped, &lerror);
@@ -434,6 +472,10 @@ compose_mode_toggled_cb (GtkToggleAction *action, DataConsole *dconsole)
 					    _("Error parsing XML specifications"));
 			g_clear_error (&lerror);
 		}
+		if (pagenb == PAGE_XML) {
+			dconsole->priv->toggling = TRUE;
+			gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+		}
 	}
 	else {
 		/* simply change the current page */
diff --git a/tools/browser/data-manager/data-source.c b/tools/browser/data-manager/data-source.c
index 9c3521b..af6c07b 100644
--- a/tools/browser/data-manager/data-source.c
+++ b/tools/browser/data-manager/data-source.c
@@ -59,9 +59,12 @@ struct _DataSourcePrivate {
 
 	gchar             *select_sql;
 	guint              exec_id;
+	gboolean           executing;
+	gboolean           exec_again;
 
 	GdaStatement      *stmt;
-	GdaSet            *params;
+	GdaSet            *ext_params; /* "free" parameters */
+	GdaSet            *params; /* all the params used when executing @stmt */
 	gboolean           need_rerun; /* set to %TRUE if @params has changed since the last exec */
 
 	GError            *exec_error;
@@ -130,6 +133,9 @@ data_source_init (DataSource *source)
 	source->priv = g_new0 (DataSourcePrivate, 1);
 	source->priv->bcnc = NULL;
 	source->priv->need_rerun = FALSE;
+	source->priv->exec_id = 0;
+	source->priv->executing = FALSE;
+	source->priv->exec_again = FALSE;
 }
 
 static void
@@ -139,6 +145,13 @@ params_changed_cb (GdaSet *params, GdaHolder *holder, DataSource *source)
 }
 
 static void
+ext_params_changed_cb (GdaSet *params, GdaHolder *holder, DataSource *source)
+{
+	source->priv->need_rerun = TRUE;
+	data_source_execute (source, NULL);
+}
+
+static void
 data_source_dispose (GObject *object)
 {
 	DataSource *source;
@@ -158,6 +171,12 @@ data_source_dispose (GObject *object)
 							      G_CALLBACK (params_changed_cb), source);
 			g_object_unref (source->priv->params);
 		}
+		if (source->priv->ext_params) {
+			g_signal_handlers_disconnect_by_func (source->priv->ext_params,
+							      G_CALLBACK (ext_params_changed_cb),
+							      source);
+			g_object_unref (source->priv->ext_params);
+		}
 
 		g_free (source->priv->id);
 		g_free (source->priv->title);
@@ -401,7 +420,7 @@ init_from_table_node (DataSource *source, xmlNodePtr node, GError **error)
 		g_array_append_val (source->priv->export_names, tmp);
 		g_hash_table_insert (source->priv->export_columns, tmp,
 				     GINT_TO_POINTER (i + 1));
-		g_print ("EXPORT [%s]\n", tmp);
+		/*g_print ("EXPORT [%s]\n", tmp);*/
 
 		if (source->priv->id)
 			tmp = g_strdup_printf ("%s %d", source->priv->id, i + 1);
@@ -410,7 +429,7 @@ init_from_table_node (DataSource *source, xmlNodePtr node, GError **error)
 		g_array_append_val (source->priv->export_names, tmp);
 		g_hash_table_insert (source->priv->export_columns, tmp,
 				     GINT_TO_POINTER (i + 1));
-		g_print ("EXPORT [%s]\n", tmp);
+		/*g_print ("EXPORT [%s]\n", tmp);*/
 	}
 	xmlFree (tname);
 
@@ -515,9 +534,12 @@ exec_end_timeout_cb (DataSource *source)
 {
 	GObject *obj;
 
+	g_return_val_if_fail (source->priv->exec_id > 0, FALSE);
+
 	g_clear_error (&source->priv->exec_error);
 	obj = browser_connection_execution_get_result (source->priv->bcnc,
-						       source->priv->exec_id, NULL,
+						       source->priv->exec_id,
+						       NULL,
 						       &source->priv->exec_error);
 	if (obj) {
 		if (GDA_IS_DATA_MODEL (obj)) {
@@ -531,19 +553,29 @@ exec_end_timeout_cb (DataSource *source)
 				gda_data_model_thaw (source->priv->model);
 				gda_data_model_reset (source->priv->model);
 			}
+			/*gda_data_model_dump (source->priv->model, NULL);*/
 		}
 		else {
 			g_object_unref (obj);
 			g_set_error (&source->priv->exec_error, 0, 0,
 				     _("Statement to execute is not a selection statement"));
 		}
+
 		source->priv->exec_id = 0;
 		g_signal_emit (source, data_source_signals [EXEC_FINISHED], 0, source->priv->exec_error);
+		if (source->priv->exec_again) {
+			source->priv->exec_again = FALSE;
+			data_source_execute (source, NULL);
+		}
 		return FALSE;
 	}
 	else if (source->priv->exec_error) {
 		source->priv->exec_id = 0;
 		g_signal_emit (source, data_source_signals [EXEC_FINISHED], 0, source->priv->exec_error);
+		if (source->priv->exec_again) {
+			source->priv->exec_again = FALSE;
+			data_source_execute (source, NULL);
+		}
 		return FALSE;
 	}
 	else
@@ -557,7 +589,7 @@ gboolean
 data_source_execution_going_on (DataSource *source)
 {
 	g_return_val_if_fail (IS_DATA_SOURCE (source), FALSE);
-	return source->priv->exec_id == 0 ? FALSE : TRUE;
+	return source->priv->executing || (source->priv->exec_id > 0);
 }
 
 /**
@@ -573,6 +605,42 @@ data_source_get_import (DataSource *source)
 }
 
 /**
+ * data_source_set_external_import
+ */
+void
+data_source_set_params (DataSource *source, GdaSet *params)
+{
+	gboolean bound = FALSE;
+	g_return_if_fail (IS_DATA_SOURCE (source));
+	g_return_if_fail (!params || GDA_IS_SET (params));
+
+	if (source->priv->ext_params) {
+		g_signal_handlers_disconnect_by_func (source->priv->ext_params,
+						      G_CALLBACK (ext_params_changed_cb), source);
+		g_object_unref (source->priv->ext_params);
+		source->priv->ext_params = NULL;
+	}
+
+	if (source->priv->params) {
+		GSList *list;
+		for (list = source->priv->params->holders; list; list = list->next) {
+			GdaHolder *holder = GDA_HOLDER (list->data);
+			GdaHolder *bind = NULL;
+			if (params)
+				bind = gda_set_get_holder (params, gda_holder_get_id (holder));
+			if (gda_holder_set_bind (holder, bind, NULL))
+				bound = TRUE;
+		}
+	}
+
+	if (params && bound) {
+		source->priv->ext_params = g_object_ref (params);
+		g_signal_connect (params, "holder-changed",
+				  G_CALLBACK (ext_params_changed_cb), source);
+	}
+}
+
+/**
  * data_source_get_export_template
  *
  * Returns: an array of strings, or %NULL
@@ -597,15 +665,24 @@ data_source_get_export_columns (DataSource *source)
 }
 
 /**
- * data_source_start_execution
+ * data_source_execute
  */
 void
 data_source_execute (DataSource *source, GError **error)
 {
 	GError *lerror = NULL;
 	gboolean has_exec = TRUE;
+	guint exec_id = 0;
 	g_return_if_fail (IS_DATA_SOURCE (source));
-	
+
+	if (source->priv->exec_again)
+		return;
+	if (source->priv->executing || (source->priv->exec_id > 0)) {
+		source->priv->exec_again = TRUE;
+		return;
+	}
+
+	source->priv->executing = TRUE;
 	if (! source->priv->stmt) {
 		if (source->priv->init_error)
 			g_propagate_error (error, source->priv->init_error);
@@ -620,29 +697,35 @@ data_source_execute (DataSource *source, GError **error)
 			 * wrong thread */
 			source->priv->need_rerun = FALSE;
 			gda_data_model_freeze (source->priv->model);
-			source->priv->exec_id = browser_connection_rerun_select (source->priv->bcnc,
-										 source->priv->model, &lerror);
+			exec_id = browser_connection_rerun_select (source->priv->bcnc,
+								   source->priv->model, &lerror);
 		}
 		else
 			has_exec = FALSE;
 	}
 	else
-		source->priv->exec_id = browser_connection_execute_statement (source->priv->bcnc,
-									      source->priv->stmt,
-									      source->priv->params,
-									      GDA_STATEMENT_MODEL_RANDOM_ACCESS | GDA_STATEMENT_MODEL_ALLOW_NOPARAM,
-									      FALSE, &lerror);
+		exec_id = browser_connection_execute_statement (source->priv->bcnc,
+								source->priv->stmt,
+								source->priv->params,
+								GDA_STATEMENT_MODEL_RANDOM_ACCESS |
+								GDA_STATEMENT_MODEL_ALLOW_NOPARAM,
+								FALSE, &lerror);
+
 	if (has_exec) {
 		g_signal_emit (source, data_source_signals [EXEC_STARTED], 0);
-		if (! source->priv->exec_id) {
+		if (! exec_id) {
+			gda_data_model_thaw (source->priv->model);
+			gda_data_model_reset (source->priv->model);
 			g_signal_emit (source, data_source_signals [EXEC_FINISHED], 0, lerror);
 			g_propagate_error (error, lerror);
 		}
 		else {
 			/* monitor the end of execution */
+			source->priv->exec_id = exec_id;
 			g_timeout_add (50, (GSourceFunc) exec_end_timeout_cb, source);
 		}
 	}
+	source->priv->executing = FALSE;
 }
 
 /*
diff --git a/tools/browser/data-manager/data-source.h b/tools/browser/data-manager/data-source.h
index 391eca6..720c719 100644
--- a/tools/browser/data-manager/data-source.h
+++ b/tools/browser/data-manager/data-source.h
@@ -56,6 +56,7 @@ struct _DataSourceClass
 GType               data_source_get_type            (void) G_GNUC_CONST;
 
 DataSource         *data_source_new_from_xml_node   (BrowserConnection *bcnc, xmlNodePtr node, GError **error);
+void                data_source_set_params          (DataSource *source, GdaSet *params);
 xmlNodePtr          data_source_to_xml_node         (DataSource *source);
 
 GdaSet             *data_source_get_import          (DataSource *source);
diff --git a/tools/browser/data-manager/spec-editor.c b/tools/browser/data-manager/spec-editor.c
index dabc74b..9d7972c 100644
--- a/tools/browser/data-manager/spec-editor.c
+++ b/tools/browser/data-manager/spec-editor.c
@@ -26,6 +26,7 @@
 #include "data-source.h"
 #include <libgda/libgda.h>
 #include "../support.h"
+#include "marshal.h"
 
 #ifdef HAVE_GTKSOURCEVIEW
   #ifdef GTK_DISABLE_SINGLE_INCLUDES
@@ -45,13 +46,14 @@ struct _SpecEditorPrivate {
 	SpecEditorMode mode;
 	GtkNotebook *notebook;
 
-	guint params_compute_id; /* timout ID to compute params */
+        GdaSet *params; /* execution params */
 
 	/* reference for all views */
 	xmlDocPtr doc;
 
 	/* XML view */
 	gboolean xml_view_up_to_date;
+	guint signal_editor_changed_id; /* timout ID to signal editor changed */
 	GtkWidget *text;
 	GtkTextBuffer *buffer;
 
@@ -63,6 +65,12 @@ static void spec_editor_class_init (SpecEditorClass *klass);
 static void spec_editor_init       (SpecEditor *sped, SpecEditorClass *klass);
 static void spec_editor_dispose    (GObject *object);
 
+enum {
+	CHANGED,
+        LAST_SIGNAL
+};
+
+static guint spec_editor_signals[LAST_SIGNAL] = { 0 };
 static GObjectClass *parent_class = NULL;
 
 /*
@@ -75,6 +83,15 @@ spec_editor_class_init (SpecEditorClass *klass)
 
 	parent_class = g_type_class_peek_parent (klass);
 
+	/* signals */
+        spec_editor_signals [CHANGED] =
+                g_signal_new ("changed",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (SpecEditorClass, changed),
+                              NULL, NULL,
+                              _dm_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
 	object_class->dispose = spec_editor_dispose;
 }
 
@@ -86,7 +103,7 @@ spec_editor_init (SpecEditor *sped, SpecEditorClass *klass)
 
 	/* allocate private structure */
 	sped->priv = g_new0 (SpecEditorPrivate, 1);
-	sped->priv->params_compute_id = 0;
+	sped->priv->signal_editor_changed_id = 0;
 	sped->priv->mode = SPEC_EDITOR_XML;
 }
 
@@ -117,9 +134,10 @@ spec_editor_dispose (GObject *object)
 {
 	SpecEditor *sped = (SpecEditor*) object;
 	if (sped->priv) {
-		if (sped->priv->params_compute_id)
-			g_source_remove (sped->priv->params_compute_id);
-
+		if (sped->priv->signal_editor_changed_id)
+			g_source_remove (sped->priv->signal_editor_changed_id);
+		if (sped->priv->params)
+			g_object_unref (sped->priv->params);
 		if (sped->priv->bcnc)
 			g_object_unref (sped->priv->bcnc);
 
@@ -132,12 +150,13 @@ spec_editor_dispose (GObject *object)
 }
 
 static gboolean
-compute_params (SpecEditor *sped)
+signal_editor_changed (SpecEditor *sped)
 {
-	TO_IMPLEMENT;
-	
+	/* send signal */
+	g_signal_emit (sped, spec_editor_signals[CHANGED], 0);
+
 	/* remove timeout */
-	sped->priv->params_compute_id = 0;
+	sped->priv->signal_editor_changed_id = 0;
 	return FALSE;
 }
 
@@ -145,9 +164,9 @@ compute_params (SpecEditor *sped)
 static void
 editor_changed_cb (GtkTextBuffer *buffer, SpecEditor *sped)
 {
-	if (sped->priv->params_compute_id)
-		g_source_remove (sped->priv->params_compute_id);
-	sped->priv->params_compute_id = g_timeout_add_seconds (1, (GSourceFunc) compute_params, sped);
+	if (sped->priv->signal_editor_changed_id)
+		g_source_remove (sped->priv->signal_editor_changed_id);
+	sped->priv->signal_editor_changed_id = g_timeout_add_seconds (1, (GSourceFunc) signal_editor_changed, sped);
 }
 
 /**
@@ -216,8 +235,12 @@ spec_editor_set_xml_text (SpecEditor *sped, const gchar *xml)
 	g_return_if_fail (IS_SPEC_EDITOR (sped));
 
 	gtk_text_buffer_set_text (sped->priv->buffer, xml, -1);
+	signal_editor_changed (sped);
 }
 
+/**
+ * spec_editor_get_xml_text
+ */
 gchar *
 spec_editor_get_xml_text (SpecEditor *sped)
 {
@@ -260,7 +283,78 @@ spec_editor_get_mode (SpecEditor *sped)
 }
 
 static GArray *compute_sources (SpecEditor *sped, GError **error);
+static GSList *compute_sources_list (SpecEditor *sped, GError **error);
+
+static void
+compute_params (SpecEditor *sped)
+{
+	/* cleanning process */
+	if (sped->priv->params) {
+		browser_connection_keep_variables (sped->priv->bcnc, sped->priv->params);
+		g_object_unref (sped->priv->params);
+        }
+        sped->priv->params = NULL;
+	
+	/* compute new params */
+	GSList *sources_list;
+	sources_list = compute_sources_list (sped, NULL);
+	if (sources_list) {
+		GSList *list;
+		for (list = sources_list; list; list = list->next) {
+			DataSource *source;
+			GdaSet *set;
+			
+			source = DATA_SOURCE (list->data);
+			set = data_source_get_import (source);
+			if (!set)
+				continue;
+
+			GSList *holders;
+			gboolean found;
+			for (found = FALSE, holders = set->holders; holders; holders = holders->next) {
+				GSList *list2;
+				for (list2 = sources_list; list2; list2 = list2->next) {
+					if (list2 == list)
+						continue;
+					GHashTable *export_h;
+					export_h = data_source_get_export_columns (DATA_SOURCE (list2->data));
+					if (g_hash_table_lookup (export_h, 
+					      gda_holder_get_id (GDA_HOLDER (holders->data)))) {
+						found = TRUE;
+						break;
+					}
+				}
+			}
+			if (! found) {
+				if (! sped->priv->params)
+					sped->priv->params = gda_set_copy (set);
+				else
+					gda_set_merge_with_set (sped->priv->params, set);
+			}
+		}
+
+		/* cleanups */
+		g_slist_foreach (sources_list, (GFunc) g_object_unref, NULL);
+		g_slist_free (sources_list);
+		sources_list = NULL;
+	}
+
+	browser_connection_load_variables (sped->priv->bcnc, sped->priv->params);
+}
+
+/**
+ * spec_editor_get_params
+ *
+ * Returns: a pointer to an internal #GdaSet, must not be modified
+ */
+GdaSet *
+spec_editor_get_params (SpecEditor *sped)
+{
+	g_return_val_if_fail (IS_SPEC_EDITOR (sped), NULL);
 
+	compute_params (sped);
+	return sped->priv->params;
+}
 
 /**
  * spec_editor_get_sources_array
@@ -269,10 +363,10 @@ GArray *
 spec_editor_get_sources_array (SpecEditor *sped, GError **error)
 {
 	g_return_val_if_fail (IS_SPEC_EDITOR (sped), NULL);
-	if (sped->priv->params_compute_id > 0) {
-		g_source_remove (sped->priv->params_compute_id);
-		sped->priv->params_compute_id = 0;
-		//compute_params (tconsole);
+	if (sped->priv->signal_editor_changed_id > 0) {
+		g_source_remove (sped->priv->signal_editor_changed_id);
+		sped->priv->signal_editor_changed_id = 0;
+		compute_params (sped);
 	}
 	return compute_sources (sped, error);
 }
@@ -408,12 +502,11 @@ create_sources_array (GSList *sources_list, GError **error)
 	return array;
 }
 
-static GArray *
-compute_sources (SpecEditor *sped, GError **error)
+static GSList *
+compute_sources_list (SpecEditor *sped, GError **error)
 {
 	gchar *xml;
 	xmlDocPtr doc = NULL;
-	GError *lerror = NULL;
 	GSList *sources_list = NULL;
 
 	/* create sources_list from XML */
@@ -427,7 +520,7 @@ compute_sources (SpecEditor *sped, GError **error)
 	}
 
 	if (!doc) {
-		g_set_error (&lerror, 0, 0,
+		g_set_error (error, 0, 0,
 			     _("Error parsing XML specifications"));
 		goto onerror;
 	}
@@ -444,42 +537,51 @@ compute_sources (SpecEditor *sped, GError **error)
 		if (!strcmp ((gchar*) node->name, "table") ||
 		    !strcmp ((gchar*) node->name, "query")) {
 			DataSource *source;
-			source = data_source_new_from_xml_node (sped->priv->bcnc, node, &lerror);
+			source = data_source_new_from_xml_node (sped->priv->bcnc, node, error);
 			if (!source)
 				goto onerror;
-			else
-				sources_list = g_slist_prepend (sources_list, source);
+			
+			sources_list = g_slist_prepend (sources_list, source);
+			data_source_set_params (source, sped->priv->params);
 		}
 	}
 	xmlFreeDoc (doc);
 	doc = NULL;
-	sources_list = g_slist_reverse (sources_list);
+	return g_slist_reverse (sources_list);
 
-	/* reorder sources_list */
-	GArray *sources_array;
-	sources_array = create_sources_array (sources_list, &lerror);
+ onerror:
+	if (doc)
+		xmlFreeDoc (doc);
 	if (sources_list) {
 		g_slist_foreach (sources_list, (GFunc) g_object_unref, NULL);
 		g_slist_free (sources_list);
-		sources_list = NULL;
 	}
-	if (! sources_array)
-		goto onerror;
+	
+	return NULL;
+}
 
-	return sources_array;
+static GArray *
+compute_sources (SpecEditor *sped, GError **error)
+{
+	GArray *sources_array = NULL;
+	GSList *sources_list;
+	GError *lerror = NULL;
+
+	sources_list = compute_sources_list (sped, &lerror);
+	if (!lerror)
+		sources_array = create_sources_array (sources_list, &lerror);
 
- onerror:
-	if (doc)
-		xmlFreeDoc (doc);
 	if (sources_list) {
 		g_slist_foreach (sources_list, (GFunc) g_object_unref, NULL);
 		g_slist_free (sources_list);
+		sources_list = NULL;
 	}
+
 	if (lerror) {
 		browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) sped),
 				    lerror && lerror->message ? lerror->message :_("Error parsing XML specifications"));
 		g_clear_error (&lerror);
 	}
-	
-	return NULL;
+
+	return sources_array;
 }
diff --git a/tools/browser/data-manager/spec-editor.h b/tools/browser/data-manager/spec-editor.h
index 624975b..40485e9 100644
--- a/tools/browser/data-manager/spec-editor.h
+++ b/tools/browser/data-manager/spec-editor.h
@@ -46,6 +46,9 @@ struct _SpecEditor {
 
 struct _SpecEditorClass {
 	GtkVBoxClass parent_class;
+
+	/* signals */
+	void        (*changed) (SpecEditor *editor);
 };
 
 typedef enum {
@@ -62,6 +65,7 @@ gchar      *spec_editor_get_xml_text (SpecEditor *sped);
 void        spec_editor_set_mode     (SpecEditor *sped, SpecEditorMode mode);
 SpecEditorMode spec_editor_get_mode  (SpecEditor *sped);
 
+GdaSet     *spec_editor_get_params   (SpecEditor *sped);
 GArray     *spec_editor_get_sources_array (SpecEditor *sped, GError **error);
 void        spec_editor_destroy_sources_array (GArray *array);
 
diff --git a/tools/browser/doc/gda-browser-sections.txt b/tools/browser/doc/gda-browser-sections.txt
index 1424209..4cb6751 100644
--- a/tools/browser/doc/gda-browser-sections.txt
+++ b/tools/browser/doc/gda-browser-sections.txt
@@ -92,6 +92,9 @@ browser_connection_get_transaction_status
 <SUBSECTION>
 browser_connection_set_table_column_attribute
 browser_connection_get_table_column_attribute
+<SUBSECTION>
+browser_connection_keep_variables
+browser_connection_load_variables
 <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 1c12eea..781266a 100644
--- a/tools/browser/doc/tmpl/browser-connection.sgml
+++ b/tools/browser/doc/tmpl/browser-connection.sgml
@@ -31,7 +31,6 @@ An opened connection
 @cnc: 
 @dict_file_name: 
 @parser: 
- variables: 
 @dsn_info: 
 @p_mstruct_mutex: 
 @p_mstruct: 
@@ -40,6 +39,7 @@ An opened connection
 @busy: 
 @busy_reason: 
 @store_cnc: 
+ variables: 
 
 <!-- ##### STRUCT BrowserConnection ##### -->
 <para>
@@ -309,3 +309,21 @@ An opened connection
 @Returns: 
 
 
+<!-- ##### FUNCTION browser_connection_keep_variables ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ set: 
+
+
+<!-- ##### FUNCTION browser_connection_load_variables ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ set: 
+
+
diff --git a/tools/browser/query-exec/query-console.c b/tools/browser/query-exec/query-console.c
index 91e774e..7ad14c7 100644
--- a/tools/browser/query-exec/query-console.c
+++ b/tools/browser/query-exec/query-console.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The GNOME Foundation
+ * Copyright (C) 2009 - 2010 The GNOME Foundation
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -106,7 +106,6 @@ struct _QueryConsolePrivate {
 	GtkWidget   *exec_button;
 	GtkWidget   *indent_button;
 	guint params_compute_id; /* timout ID to compute params */
-	GdaSet *past_params; /* keeps values given to old params */
 	GdaSet *params; /* execution params */
 	GtkWidget *params_popup; /* popup shown when invalid params are required */
 
@@ -186,7 +185,6 @@ query_console_init (QueryConsole *tconsole, QueryConsoleClass *klass)
 	tconsole->priv = g_new0 (QueryConsolePrivate, 1);
 	tconsole->priv->parser = NULL;
 	tconsole->priv->params_compute_id = 0;
-	tconsole->priv->past_params = NULL;
 	tconsole->priv->params = NULL;
 	tconsole->priv->params_popup = NULL;
 	tconsole->priv->agroup = NULL;
@@ -211,8 +209,6 @@ query_console_dispose (GObject *object)
 		}
 		if (tconsole->priv->parser)
 			g_object_unref (tconsole->priv->parser);
-		if (tconsole->priv->past_params)
-			g_object_unref (tconsole->priv->past_params);
 		if (tconsole->priv->params)
 			g_object_unref (tconsole->priv->params);
 		if (tconsole->priv->params_compute_id)
@@ -544,16 +540,11 @@ compute_params (QueryConsole *tconsole)
 	GdaBatch *batch;
 
 	if (tconsole->priv->params) {
-		if (tconsole->priv->past_params) {
-			gda_set_merge_with_set (tconsole->priv->params, tconsole->priv->past_params);
-			g_object_unref (tconsole->priv->past_params);
-			tconsole->priv->past_params = tconsole->priv->params;
-		}
-		else
-			tconsole->priv->past_params = tconsole->priv->params;
+		browser_connection_keep_variables (tconsole->priv->bcnc, tconsole->priv->params);
+		g_object_unref (tconsole->priv->params);
 	}
-
 	tconsole->priv->params = NULL;
+
 	if (tconsole->priv->params_form) {
 		gtk_widget_destroy (tconsole->priv->params_form);
 		tconsole->priv->params_form = NULL;		
@@ -590,35 +581,7 @@ compute_params (QueryConsole *tconsole)
 		gtk_widget_show (tconsole->priv->params_form);
 		g_object_unref (batch);
 
-		if (tconsole->priv->past_params && tconsole->priv->params) {
-			/* copy the values from tconsole->priv->past_params to tconsole->priv->params */
-			GSList *list;
-			for (list = tconsole->priv->params->holders; list; list = list->next) {
-				GdaHolder *oldh, *newh;
-				newh = GDA_HOLDER (list->data);
-				oldh = gda_set_get_holder (tconsole->priv->past_params, gda_holder_get_id  (newh));
-				if (oldh) {
-					GType otype, ntype;
-					otype = gda_holder_get_g_type (oldh);
-					ntype = gda_holder_get_g_type (newh);
-					if (otype == ntype) {
-						const GValue *ovalue;
-						ovalue = gda_holder_get_value (oldh);
-						gda_holder_set_value (newh, ovalue, NULL);
-					}
-					else if (g_value_type_transformable (otype, ntype)) {
-						const GValue *ovalue;
-						GValue *nvalue;
-						ovalue = gda_holder_get_value (oldh);
-						nvalue = gda_value_new (ntype);
-						if (g_value_transform (ovalue, nvalue))
-							gda_holder_take_value (newh, nvalue, NULL);
-						else
-							gda_value_free  (nvalue);
-					}
-				}
-			}
-		}
+		browser_connection_load_variables (tconsole->priv->bcnc, tconsole->priv->params);
 		if (tconsole->priv->params && show_variables &&
 		    gda_set_is_valid (tconsole->priv->params, NULL))
 			show_variables = FALSE;



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