[libgda] GdaBrowser: initial support for virtual connections
- From: Vivien Malerba <vivien src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [libgda] GdaBrowser: initial support for virtual connections
- Date: Mon, 19 Oct 2009 18:42:34 +0000 (UTC)
commit f62fe219749f5401a02616f8e5f684aba25ab56c
Author: Vivien Malerba <malerba gnome-db org>
Date: Sat Oct 17 12:18:11 2009 +0200
GdaBrowser: initial support for virtual connections
tools/browser/Makefile.am | 4 +
tools/browser/browser-connection-priv.h | 45 +++
tools/browser/browser-connection.c | 396 ++++++++------------
tools/browser/browser-connection.h | 4 +-
tools/browser/browser-connections-list.c | 42 +--
tools/browser/browser-virtual-connection.c | 506 +++++++++++++++++++++++++
tools/browser/browser-virtual-connection.h | 94 +++++
tools/browser/browser-window.c | 40 ++
tools/browser/connection-binding-properties.c | 394 +++++++++++++++++++
tools/browser/connection-binding-properties.h | 61 +++
tools/browser/support.c | 70 ++++
tools/browser/support.h | 11 +
12 files changed, 1393 insertions(+), 274 deletions(-)
---
diff --git a/tools/browser/Makefile.am b/tools/browser/Makefile.am
index 4814fe3..1010f13 100644
--- a/tools/browser/Makefile.am
+++ b/tools/browser/Makefile.am
@@ -54,10 +54,14 @@ libbrowser_la_SOURCES=\
browser-favorites.h \
browser-variable.c \
browser-variable.h \
+ browser-virtual-connection.c \
+ browser-virtual-connection.h \
browser-window.c \
browser-window.h \
browser-connections-list.c \
browser-connections-list.h \
+ connection-binding-properties.c \
+ connection-binding-properties.h \
mgr-favorites.h \
mgr-favorites.c \
browser-stock-icons.c \
diff --git a/tools/browser/browser-connection-priv.h b/tools/browser/browser-connection-priv.h
new file mode 100644
index 0000000..27c5c38
--- /dev/null
+++ b/tools/browser/browser-connection-priv.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 Vivien Malerba
+ *
+ * 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 __BROWSER_CONNECTION_PRIVATE_H__
+#define __BROWSER_CONNECTION_PRIVATE_H__
+
+#include <libgda/thread-wrapper/gda-thread-wrapper.h>
+
+struct _BrowserConnectionPrivate {
+ GdaThreadWrapper *wrapper;
+ GSList *wrapper_jobs;
+ guint wrapper_results_timer;
+ GHashTable *executed_statements; /* key = guint exec ID, value = a StatementResult pointer */
+
+ gchar *name;
+ GdaConnection *cnc;
+ gchar *dict_file_name;
+ GdaSqlParser *parser;
+ GSList *variables; /* list of BrowserVariable pointer, owned here */
+
+ GdaDsnInfo dsn_info;
+ GMutex *p_mstruct_mutex;
+ GdaMetaStruct *p_mstruct; /* private GdaMetaStruct: while it is being created */
+ GdaMetaStruct *mstruct; /* public GdaMetaStruct: once it has been created and is no more modified */
+
+ BrowserFavorites *bfav;
+};
+
+#endif
diff --git a/tools/browser/browser-connection.c b/tools/browser/browser-connection.c
index 8219042..ae1ae9b 100644
--- a/tools/browser/browser-connection.c
+++ b/tools/browser/browser-connection.c
@@ -25,7 +25,8 @@
#include "marshal.h"
#include <sql-parser/gda-sql-parser.h>
#include <libgda/gda-sql-builder.h>
-#include <virtual/libgda-virtual.h>
+
+#include "browser-connection-priv.h"
/* code inclusion */
#include "../dict-file-name.c"
@@ -47,26 +48,6 @@ statement_result_free (StatementResult *res)
g_free (res);
}
-struct _BrowserConnectionPrivate {
- GdaThreadWrapper *wrapper;
- GSList *wrapper_jobs;
- guint wrapper_results_timer;
- GHashTable *executed_statements; /* key = guint exec ID, value = a StatementResult pointer */
-
- gchar *name;
- GdaConnection *cnc;
- gchar *dict_file_name;
- GdaSqlParser *parser;
- GSList *variables; /* list of BrowserVariable pointer, owned here */
-
- GdaDsnInfo dsn_info;
- GMutex *p_mstruct_mutex;
- GdaMetaStruct *p_mstruct; /* private GdaMetaStruct: while it is being created */
- GdaMetaStruct *mstruct; /* public GdaMetaStruct: once it has been created and is no more modified */
-
- BrowserFavorites *bfav;
-};
-
/* signals */
enum {
BUSY,
@@ -140,10 +121,23 @@ pop_wrapper_job (BrowserConnection *bcnc, WrapperJob *wj)
static void browser_connection_class_init (BrowserConnectionClass *klass);
static void browser_connection_init (BrowserConnection *bcnc);
static void browser_connection_dispose (GObject *object);
-
+static void browser_connection_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void browser_connection_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
/* get a pointer to the parents to be able to call their destructor */
static GObjectClass *parent_class = NULL;
+/* properties */
+enum {
+ PROP_0,
+ PROP_GDA_CNC
+};
+
GType
browser_connection_get_type (void)
{
@@ -216,6 +210,17 @@ browser_connection_class_init (BrowserConnectionClass *klass)
klass->favorites_changed = NULL;
klass->transaction_status_changed = NULL;
+ klass->is_busy = NULL;
+
+ /* Properties */
+ object_class->set_property = browser_connection_set_property;
+ object_class->get_property = browser_connection_get_property;
+ g_object_class_install_property (object_class, PROP_GDA_CNC,
+ g_param_spec_object ("gda-connection", NULL, "Connection to use",
+ GDA_TYPE_CONNECTION,
+ G_PARAM_READABLE | G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+
object_class->dispose = browser_connection_dispose;
}
@@ -242,6 +247,139 @@ browser_connection_init (BrowserConnection *bcnc)
}
static void
+transaction_status_changed_cb (GdaConnection *cnc, BrowserConnection *bcnc)
+{
+ g_signal_emit (bcnc, browser_connection_signals [TRANSACTION_STATUS_CHANGED], 0);
+}
+
+/* executed in sub @bcnc->priv->wrapper's thread */
+static gpointer
+wrapper_meta_store_update (BrowserConnection *bcnc, GError **error)
+{
+ gboolean retval;
+ GdaMetaContext context = {"_tables", 0, NULL, NULL};
+ retval = gda_connection_update_meta_store (bcnc->priv->cnc, &context, error);
+
+ return GINT_TO_POINTER (retval ? 2 : 1);
+}
+
+/* executed in sub @bcnc->priv->wrapper's thread */
+static gpointer
+wrapper_meta_struct_sync (BrowserConnection *bcnc, GError **error)
+{
+ gboolean retval;
+
+ g_mutex_lock (bcnc->priv->p_mstruct_mutex);
+ g_assert (bcnc->priv->p_mstruct);
+ g_object_ref (G_OBJECT (bcnc->priv->p_mstruct));
+ retval = gda_meta_struct_complement_all (bcnc->priv->p_mstruct, error);
+ g_object_unref (G_OBJECT (bcnc->priv->p_mstruct));
+ g_mutex_unlock (bcnc->priv->p_mstruct_mutex);
+
+ return GINT_TO_POINTER (retval ? 2 : 1);
+}
+
+static void
+browser_connection_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ BrowserConnection *bcnc;
+
+ bcnc = BROWSER_CONNECTION (object);
+ if (bcnc->priv) {
+ switch (param_id) {
+ case PROP_GDA_CNC:
+ bcnc->priv->cnc = (GdaConnection*) g_value_get_object (value);
+ if (!bcnc->priv->cnc)
+ return;
+
+ g_object_ref (bcnc->priv->cnc);
+ g_signal_connect (bcnc->priv->cnc, "transaction-status-changed",
+ G_CALLBACK (transaction_status_changed_cb), bcnc);
+
+ /* meta store */
+ gchar *dict_file_name = NULL;
+ gboolean update_store = FALSE;
+ GdaMetaStore *store;
+ gchar *cnc_string, *cnc_info;
+
+ g_object_get (G_OBJECT (bcnc->priv->cnc),
+ "dsn", &cnc_info,
+ "cnc-string", &cnc_string, NULL);
+ dict_file_name = compute_dict_file_name (cnc_info ? gda_config_get_dsn_info (cnc_info) : NULL,
+ cnc_string);
+ g_free (cnc_string);
+ if (dict_file_name) {
+ if (! g_file_test (dict_file_name, G_FILE_TEST_EXISTS))
+ update_store = TRUE;
+ store = gda_meta_store_new_with_file (dict_file_name);
+ }
+ else {
+ store = gda_meta_store_new (NULL);
+ if (store)
+ update_store = TRUE;
+ }
+ bcnc->priv->dict_file_name = dict_file_name;
+ g_object_set (G_OBJECT (bcnc->priv->cnc), "meta-store", store, NULL);
+ if (update_store) {
+ GError *lerror = NULL;
+ guint job_id;
+ job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
+ (GdaThreadWrapperFunc) wrapper_meta_store_update,
+ g_object_ref (bcnc), g_object_unref, &lerror);
+ if (job_id > 0)
+ push_wrapper_job (bcnc, job_id, JOB_TYPE_META_STORE_UPDATE,
+ _("Getting database schema information"));
+ else if (lerror) {
+ browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
+ lerror->message ? lerror->message : _("No detail"));
+ g_error_free (lerror);
+ }
+ }
+ else {
+ guint job_id;
+ GError *lerror = NULL;
+
+ bcnc->priv->p_mstruct = gda_meta_struct_new (store, GDA_META_STRUCT_FEATURE_ALL);
+ job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
+ (GdaThreadWrapperFunc) wrapper_meta_struct_sync,
+ g_object_ref (bcnc), g_object_unref, &lerror);
+ if (job_id > 0)
+ push_wrapper_job (bcnc, job_id, JOB_TYPE_META_STRUCT_SYNC,
+ _("Analysing database schema"));
+ else if (lerror) {
+ browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
+ lerror->message ? lerror->message : _("No detail"));
+ g_error_free (lerror);
+ }
+ g_object_unref (store);
+ }
+ break;
+ }
+ }
+}
+
+static void
+browser_connection_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ BrowserConnection *bcnc;
+
+ bcnc = BROWSER_CONNECTION (object);
+ if (bcnc->priv) {
+ switch (param_id) {
+ case PROP_GDA_CNC:
+ g_value_set_object (value, bcnc->priv->cnc);
+ break;
+ }
+ }
+}
+
+static void
clear_dsn_info (BrowserConnection *bcnc)
{
g_free (bcnc->priv->dsn_info.name);
@@ -267,12 +405,6 @@ fav_changed_cb (BrowserFavorites *bfav, BrowserConnection *bcnc)
}
static void
-transaction_status_changed_cb (GdaConnection *cnc, BrowserConnection *bcnc)
-{
- g_signal_emit (bcnc, browser_connection_signals [TRANSACTION_STATUS_CHANGED], 0);
-}
-
-static void
browser_connection_dispose (GObject *object)
{
BrowserConnection *bcnc;
@@ -331,33 +463,6 @@ browser_connection_dispose (GObject *object)
parent_class->dispose (object);
}
-/* executed in sub @bcnc->priv->wrapper's thread */
-static gpointer
-wrapper_meta_store_update (BrowserConnection *bcnc, GError **error)
-{
- gboolean retval;
- GdaMetaContext context = {"_tables", 0, NULL, NULL};
- retval = gda_connection_update_meta_store (bcnc->priv->cnc, &context, error);
-
- return GINT_TO_POINTER (retval ? 2 : 1);
-}
-
-/* executed in sub @bcnc->priv->wrapper's thread */
-static gpointer
-wrapper_meta_struct_sync (BrowserConnection *bcnc, GError **error)
-{
- gboolean retval;
-
- g_mutex_lock (bcnc->priv->p_mstruct_mutex);
- g_assert (bcnc->priv->p_mstruct);
- g_object_ref (G_OBJECT (bcnc->priv->p_mstruct));
- retval = gda_meta_struct_complement_all (bcnc->priv->p_mstruct, error);
- g_object_unref (G_OBJECT (bcnc->priv->p_mstruct));
- g_mutex_unlock (bcnc->priv->p_mstruct_mutex);
-
- return GINT_TO_POINTER (retval ? 2 : 1);
-}
-
static gboolean
check_for_wrapper_result (BrowserConnection *bcnc)
{
@@ -491,188 +596,11 @@ browser_connection_new (GdaConnection *cnc)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- bcnc = BROWSER_CONNECTION (g_object_new (BROWSER_TYPE_CONNECTION, NULL));
- bcnc->priv->cnc = g_object_ref (cnc);
- g_signal_connect (cnc, "transaction-status-changed",
- G_CALLBACK (transaction_status_changed_cb), bcnc);
-
- /* meta store */
- gchar *dict_file_name = NULL;
- gboolean update_store = FALSE;
- GdaMetaStore *store;
- gchar *cnc_string, *cnc_info;
-
- g_object_get (G_OBJECT (cnc),
- "dsn", &cnc_info,
- "cnc-string", &cnc_string, NULL);
- dict_file_name = compute_dict_file_name (cnc_info ? gda_config_get_dsn_info (cnc_info) : NULL,
- cnc_string);
- g_free (cnc_string);
- if (dict_file_name) {
- if (! g_file_test (dict_file_name, G_FILE_TEST_EXISTS))
- update_store = TRUE;
- store = gda_meta_store_new_with_file (dict_file_name);
- }
- else {
- store = gda_meta_store_new (NULL);
- if (store)
- update_store = TRUE;
- }
- bcnc->priv->dict_file_name = dict_file_name;
- g_object_set (G_OBJECT (cnc), "meta-store", store, NULL);
- if (update_store) {
- GError *lerror = NULL;
- guint job_id;
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_meta_store_update,
- g_object_ref (bcnc), g_object_unref, &lerror);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_META_STORE_UPDATE,
- _("Getting database schema information"));
- else if (lerror) {
- browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
- lerror->message ? lerror->message : _("No detail"));
- g_error_free (lerror);
- }
- }
- else {
- guint job_id;
- GError *lerror = NULL;
-
- bcnc->priv->p_mstruct = gda_meta_struct_new (store, GDA_META_STRUCT_FEATURE_ALL);
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_meta_struct_sync,
- g_object_ref (bcnc), g_object_unref, &lerror);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_META_STRUCT_SYNC,
- _("Analysing database schema"));
- else if (lerror) {
- browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
- lerror->message ? lerror->message : _("No detail"));
- g_error_free (lerror);
- }
- g_object_unref (store);
- }
+ bcnc = BROWSER_CONNECTION (g_object_new (BROWSER_TYPE_CONNECTION, "gda-connection", cnc, NULL));
return bcnc;
}
-static GdaThreadWrapper *wrapper = NULL;
-typedef struct {
- guint cncid;
- GMainLoop *loop;
- GError **error;
-
- /* out */
- GdaConnection *cnc;
-} MainloopData;
-
-static gboolean
-check_for_cnc (MainloopData *data)
-{
- GdaConnection *cnc;
- GError *lerror = NULL;
- cnc = gda_thread_wrapper_fetch_result (wrapper, FALSE, data->cncid, &lerror);
- if (cnc || (!cnc && lerror)) {
- /* waiting is finished! */
- data->cnc = cnc;
- if (lerror)
- g_propagate_error (data->error, lerror);
- g_main_loop_quit (data->loop);
- return FALSE;
- }
- return TRUE;
-}
-
-typedef struct {
- GdaConnection *cnc_to_wrap;
- const gchar *ns;
-} VirtualConnectionData;
-/*
- * executed in a sub thread
- */
-static GdaConnection *
-sub_thread_open_cnc (VirtualConnectionData *vcdata, GError **error)
-{
-#ifndef DUMMY
- static GdaVirtualProvider *provider = NULL;
- GdaConnection *virtual, *cnc;
- if (!provider)
- provider = gda_vprovider_hub_new ();
-
- virtual = gda_virtual_connection_open_extended (provider, GDA_CONNECTION_OPTIONS_THREAD_SAFE, NULL);
- cnc = g_object_get_data (G_OBJECT (virtual), "gda-virtual-connection");
- if (!gda_vconnection_hub_add (GDA_VCONNECTION_HUB (cnc), vcdata->cnc_to_wrap,
- vcdata->ns, error)) {
- g_object_unref (virtual);
- return NULL;
- }
- else
- return virtual;
-#else
- sleep (5);
- g_set_error (error, 0, 0, "Oooo");
- return NULL;
-#endif
-}
-/**
- * browser_connection_new_virtual
- * @bcnc: a #BrowserConnection
- * @ns: the namespace for @bcnc's tables
- * @error: a place to store errors, or %NULL
- *
- * Creates a new virtual connection using #BrowserConnection as a starting point.
- *
- * To close the new connection, use browser_core_close_connection().
- *
- * Returns: a new object
- */
-BrowserConnection *
-browser_connection_new_virtual (BrowserConnection *bcnc, const gchar *ns, GError **error)
-{
- g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
-
- if (!wrapper)
- wrapper = gda_thread_wrapper_new ();
-
- guint cncid;
- VirtualConnectionData vcdata;
-
- vcdata.cnc_to_wrap = bcnc->priv->cnc;
- vcdata.ns = ns ? ns : bcnc->priv->name;
- cncid = gda_thread_wrapper_execute (wrapper,
- (GdaThreadWrapperFunc) sub_thread_open_cnc,
- (gpointer) &vcdata,
- (GDestroyNotify) NULL,
- error);
- if (cncid == 0)
- return NULL;
-
- GMainLoop *loop;
- guint source_id;
- MainloopData data;
-
- loop = g_main_loop_new (NULL, FALSE);
- data.cncid = cncid;
- data.error = error;
- data.loop = loop;
- data.cnc = NULL;
-
- source_id = g_timeout_add (200, (GSourceFunc) check_for_cnc, &data);
- g_main_loop_run (loop);
- g_main_loop_unref (loop);
-
- if (data.cnc) {
- BrowserConnection *nbcnc;
- g_object_set (data.cnc, "monitor-wrapped-in-mainloop", TRUE, NULL);
- nbcnc = browser_connection_new (data.cnc);
- g_object_unref (data.cnc);
- return nbcnc;
- }
- else
- return NULL;
-}
-
/**
* browser_connection_get_name
* @bcnc: a #BrowserConnection
@@ -756,6 +684,8 @@ browser_connection_is_busy (BrowserConnection *bcnc, gchar **out_reason)
*out_reason = g_strdup (wj->reason);
return TRUE;
}
+ else if (BROWSER_CONNECTION_CLASS (G_OBJECT_GET_CLASS (bcnc))->is_busy)
+ return BROWSER_CONNECTION_CLASS (G_OBJECT_GET_CLASS (bcnc))->is_busy (bcnc, out_reason);
else
return FALSE;
}
diff --git a/tools/browser/browser-connection.h b/tools/browser/browser-connection.h
index 49b3025..4ad0737 100644
--- a/tools/browser/browser-connection.h
+++ b/tools/browser/browser-connection.h
@@ -52,12 +52,14 @@ struct _BrowserConnectionClass
void (*meta_changed) (BrowserConnection *bcnc, GdaMetaStruct *mstruct);
void (*favorites_changed) (BrowserConnection *bcnc);
void (*transaction_status_changed) (BrowserConnection *bcnc);
+
+ /* virtual methods */
+ gboolean (*is_busy) (BrowserConnection *bcnc, gchar **out_reason);
};
GType browser_connection_get_type (void) G_GNUC_CONST;
BrowserConnection *browser_connection_new (GdaConnection *cnc);
-BrowserConnection *browser_connection_new_virtual (BrowserConnection *bcnc, const gchar *ns, GError **error);
const gchar *browser_connection_get_name (BrowserConnection *bcnc);
const GdaDsnInfo *browser_connection_get_information (BrowserConnection *bcnc);
diff --git a/tools/browser/browser-connections-list.c b/tools/browser/browser-connections-list.c
index 28887f6..c96d261 100644
--- a/tools/browser/browser-connections-list.c
+++ b/tools/browser/browser-connections-list.c
@@ -304,37 +304,8 @@ connection_new_cb (GtkButton *button, BrowserConnectionsList *clist)
}
}
-static void
-connection_bind_cb (GtkButton *button, BrowserConnectionsList *clist)
-{
- GtkTreeSelection *select;
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- select = gtk_tree_view_get_selection (clist->priv->treeview);
- if (gtk_tree_selection_get_selected (select, &model, &iter)) {
- BrowserConnection *bcnc, *nbcnc;
- GError *error = NULL;
- gtk_tree_model_get (model, &iter, COLUMN_BCNC, &bcnc, -1);
- nbcnc = browser_connection_new_virtual (bcnc, NULL, &error);
- if (nbcnc) {
- BrowserWindow *nbwin;
- nbwin = browser_window_new (nbcnc, NULL);
-
- browser_core_take_window (nbwin);
- browser_core_take_connection (nbcnc);
- }
- else {
- browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) clist),
- _("Could not open binding connection: %s"),
- error && error->message ? error->message : _("No detail"));
- g_clear_error (&error);
- }
- }
-}
-
/**
- * browser_connections_list_new
+ * browser_connections_list_show
*
* Creates a new #BrowserConnectionsList widget and displays it.
* Only one is created and shown (singleton)
@@ -422,21 +393,12 @@ browser_connections_list_show (void)
gtk_widget_set_tooltip_text (button, _("Close selected connection"));
_clist->priv->close_cnc_button = button;
- button = gtk_button_new_with_label (_("Open"));
+ button = gtk_button_new_with_label (_("Connect"));
gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (connection_new_cb), clist);
gtk_widget_set_tooltip_text (button, _("Open a new connection"));
- button = gtk_button_new_with_label (_("Bind"));
- gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
- g_signal_connect (button, "clicked",
- G_CALLBACK (connection_bind_cb), clist);
- gtk_widget_set_tooltip_text (button, _("Use selected connection to create\n"
- "a new binding connection to access data\n"
- "from multiple databases at once"));
-
-
/* GtkTreeModel and view */
GtkListStore *store;
store = gtk_list_store_new (NUM_COLUMNS,
diff --git a/tools/browser/browser-virtual-connection.c b/tools/browser/browser-virtual-connection.c
new file mode 100644
index 0000000..d3e728e
--- /dev/null
+++ b/tools/browser/browser-virtual-connection.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2009 Vivien Malerba
+ *
+ * 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 <string.h>
+#include <glib/gi18n-lib.h>
+#include "browser-virtual-connection.h"
+#include "browser-connection-priv.h"
+#include <virtual/libgda-virtual.h>
+
+/*
+ * Main static functions
+ */
+static void browser_virtual_connection_class_init (BrowserVirtualConnectionClass *klass);
+static void browser_virtual_connection_init (BrowserVirtualConnection *stmt);
+static void browser_virtual_connection_dispose (GObject *object);
+static void browser_virtual_connection_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void browser_virtual_connection_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+struct _BrowserVirtualConnectionPrivate
+{
+ GtkTable *layout_table;
+ BrowserVirtualConnectionSpecs *specs;
+};
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+/* properties */
+enum {
+ PROP_0,
+ PROP_SPECS
+};
+
+GType
+browser_virtual_connection_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+ static const GTypeInfo info = {
+ sizeof (BrowserVirtualConnectionClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) browser_virtual_connection_class_init,
+ NULL,
+ NULL,
+ sizeof (BrowserVirtualConnection),
+ 0,
+ (GInstanceInitFunc) browser_virtual_connection_init
+ };
+
+ g_static_mutex_lock (®istering);
+ if (type == 0)
+ type = g_type_register_static (BROWSER_TYPE_CONNECTION, "BrowserVirtualConnection", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+ return type;
+}
+
+static void
+source_cnc_busy_cb (BrowserConnection *bcnc, gboolean is_busy, const gchar *reason,
+ BrowserConnection *virtual)
+{
+ g_signal_emit_by_name (virtual, "busy", is_busy,
+ is_busy ? _("Bound connection is used") : NULL);
+}
+
+static gboolean
+is_busy (BrowserConnection *bcnc, gchar **out_reason)
+{
+ GSList *list;
+ if (out_reason)
+ *out_reason = NULL;
+
+ if (! BROWSER_VIRTUAL_CONNECTION (bcnc)->priv->specs)
+ return FALSE;
+
+ for (list = BROWSER_VIRTUAL_CONNECTION (bcnc)->priv->specs->parts; list; list = list->next) {
+ BrowserVirtualConnectionPart *part;
+ part = (BrowserVirtualConnectionPart*) list->data;
+ if (part->part_type == BROWSER_VIRTUAL_CONNECTION_PART_CNC) {
+ BrowserVirtualConnectionCnc *cnc;
+ cnc = &(part->u.cnc);
+ if (browser_connection_is_busy (cnc->source_cnc, out_reason))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+m_busy (BrowserConnection *bcnc, gboolean is_busy, const gchar *reason)
+{
+ /*
+ * declare all the source connections as busy
+ */
+ GSList *list;
+ if (! BROWSER_VIRTUAL_CONNECTION (bcnc)->priv->specs)
+ return;
+
+ for (list = BROWSER_VIRTUAL_CONNECTION (bcnc)->priv->specs->parts; list; list = list->next) {
+ BrowserVirtualConnectionPart *part;
+ part = (BrowserVirtualConnectionPart*) list->data;
+ if (part->part_type == BROWSER_VIRTUAL_CONNECTION_PART_CNC) {
+ BrowserVirtualConnectionCnc *cnc;
+ cnc = &(part->u.cnc);
+ g_signal_handlers_block_by_func (cnc->source_cnc,
+ G_CALLBACK (source_cnc_busy_cb),
+ bcnc);
+ g_signal_emit_by_name (cnc->source_cnc, "busy", is_busy,
+ is_busy ? _("Virtual connection using this connection is busy") : NULL);
+ g_signal_handlers_unblock_by_func (cnc->source_cnc,
+ G_CALLBACK (source_cnc_busy_cb),
+ bcnc);
+ }
+ }
+}
+
+static void
+browser_virtual_connection_class_init (BrowserVirtualConnectionClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ parent_class = g_type_class_peek_parent (klass);
+
+ BROWSER_CONNECTION_CLASS (klass)->busy = m_busy;
+ BROWSER_CONNECTION_CLASS (klass)->is_busy = is_busy;
+
+ /* Properties */
+ object_class->set_property = browser_virtual_connection_set_property;
+ object_class->get_property = browser_virtual_connection_get_property;
+ g_object_class_install_property (object_class, PROP_SPECS,
+ g_param_spec_pointer ("specs", NULL,
+ "Specifications as a BrowserVirtualConnectionSpecs pointer",
+ G_PARAM_READABLE | G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+ object_class->dispose = browser_virtual_connection_dispose;
+}
+
+static void
+browser_virtual_connection_init (BrowserVirtualConnection *bcnc)
+{
+ bcnc->priv = g_new0 (BrowserVirtualConnectionPrivate, 1);
+}
+
+static void
+browser_virtual_connection_dispose (GObject *object)
+{
+ BrowserVirtualConnection *bcnc;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (BROWSER_IS_VIRTUAL_CONNECTION (object));
+
+ bcnc = BROWSER_VIRTUAL_CONNECTION (object);
+
+ if (bcnc->priv) {
+ if (bcnc->priv->specs) {
+ GSList *list;
+ for (list = bcnc->priv->specs->parts; list; list = list->next) {
+ BrowserVirtualConnectionPart *part;
+ part = (BrowserVirtualConnectionPart*) list->data;
+ if (part->part_type == BROWSER_VIRTUAL_CONNECTION_PART_CNC) {
+ BrowserVirtualConnectionCnc *cnc;
+ cnc = &(part->u.cnc);
+ g_signal_handlers_disconnect_by_func (cnc->source_cnc,
+ G_CALLBACK (source_cnc_busy_cb),
+ bcnc);
+ }
+ }
+ browser_virtual_connection_specs_free (bcnc->priv->specs);
+ }
+
+ g_free (bcnc->priv);
+ bcnc->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->dispose (object);
+}
+
+static void
+browser_virtual_connection_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ BrowserVirtualConnection *bcnc;
+
+ bcnc = BROWSER_VIRTUAL_CONNECTION (object);
+ if (bcnc->priv) {
+ switch (param_id) {
+ case PROP_SPECS:
+ bcnc->priv->specs = browser_virtual_connection_specs_copy (g_value_get_pointer (value));
+ GSList *list;
+ for (list = bcnc->priv->specs->parts; list; list = list->next) {
+ BrowserVirtualConnectionPart *part;
+ part = (BrowserVirtualConnectionPart*) list->data;
+ if (part->part_type == BROWSER_VIRTUAL_CONNECTION_PART_CNC) {
+ BrowserVirtualConnectionCnc *cnc;
+ cnc = &(part->u.cnc);
+ g_signal_connect (cnc->source_cnc, "busy",
+ G_CALLBACK (source_cnc_busy_cb), bcnc);
+ }
+ }
+
+ break;
+ }
+ }
+}
+
+static void
+browser_virtual_connection_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ BrowserVirtualConnection *bcnc;
+
+ bcnc = BROWSER_VIRTUAL_CONNECTION (object);
+ if (bcnc->priv) {
+ switch (param_id) {
+ case PROP_SPECS:
+ g_value_set_pointer (value, bcnc->priv->specs);
+ break;
+ }
+ }
+}
+
+
+
+typedef struct {
+ guint cncid;
+ GMainLoop *loop;
+ GError **error;
+ GdaThreadWrapper *wrapper;
+
+ /* out */
+ GdaConnection *cnc;
+} MainloopData;
+
+static gboolean
+check_for_cnc (MainloopData *data)
+{
+ GdaConnection *cnc;
+ GError *lerror = NULL;
+ cnc = gda_thread_wrapper_fetch_result (data->wrapper, FALSE, data->cncid, &lerror);
+ if (cnc || (!cnc && lerror)) {
+ /* waiting is finished! */
+ data->cnc = cnc;
+ if (lerror)
+ g_propagate_error (data->error, lerror);
+ g_main_loop_quit (data->loop);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * executed in a sub thread
+ */
+static GdaConnection *
+sub_thread_open_cnc (BrowserVirtualConnectionSpecs *specs, GError **error)
+{
+#ifndef DUMMY
+ /* create GDA virtual connection */
+ static GdaVirtualProvider *provider = NULL;
+ GdaConnection *virtual, *cnc;
+ if (!provider)
+ provider = gda_vprovider_hub_new ();
+
+ virtual = gda_virtual_connection_open_extended (provider, GDA_CONNECTION_OPTIONS_THREAD_SAFE, NULL);
+ cnc = g_object_get_data (G_OBJECT (virtual), "gda-virtual-connection");
+
+ /* add parts to connection as specified by @specs */
+ GSList *list;
+ for (list = specs->parts; list; list = list->next) {
+ BrowserVirtualConnectionPart *part;
+ part = (BrowserVirtualConnectionPart*) list->data;
+ switch (part->part_type) {
+ case BROWSER_VIRTUAL_CONNECTION_PART_MODEL: {
+ BrowserVirtualConnectionModel *pm;
+ pm = &(part->u.model);
+ if (! gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (cnc),
+ pm->model, pm->table_name, error)) {
+ g_object_unref (virtual);
+ return NULL;
+ }
+ break;
+ }
+ case BROWSER_VIRTUAL_CONNECTION_PART_CNC: {
+ BrowserVirtualConnectionCnc *scnc;
+ scnc = &(part->u.cnc);
+ if (!gda_vconnection_hub_add (GDA_VCONNECTION_HUB (cnc), scnc->source_cnc->priv->cnc,
+ scnc->table_schema, error)) {
+ g_object_unref (virtual);
+ return NULL;
+ }
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ return virtual;
+#else
+ sleep (5);
+ g_set_error (error, 0, 0, "Timeout!!!");
+ return NULL;
+#endif
+}
+
+/**
+ * browser_virtual_connection_new
+ * @specs: the specifications of the virtual connection's contents
+ * @error: a place to store errors, or %NULL
+ *
+ * Creates a new #BrowserVirtualConnection connection.
+ *
+ * Returns: the new connection
+ */
+BrowserConnection *
+browser_virtual_connection_new (BrowserVirtualConnectionSpecs *specs, GError **error)
+{
+ /* open virtual GdaConnection in sub thread */
+ GdaThreadWrapper *wrapper;
+ guint cncid;
+
+ g_return_val_if_fail (specs, NULL);
+
+ wrapper = gda_thread_wrapper_new ();
+ cncid = gda_thread_wrapper_execute (wrapper,
+ (GdaThreadWrapperFunc) sub_thread_open_cnc,
+ (gpointer) specs,
+ (GDestroyNotify) NULL,
+ error);
+ if (cncid == 0)
+ return NULL;
+
+ GMainLoop *loop;
+ guint source_id;
+ MainloopData data;
+
+ loop = g_main_loop_new (NULL, FALSE);
+ data.wrapper = wrapper;
+ data.cncid = cncid;
+ data.error = error;
+ data.loop = loop;
+ data.cnc = NULL;
+
+ source_id = g_timeout_add (200, (GSourceFunc) check_for_cnc, &data);
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+ g_object_unref (wrapper);
+
+ /* create the BrowserConnection object */
+ if (data.cnc) {
+ BrowserConnection *nbcnc;
+ g_object_set (data.cnc, "monitor-wrapped-in-mainloop", TRUE, NULL);
+ nbcnc = g_object_new (BROWSER_TYPE_VIRTUAL_CONNECTION, "specs", specs,
+ "gda-connection", data.cnc, NULL);
+ g_object_unref (data.cnc);
+
+ return nbcnc;
+ }
+ else
+ return NULL;
+}
+
+/*
+ * Spec manipulations
+ */
+
+/**
+ * browser_virtual_connection_part_copy
+ */
+BrowserVirtualConnectionPart *
+browser_virtual_connection_part_copy (const BrowserVirtualConnectionPart *part)
+{
+ BrowserVirtualConnectionPart *npart;
+ g_return_val_if_fail (part, NULL);
+
+ npart = g_new0 (BrowserVirtualConnectionPart, 1);
+ npart->part_type = part->part_type;
+
+ switch (part->part_type) {
+ case BROWSER_VIRTUAL_CONNECTION_PART_MODEL: {
+ const BrowserVirtualConnectionModel *spm;
+ BrowserVirtualConnectionModel *npm;
+ spm = &(part->u.model);
+ npm = &(npart->u.model);
+ if (spm->table_schema)
+ npm->table_schema = g_strdup (spm->table_schema);
+ if (spm->table_name)
+ npm->table_name = g_strdup (spm->table_name);
+ if (spm->model)
+ npm->model = g_object_ref (G_OBJECT (spm->model));
+ break;
+ }
+ case BROWSER_VIRTUAL_CONNECTION_PART_CNC: {
+ const BrowserVirtualConnectionCnc *scnc;
+ BrowserVirtualConnectionCnc *ncnc;
+ scnc = &(part->u.cnc);
+ ncnc = &(npart->u.cnc);
+ if (scnc->table_schema)
+ ncnc->table_schema = g_strdup (scnc->table_schema);
+ if (scnc->source_cnc)
+ ncnc->source_cnc = g_object_ref (G_OBJECT (scnc->source_cnc));
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+
+ return npart;
+}
+
+/**
+ * browser_virtual_connection_part_free
+ */
+void
+browser_virtual_connection_part_free (BrowserVirtualConnectionPart *part)
+{
+ if (!part)
+ return;
+
+ switch (part->part_type) {
+ case BROWSER_VIRTUAL_CONNECTION_PART_MODEL: {
+ BrowserVirtualConnectionModel *pm;
+ pm = &(part->u.model);
+ g_free (pm->table_schema);
+ g_free (pm->table_name);
+ if (pm->model)
+ g_object_unref (pm->model);
+ break;
+ }
+ case BROWSER_VIRTUAL_CONNECTION_PART_CNC: {
+ BrowserVirtualConnectionCnc *cnc;
+ cnc = &(part->u.cnc);
+ g_free (cnc->table_schema);
+ if (cnc->source_cnc)
+ g_object_unref (cnc->source_cnc);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+/**
+ * browser_virtual_connection_specs_copy
+ */
+BrowserVirtualConnectionSpecs *
+browser_virtual_connection_specs_copy (const BrowserVirtualConnectionSpecs *specs)
+{
+ BrowserVirtualConnectionSpecs *ns;
+ GSList *list;
+
+ g_return_val_if_fail (specs, NULL);
+
+ ns = g_new0 (BrowserVirtualConnectionSpecs, 1);
+ for (list = specs->parts; list; list = list->next) {
+ BrowserVirtualConnectionPart *npart;
+ npart = browser_virtual_connection_part_copy ((BrowserVirtualConnectionPart*) list->data);
+ ns->parts = g_slist_prepend (ns->parts, npart);
+ }
+ ns->parts = g_slist_reverse (ns->parts);
+
+ return ns;
+}
+
+/**
+ * browser_virtual_connection_specs_free
+ */
+void
+browser_virtual_connection_specs_free (BrowserVirtualConnectionSpecs *specs)
+{
+ if (!specs)
+ return;
+ g_slist_foreach (specs->parts, (GFunc) browser_virtual_connection_part_free, NULL);
+ g_slist_free (specs->parts);
+ g_free (specs);
+}
diff --git a/tools/browser/browser-virtual-connection.h b/tools/browser/browser-virtual-connection.h
new file mode 100644
index 0000000..840e1bc
--- /dev/null
+++ b/tools/browser/browser-virtual-connection.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009 Vivien Malerba
+ *
+ * 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 __BROWSER_VIRTUAL_CONNECTION_H_
+#define __BROWSER_VIRTUAL_CONNECTION_H_
+
+#include <gtk/gtk.h>
+#include "browser-connection.h"
+
+G_BEGIN_DECLS
+
+#define BROWSER_TYPE_VIRTUAL_CONNECTION (browser_virtual_connection_get_type())
+#define BROWSER_VIRTUAL_CONNECTION(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, browser_virtual_connection_get_type(), BrowserVirtualConnection)
+#define BROWSER_VIRTUAL_CONNECTION_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, browser_virtual_connection_get_type (), BrowserVirtualConnectionClass)
+#define BROWSER_IS_VIRTUAL_CONNECTION(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, browser_virtual_connection_get_type ())
+
+typedef struct _BrowserVirtualConnection BrowserVirtualConnection;
+typedef struct _BrowserVirtualConnectionPrivate BrowserVirtualConnectionPrivate;
+typedef struct _BrowserVirtualConnectionClass BrowserVirtualConnectionClass;
+
+/* struct for the object's data */
+struct _BrowserVirtualConnection
+{
+ BrowserConnection object;
+ BrowserVirtualConnectionPrivate *priv;
+};
+
+/* struct for the object's class */
+struct _BrowserVirtualConnectionClass
+{
+ BrowserConnectionClass parent_class;
+};
+
+/* parts types */
+typedef enum {
+ BROWSER_VIRTUAL_CONNECTION_PART_MODEL,
+ BROWSER_VIRTUAL_CONNECTION_PART_CNC,
+} BrowserVirtualConnectionType;
+
+/* part: a table from a GdaDataModel */
+typedef struct {
+ gchar *table_schema;
+ gchar *table_name;
+ GdaDataModel *model;
+} BrowserVirtualConnectionModel;
+
+/* part: tables from a BrowserConnection */
+typedef struct {
+ gchar *table_schema;
+ BrowserConnection *source_cnc;
+} BrowserVirtualConnectionCnc;
+
+/* generic part */
+typedef struct {
+ BrowserVirtualConnectionType part_type;
+ union {
+ BrowserVirtualConnectionModel model;
+ BrowserVirtualConnectionCnc cnc;
+ } u;
+} BrowserVirtualConnectionPart;
+BrowserVirtualConnectionPart *browser_virtual_connection_part_copy (const BrowserVirtualConnectionPart *part);
+void browser_virtual_connection_part_free (BrowserVirtualConnectionPart *part);
+
+/* specs */
+typedef struct {
+ GSList *parts;
+} BrowserVirtualConnectionSpecs;
+BrowserVirtualConnectionSpecs *browser_virtual_connection_specs_copy (const BrowserVirtualConnectionSpecs *specs);
+void browser_virtual_connection_specs_free (BrowserVirtualConnectionSpecs *specs);
+
+GType browser_virtual_connection_get_type (void) G_GNUC_CONST;
+BrowserConnection *browser_virtual_connection_new (BrowserVirtualConnectionSpecs *specs,
+ GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/browser-window.c b/tools/browser/browser-window.c
index 108e6c4..fd06c0b 100644
--- a/tools/browser/browser-window.c
+++ b/tools/browser/browser-window.c
@@ -29,6 +29,7 @@
#include "browser-connections-list.h"
#include "browser-spinner.h"
#include "browser-stock-icons.h"
+#include "connection-binding-properties.h"
/*
* structure representing a 'tab' in a window
@@ -192,6 +193,7 @@ static void window_new_cb (GtkAction *action, BrowserWindow *bwin);
static void window_new_with_cnc_cb (GtkAction *action, BrowserWindow *bwin);
static void connection_close_cb (GtkAction *action, BrowserWindow *bwin);
static void connection_open_cb (GtkAction *action, BrowserWindow *bwin);
+static void connection_bind_cb (GtkAction *action, BrowserWindow *bwin);
static void connection_list_cb (GtkAction *action, BrowserWindow *bwin);
static void connection_meta_update_cb (GtkAction *action, BrowserWindow *bwin);
static void perspective_toggle_cb (GtkRadioAction *action, GtkRadioAction *current, BrowserWindow *bwin);
@@ -204,6 +206,9 @@ static const GtkToggleActionEntry ui_toggle_actions [] =
static const GtkActionEntry ui_actions[] = {
{ "Connection", NULL, "_Connection", NULL, "Connection", NULL },
{ "ConnectionOpen", GTK_STOCK_CONNECT, "_Connect", NULL, "Open a connection", G_CALLBACK (connection_open_cb)},
+ { "ConnectionBind", NULL, N_("_Bind connection"), "<control>B", N_("Use connection to create\n"
+ "a new binding connection to access data\n"
+ "from multiple databases at once"), G_CALLBACK (connection_bind_cb)},
{ "ConnectionList", NULL, "_Connections list", NULL, "Connections list", G_CALLBACK (connection_list_cb)},
{ "ConnectionMetaSync", GTK_STOCK_REFRESH, "_Fetch meta data", NULL, "Fetch meta data", G_CALLBACK (connection_meta_update_cb)},
{ "ConnectionClose", GTK_STOCK_CLOSE, "_Close connection", NULL, "Close this connection", G_CALLBACK (connection_close_cb)},
@@ -226,7 +231,9 @@ static const gchar *ui_actions_info =
" <menuitem name='ConnectionList' action= 'ConnectionList'/>"
" <menuitem name='ConnectionMetaSync' action= 'ConnectionMetaSync'/>"
" <separator/>"
+ " <menuitem name='ConnectionBind' action= 'ConnectionBind'/>"
" <menuitem name='ConnectionClose' action= 'ConnectionClose'/>"
+ " <separator/>"
" <menuitem name='Quit' action= 'Quit'/>"
" <separator/>"
" </menu>"
@@ -771,6 +778,39 @@ connection_open_cb (GtkAction *action, BrowserWindow *bwin)
}
static void
+connection_bind_cb (GtkAction *action, BrowserWindow *bwin)
+{
+ GtkWidget *win;
+ gint res;
+
+ win = connection_binding_properties_new_create (bwin->priv->bcnc);
+ gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (bwin));
+ gtk_widget_show (win);
+
+ res = gtk_dialog_run (GTK_DIALOG (win));
+ if (res == GTK_RESPONSE_OK) {
+ BrowserConnection *bcnc;
+ GError *error = NULL;
+ bcnc = browser_virtual_connection_new (connection_binding_properties_get_specs
+ (CONNECTION_BINDING_PROPERTIES (win)), &error);
+ if (bcnc) {
+ BrowserWindow *bwin;
+ bwin = browser_window_new (bcnc, NULL);
+
+ browser_core_take_window (bwin);
+ browser_core_take_connection (bcnc);
+ }
+ else {
+ browser_show_error ((GtkWindow*) bwin,
+ _("Could not open binding connection: %s"),
+ error && error->message ? error->message : _("No detail"));
+ g_clear_error (&error);
+ }
+ }
+ gtk_widget_destroy (win);
+}
+
+static void
connection_list_cb (GtkAction *action, BrowserWindow *bwin)
{
browser_connections_list_show ();
diff --git a/tools/browser/connection-binding-properties.c b/tools/browser/connection-binding-properties.c
new file mode 100644
index 0000000..eaf6b87
--- /dev/null
+++ b/tools/browser/connection-binding-properties.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2009 Vivien Malerba
+ *
+ * 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 <string.h>
+#include <glib/gi18n-lib.h>
+#include "connection-binding-properties.h"
+#include "browser-connection.h"
+#include "support.h"
+#include <libgda-ui/libgda-ui.h>
+
+/*
+ * Main static functions
+ */
+static void connection_binding_properties_class_init (ConnectionBindingPropertiesClass *klass);
+static void connection_binding_properties_init (ConnectionBindingProperties *stmt);
+static void connection_binding_properties_dispose (GObject *object);
+
+static void create_layout (ConnectionBindingProperties *cprop);
+static void update_display (ConnectionBindingProperties *cprop);
+
+struct _ConnectionBindingPropertiesPrivate
+{
+ BrowserVirtualConnectionSpecs *specs;
+ GtkTable *layout_table;
+};
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+GType
+connection_binding_properties_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+ static const GTypeInfo info = {
+ sizeof (ConnectionBindingPropertiesClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) connection_binding_properties_class_init,
+ NULL,
+ NULL,
+ sizeof (ConnectionBindingProperties),
+ 0,
+ (GInstanceInitFunc) connection_binding_properties_init
+ };
+
+ g_static_mutex_lock (®istering);
+ if (type == 0)
+ type = g_type_register_static (GTK_TYPE_DIALOG, "ConnectionBindingProperties", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+ return type;
+}
+
+static void
+connection_binding_properties_class_init (ConnectionBindingPropertiesClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = connection_binding_properties_dispose;
+}
+
+static void
+connection_binding_properties_init (ConnectionBindingProperties *cprop)
+{
+ cprop->priv = g_new0 (ConnectionBindingPropertiesPrivate, 1);
+}
+
+static void
+connection_binding_properties_dispose (GObject *object)
+{
+ ConnectionBindingProperties *cprop;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (CONNECTION_IS_BINDING_PROPERTIES (object));
+
+ cprop = CONNECTION_BINDING_PROPERTIES (object);
+
+ if (cprop->priv) {
+ if (cprop->priv->specs)
+ browser_virtual_connection_specs_free (cprop->priv->specs);
+ g_free (cprop->priv);
+ cprop->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->dispose (object);
+}
+
+/**
+ * connection_binding_properties_new_create
+ * @bcnc: a #BrowserConnection
+ *
+ * Creates a new #ConnectionBindingProperties window. The window will allow a new
+ * virtual connection to be opened using tables from @bcnc.
+ *
+ * Returns: the new object
+ */
+GtkWidget *
+connection_binding_properties_new_create (BrowserConnection *bcnc)
+{
+ ConnectionBindingProperties *cprop;
+ BrowserVirtualConnectionSpecs *specs;
+ BrowserVirtualConnectionPart *part;
+
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+
+ specs = g_new0 (BrowserVirtualConnectionSpecs, 1);
+ part = g_new0 (BrowserVirtualConnectionPart, 1);
+ part->part_type = BROWSER_VIRTUAL_CONNECTION_PART_CNC;
+ part->u.cnc.table_schema = g_strdup (browser_connection_get_name (bcnc));
+ part->u.cnc.source_cnc = g_object_ref (G_OBJECT (bcnc));
+ specs->parts = g_slist_append (NULL, part);
+
+ cprop = CONNECTION_BINDING_PROPERTIES (g_object_new (CONNECTION_TYPE_BINDING_PROPERTIES, NULL));
+ cprop->priv->specs = specs;
+ gtk_window_set_title (GTK_WINDOW (cprop), _("New virtual connection"));
+
+ create_layout (cprop);
+ update_display (cprop);
+
+ gtk_widget_show (gtk_dialog_add_button (GTK_DIALOG (cprop), GTK_STOCK_NEW, GTK_RESPONSE_OK));
+ gtk_widget_show (gtk_dialog_add_button (GTK_DIALOG (cprop), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL));
+
+ return (GtkWidget*) cprop;
+}
+
+static void
+create_layout (ConnectionBindingProperties *cprop)
+{
+ GtkWidget *label, *hbox;
+ gchar *str;
+
+ str = g_strdup_printf ("<b>%s:</b>\n<small>%s</small>",
+ _("Virtual connection's properties"),
+ _("Define the sources of data for which tables will\n"
+ "appear in the virtual connection"));
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ g_free (str);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (cprop)->vbox), label, FALSE, FALSE, 5);
+
+ hbox = gtk_hbox_new (FALSE, 0); /* HIG */
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (cprop)->vbox), hbox, TRUE, TRUE, 0);
+ label = gtk_label_new (" ");
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ cprop->priv->layout_table = GTK_TABLE (gtk_table_new (2, 2, FALSE));
+ gtk_box_pack_start (GTK_BOX (hbox), (GtkWidget*) cprop->priv->layout_table, TRUE, TRUE, 0);
+
+ gtk_widget_show_all (GTK_DIALOG (cprop)->vbox);
+}
+
+static void add_part_clicked_cb (GtkWidget *button, ConnectionBindingProperties *cprop);
+static void del_part_clicked_cb (GtkWidget *button, BrowserVirtualConnectionPart *part);
+
+static GtkWidget *create_part_for_model (BrowserVirtualConnectionModel *pm);
+static GtkWidget *create_part_for_cnc (BrowserVirtualConnectionCnc *cnc);
+
+static void
+update_display (ConnectionBindingProperties *cprop)
+{
+ /* clear any previous setting */
+ gtk_container_foreach (GTK_CONTAINER (cprop->priv->layout_table), (GtkCallback) gtk_widget_destroy, NULL);
+
+ /* new contents */
+ gint top = 0;
+ GtkWidget *button, *label;
+ if (cprop->priv->specs) {
+ GSList *list;
+ for (list = cprop->priv->specs->parts; list; list = list->next, top++) {
+ BrowserVirtualConnectionPart *part;
+ GtkWidget *display = NULL;
+
+ part = (BrowserVirtualConnectionPart*) list->data;
+ switch (part->part_type) {
+ case BROWSER_VIRTUAL_CONNECTION_PART_MODEL:
+ display = create_part_for_model (&(part->u.model));
+ break;
+ case BROWSER_VIRTUAL_CONNECTION_PART_CNC:
+ display = create_part_for_cnc (&(part->u.cnc));
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ gtk_table_attach (cprop->priv->layout_table, display, 0, 1, top, top + 1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
+
+ button = gtk_button_new ();
+ label = browser_make_tab_label_with_stock (NULL, GTK_STOCK_REMOVE, FALSE, NULL);
+ gtk_container_add (GTK_CONTAINER (button), label);
+ gtk_table_attach (cprop->priv->layout_table, button, 1, 2, top, top + 1, 0, GTK_FILL, 0, 0);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (del_part_clicked_cb), part);
+ }
+ }
+
+ /* bottom button to add a part */
+ button = gtk_button_new ();
+ label = browser_make_tab_label_with_stock (_("Add part"), GTK_STOCK_ADD, FALSE, NULL);
+ gtk_container_add (GTK_CONTAINER (button), label);
+ gtk_table_attach (cprop->priv->layout_table, button, 0, 2, top, top + 1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (add_part_clicked_cb), cprop);
+
+ gtk_widget_show_all ((GtkWidget*) cprop->priv->layout_table);
+}
+
+static void
+add_part_clicked_cb (GtkWidget *button, ConnectionBindingProperties *cprop)
+{
+ TO_IMPLEMENT;
+}
+
+static void
+del_part_clicked_cb (GtkWidget *button, BrowserVirtualConnectionPart *part)
+{
+ TO_IMPLEMENT;
+}
+
+static GtkWidget *
+create_part_for_model (BrowserVirtualConnectionModel *pm)
+{
+ GtkWidget *vbox, *label;
+ gchar *str;
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ label = gtk_label_new ("");
+ str = g_markup_printf_escaped ("<b>%s</b>", _("Table from a data set:"));
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ g_free (str);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ GdaSet *set;
+ GdaHolder *holder;
+ GtkWidget *form;
+ set = gda_set_new_inline (2,
+ "SCHEMA", G_TYPE_STRING, pm->table_schema,
+ "NAME", G_TYPE_STRING, pm->table_name);
+
+ holder = gda_holder_new (G_TYPE_POINTER);
+ g_object_set (holder, "id", "DATASET", "name", "Data set", NULL);
+ g_assert (gda_set_add_holder (set, holder));
+ g_object_unref (holder);
+
+ g_object_set (gda_set_get_holder (set, "SCHEMA"), "name", "Table's schema", NULL);
+ g_object_set (gda_set_get_holder (set, "NAME"), "name", "Table's name", NULL);
+
+ form = gdaui_basic_form_new (set);
+ g_object_unref (set);
+ gtk_box_pack_start (GTK_BOX (vbox), form, TRUE, TRUE, 0);
+
+ return vbox;
+}
+
+static GError *
+part_for_cnc_validate_holder_change_cb (GdaSet *set, GdaHolder *holder, GValue *new_value,
+ BrowserVirtualConnectionCnc *cnc)
+{
+ const gchar *hid;
+
+ hid = gda_holder_get_id (holder);
+ g_assert (hid);
+
+ if (!strcmp (hid, "SCHEMA")) {
+ const gchar *str, *ptr;
+ str = g_value_get_string (new_value);
+ for (ptr = str; *ptr; ptr++) {
+ if (((ptr == str) && ! g_ascii_isalpha (*ptr)) ||
+ (*ptr != '_') ||
+ ! g_ascii_isalnum (*ptr)) {
+ GError *error = NULL;
+ g_set_error (&error, 0, 0,
+ _("Invalid schema name"));
+ return error;
+ }
+ }
+ }
+
+ /* no error */
+ return NULL;
+}
+
+static void
+part_for_cnc_holder_changed_cb (GdaSet *set, GdaHolder *holder, BrowserVirtualConnectionCnc *cnc)
+{
+ const gchar *hid;
+ const GValue *value;
+
+ hid = gda_holder_get_id (holder);
+ g_assert (hid);
+ value = gda_holder_get_value (holder);
+
+ if (!strcmp (hid, "SCHEMA")) {
+ g_free (cnc->table_schema);
+ cnc->table_schema = g_value_dup_string (value);
+ }
+ else if (!strcmp (hid, "CNC")) {
+ if (cnc->source_cnc)
+ g_object_unref (cnc->source_cnc);
+ cnc->source_cnc = g_value_get_object (value);
+ if (cnc->source_cnc)
+ g_object_ref (cnc->source_cnc);
+ }
+ else
+ g_assert_not_reached ();
+}
+
+static GtkWidget *
+create_part_for_cnc (BrowserVirtualConnectionCnc *cnc)
+{
+ GtkWidget *vbox, *label;
+ gchar *str;
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ label = gtk_label_new ("");
+ str = g_markup_printf_escaped ("<b>%s</b>", _("All tables of a connection:"));
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ g_free (str);
+ gtk_widget_set_tooltip_text (label, _("Each table in the selected connection will appear\n"
+ "as a table in the virtual connection"));
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ GdaSet *set;
+ GdaHolder *holder;
+ GtkWidget *form;
+ GValue *value;
+ set = gda_set_new_inline (1,
+ "SCHEMA", G_TYPE_STRING, cnc->table_schema);
+
+ holder = gda_holder_new (BROWSER_TYPE_CONNECTION);
+ g_object_set (holder, "id", "CNC", "name", "Connection", "not-null", TRUE, NULL);
+ g_assert (gda_set_add_holder (set, holder));
+
+ g_value_set_object ((value = gda_value_new (BROWSER_TYPE_CONNECTION)), cnc->source_cnc);
+ g_assert (gda_holder_set_value (holder, value, NULL));
+ gda_value_free (value);
+
+ g_assert (gda_holder_set_source_model (holder, browser_get_connections_list (),
+ CNC_LIST_COLUMN_BCNC, NULL));
+ g_object_unref (holder);
+
+ holder = gda_set_get_holder (set, "SCHEMA");
+ g_object_set (holder, "name", "Table's schema",
+ "description", _("Name of the schema the\ntables will be in"), NULL);
+
+ form = gdaui_basic_form_new (set);
+ g_signal_connect (set, "validate-holder-change",
+ G_CALLBACK (part_for_cnc_validate_holder_change_cb), cnc);
+ g_signal_connect (set, "holder-changed",
+ G_CALLBACK (part_for_cnc_holder_changed_cb), cnc);
+
+ g_object_unref (set);
+ gtk_box_pack_start (GTK_BOX (vbox), form, TRUE, TRUE, 0);
+
+ return vbox;
+}
+
+/**
+ * connection_binding_properties_get_specs
+ * @prop: a #ConnectionBindingProperties widget
+ *
+ * Returns: a pointer to a read only #BrowserVirtualConnectionSpecs
+ */
+const BrowserVirtualConnectionSpecs *
+connection_binding_properties_get_specs (ConnectionBindingProperties *prop)
+{
+ g_return_val_if_fail (CONNECTION_IS_BINDING_PROPERTIES (prop), NULL);
+
+ return prop->priv->specs;
+}
diff --git a/tools/browser/connection-binding-properties.h b/tools/browser/connection-binding-properties.h
new file mode 100644
index 0000000..110d4db
--- /dev/null
+++ b/tools/browser/connection-binding-properties.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 Vivien Malerba
+ *
+ * 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 __CONNECTION_BINDING_PROPERTIES_H_
+#define __CONNECTION_BINDING_PROPERTIES_H_
+
+#include <gtk/gtk.h>
+#include "browser-virtual-connection.h"
+#include "decl.h"
+
+G_BEGIN_DECLS
+
+#define CONNECTION_TYPE_BINDING_PROPERTIES (connection_binding_properties_get_type())
+#define CONNECTION_BINDING_PROPERTIES(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, connection_binding_properties_get_type(), ConnectionBindingProperties)
+#define CONNECTION_BINDING_PROPERTIES_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, connection_binding_properties_get_type (), ConnectionBindingPropertiesClass)
+#define CONNECTION_IS_BINDING_PROPERTIES(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, connection_binding_properties_get_type ())
+
+typedef struct _ConnectionBindingProperties ConnectionBindingProperties;
+typedef struct _ConnectionBindingPropertiesPrivate ConnectionBindingPropertiesPrivate;
+typedef struct _ConnectionBindingPropertiesClass ConnectionBindingPropertiesClass;
+
+/* struct for the object's data */
+struct _ConnectionBindingProperties
+{
+ GtkDialog object;
+ ConnectionBindingPropertiesPrivate *priv;
+};
+
+/* struct for the object's class */
+struct _ConnectionBindingPropertiesClass
+{
+ GtkDialogClass parent_class;
+};
+
+GType connection_binding_properties_get_type (void) G_GNUC_CONST;
+GtkWidget *connection_binding_properties_new_create (BrowserConnection *bcnc);
+
+GtkWidget *connection_binding_properties_new_edit (const BrowserVirtualConnectionSpecs *specs);
+
+const BrowserVirtualConnectionSpecs *connection_binding_properties_get_specs (ConnectionBindingProperties *prop);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/support.c b/tools/browser/support.c
index 7e916af..4466734 100644
--- a/tools/browser/support.c
+++ b/tools/browser/support.c
@@ -355,3 +355,73 @@ browser_find_parent_widget (GtkWidget *current, GType requested_type)
}
return NULL;
}
+
+static void connection_added_cb (BrowserCore *bcore, BrowserConnection *bcnc, GdaDataModel *model);
+static void connection_removed_cb (BrowserCore *bcore, BrowserConnection *bcnc, GdaDataModel *model);
+
+/**
+ * browser_get_connections_list
+ *
+ * Creates a unique instance of tree model listing all the connections, and returns
+ * a pointer to it. The object will always exist after it has been created, so no need
+ * to reference it.
+ *
+ * Returns: a pointer to the #GtkTreeModel, the caller must not assume it has a reference to it.
+ */
+GdaDataModel *
+browser_get_connections_list (void)
+{
+ static GdaDataModel *model = NULL;
+ if (!model) {
+ model = gda_data_model_array_new_with_g_types (CNC_LIST_NUM_COLUMNS,
+ BROWSER_TYPE_CONNECTION,
+ G_TYPE_STRING);
+ /* initial filling */
+ GSList *connections, *list;
+ connections = browser_core_get_connections ();
+ for (list = connections; list; list = list->next)
+ connection_added_cb (browser_core_get(), BROWSER_CONNECTION (list->data),
+ model);
+ g_slist_free (connections);
+
+ g_signal_connect (browser_core_get (), "connection-added",
+ G_CALLBACK (connection_added_cb), model);
+ g_signal_connect (browser_core_get (), "connection-removed",
+ G_CALLBACK (connection_removed_cb), model);
+ }
+
+ return model;
+}
+
+static void
+connection_added_cb (BrowserCore *bcore, BrowserConnection *bcnc, GdaDataModel *model)
+{
+ GList *values;
+ GValue *value;
+
+ g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), browser_connection_get_name (bcnc));
+ values = g_list_prepend (NULL, value);
+ g_value_set_object ((value = gda_value_new (BROWSER_TYPE_CONNECTION)), bcnc);
+ values = g_list_prepend (values, value);
+
+ g_assert (gda_data_model_append_values (model, values, NULL) >= 0);
+
+ g_list_foreach (values, (GFunc) gda_value_free, NULL);
+ g_list_free (values);
+}
+
+static void
+connection_removed_cb (BrowserCore *bcore, BrowserConnection *bcnc, GdaDataModel *model)
+{
+ gint i, nrows;
+ nrows = gda_data_model_get_n_rows (model);
+ for (i = 0; i < nrows; i++) {
+ const GValue *value;
+ value = gda_data_model_get_value_at (model, 0, i, NULL);
+ g_assert (value);
+ if (g_value_get_object (value) == bcnc) {
+ g_assert (gda_data_model_remove_row (model, i, NULL));
+ break;
+ }
+ }
+}
diff --git a/tools/browser/support.h b/tools/browser/support.h
index aa13d91..8409d97 100644
--- a/tools/browser/support.h
+++ b/tools/browser/support.h
@@ -66,6 +66,17 @@ typedef enum {
GdkPixbuf *browser_get_pixbuf_icon (BrowserIconType type);
+/*
+ * Connections list
+ */
+enum
+{
+ CNC_LIST_COLUMN_BCNC = 0,
+ CNC_LIST_COLUMN_NAME = 1,
+ CNC_LIST_NUM_COLUMNS
+};
+GdaDataModel *browser_get_connections_list (void);
+
G_END_DECLS
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]