[libgda] Initial Data Manager perspective in Gda-Browser
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] Initial Data Manager perspective in Gda-Browser
- Date: Tue, 2 Mar 2010 20:38:38 +0000 (UTC)
commit d4311c780e3c9434b77f98e1c2a4163351b079f9
Author: Vivien Malerba <malerba gnome-db org>
Date: Tue Mar 2 21:38:28 2010 +0100
Initial Data Manager perspective in Gda-Browser
configure.in | 1 +
doc/C/howto.xml | 2 +-
po/POTFILES.in | 6 +
tools/browser/Makefile.am | 4 +-
tools/browser/browser-connection.c | 48 ++-
tools/browser/browser-connection.h | 3 +
tools/browser/browser-favorites.c | 10 +-
tools/browser/browser-favorites.h | 5 +-
tools/browser/browser-stock-icons.c | 11 +-
tools/browser/browser-stock-icons.h | 1 +
tools/browser/browser-window.c | 116 +++-
tools/browser/data-manager/Makefile.am | 42 ++
tools/browser/data-manager/data-console.c | 518 ++++++++++++++
tools/browser/data-manager/data-console.h | 58 ++
.../browser/data-manager/data-favorite-selector.c | 688 ++++++++++++++++++
.../browser/data-manager/data-favorite-selector.h | 59 ++
.../data-manager/data-manager-perspective.c | 327 +++++++++
.../data-manager/data-manager-perspective.h | 56 ++
tools/browser/data-manager/data-source.c | 733 ++++++++++++++++++++
tools/browser/data-manager/data-source.h | 78 ++
tools/browser/data-manager/data-widget.c | 499 +++++++++++++
tools/browser/data-manager/data-widget.h | 59 ++
tools/browser/data-manager/marshal.list | 27 +
tools/browser/data-manager/perspective-main.c | 37 +
tools/browser/data-manager/perspective-main.h | 29 +
tools/browser/data-manager/spec-editor.c | 485 +++++++++++++
tools/browser/data-manager/spec-editor.h | 70 ++
tools/browser/data/Makefile.am | 5 +
tools/browser/data/hicolor_actions_16x16_glade.png | Bin 0 -> 527 bytes
tools/browser/data/hicolor_actions_22x22_glade.png | Bin 0 -> 1024 bytes
tools/browser/data/hicolor_actions_24x24_glade.png | Bin 0 -> 1050 bytes
tools/browser/data/hicolor_actions_32x32_glade.png | Bin 0 -> 1643 bytes
.../data/hicolor_actions_scalable_glade.svg | 648 +++++++++++++++++
tools/browser/decl.h | 1 +
tools/browser/doc/tmpl/browser-favorites.sgml | 1 +
tools/browser/main.c | 6 +-
tools/browser/mgr-favorites.c | 37 +
tools/browser/query-exec/perspective-main.c | 2 +-
tools/browser/query-exec/query-console.c | 71 +--
tools/browser/query-exec/query-console.h | 2 +-
tools/browser/query-exec/query-exec-perspective.c | 143 +----
tools/browser/query-exec/query-favorite-selector.c | 10 +-
tools/browser/support.c | 41 ++-
tools/browser/support.h | 22 +-
44 files changed, 4731 insertions(+), 230 deletions(-)
---
diff --git a/configure.in b/configure.in
index 6da2d6c..b181669 100644
--- a/configure.in
+++ b/configure.in
@@ -1764,6 +1764,7 @@ tools/browser/data/Makefile
tools/browser/common/Makefile
tools/browser/schema-browser/Makefile
tools/browser/query-exec/Makefile
+tools/browser/data-manager/Makefile
tools/browser/dummy-perspective/Makefile
tools/browser/canvas/Makefile
tools/browser/doc/Makefile
diff --git a/doc/C/howto.xml b/doc/C/howto.xml
index e3a2aaa..55300d7 100644
--- a/doc/C/howto.xml
+++ b/doc/C/howto.xml
@@ -99,7 +99,7 @@ g_object_unref (b);
<para>
<programlisting>
GdaSqlBuilder *b;
-b = gda_sql_builder_new (GDA_SQL_STATEMENT_INSERT);
+b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
gda_sql_builder_select_add_field (b, "firstname", "people", "person");
gda_sql_builder_select_add_field (b, "lastname", "people", NULL);
gda_sql_builder_select_add_field (b, "date", NULL, "birthdate");
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 75712fb..b578672 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -224,6 +224,7 @@ tools/browser/login-dialog.c
tools/browser/main.c
tools/browser/mgr-favorites.c
tools/browser/support.c
+tools/browser/support.h
tools/browser/canvas/browser-canvas-column.c
tools/browser/canvas/browser-canvas-db-relations.c
tools/browser/canvas/browser-canvas-fkey.c
@@ -233,6 +234,11 @@ tools/browser/canvas/browser-canvas.c
tools/browser/common/gdaui-data-import.c
tools/browser/common/gdaui-entry-import.c
tools/browser/common/objects-cloud.c
+tools/browser/data-manager/data-console.c
+tools/browser/data-manager/data-favorite-selector.c
+tools/browser/data-manager/data-source.c
+tools/browser/data-manager/data-widget.c
+tools/browser/data-manager/spec-editor.c
tools/browser/query-exec/gda-sql.lang
tools/browser/query-exec/query-console.c
tools/browser/query-exec/query-editor.c
diff --git a/tools/browser/Makefile.am b/tools/browser/Makefile.am
index a33dc98..ff0c5d8 100644
--- a/tools/browser/Makefile.am
+++ b/tools/browser/Makefile.am
@@ -1,7 +1,7 @@
bin_PROGRAMS=gda-browser-4.0
noinst_LTLIBRARIES = libbrowser.la
-SUBDIRS = data common schema-browser query-exec dummy-perspective
+SUBDIRS = data common schema-browser query-exec data-manager dummy-perspective
if HAVE_GOOCANVAS
SUBDIRS+=canvas
noinst_PROGRAMS=canvas-example
@@ -94,7 +94,7 @@ gda_browser_4_0_LDFLAGS = $(EXTRALDFLAGS)
gda_browser_4_0_LDADD=\
schema-browser/libperspective.la \
query-exec/libperspective.la \
- dummy-perspective/libperspective.la \
+ data-manager/libperspective.la \
libbrowser.la \
$(CANVAS_LDADD) \
common/libcommon.la \
diff --git a/tools/browser/browser-connection.c b/tools/browser/browser-connection.c
index dc2b914..0afa9cb 100644
--- a/tools/browser/browser-connection.c
+++ b/tools/browser/browser-connection.c
@@ -101,6 +101,7 @@ push_wrapper_job (BrowserConnection *bcnc, guint job_id, JobType job_type, const
wj->job_type = job_type;
if (reason)
wj->reason = g_strdup (reason);
+
bcnc->priv->wrapper_jobs = g_slist_append (bcnc->priv->wrapper_jobs, wj);
if (! bcnc->priv->wrapper_jobs->next)
@@ -713,9 +714,10 @@ browser_connection_update_meta_data (BrowserConnection *bcnc)
if (bcnc->priv->wrapper_jobs) {
WrapperJob *wj;
wj = (WrapperJob*) g_slist_last (bcnc->priv->wrapper_jobs)->data;
- if (wj->job_type == JOB_TYPE_META_STORE_UPDATE)
+ if (wj->job_type == JOB_TYPE_META_STORE_UPDATE) {
/* nothing to do */
return;
+ }
}
guint job_id;
@@ -985,6 +987,50 @@ browser_connection_execute_statement (BrowserConnection *bcnc,
return job_id;
}
+typedef struct {
+ GdaConnection *cnc;
+ GdaDataModel *model;
+} RerunSelectData;
+
+/* executed in @bcnc->priv->wrapper's sub thread */
+static gpointer
+wrapper_rerun_select (RerunSelectData *data, GError **error)
+{
+ gboolean retval;
+
+ retval = gda_data_select_rerun (GDA_DATA_SELECT (data->model), error);
+ return retval ? data->model : (gpointer) 0x01;
+}
+
+/**
+ * browser_connection_rerun_select
+ */
+guint
+browser_connection_rerun_select (BrowserConnection *bcnc,
+ GdaDataModel *model,
+ GError **error)
+{
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
+ g_return_val_if_fail (GDA_IS_DATA_SELECT (model), 0);
+
+ RerunSelectData *data;
+ guint job_id;
+
+ data = g_new0 (RerunSelectData, 1);
+ data->cnc = bcnc->priv->cnc;
+ data->model = model;
+
+ job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
+ (GdaThreadWrapperFunc) wrapper_rerun_select,
+ data, (GDestroyNotify) g_free, error);
+ if (job_id > 0)
+ push_wrapper_job (bcnc, job_id, JOB_TYPE_STATEMENT_EXECUTE,
+ _("Executing a query"));
+
+ return job_id;
+}
+
+
/**
* browser_connection_execution_get_result
* @bcnc: a #BrowserConnection
diff --git a/tools/browser/browser-connection.h b/tools/browser/browser-connection.h
index 0d057ba..3c89947 100644
--- a/tools/browser/browser-connection.h
+++ b/tools/browser/browser-connection.h
@@ -86,6 +86,9 @@ guint browser_connection_execute_statement (BrowserConnection
GdaStatementModelUsage model_usage,
gboolean need_last_insert_row,
GError **error);
+guint browser_connection_rerun_select (BrowserConnection *bcnc,
+ GdaDataModel *model,
+ GError **error);
GObject *browser_connection_execution_get_result (BrowserConnection *bcnc,
guint exec_id,
GdaSet **last_insert_row, GError **error);
diff --git a/tools/browser/browser-favorites.c b/tools/browser/browser-favorites.c
index 49d9d89..81943c2 100644
--- a/tools/browser/browser-favorites.c
+++ b/tools/browser/browser-favorites.c
@@ -209,6 +209,8 @@ favorite_type_to_string (BrowserFavoritesType type)
return "DIAGRAM";
case BROWSER_FAVORITES_QUERIES:
return "QUERY";
+ case BROWSER_FAVORITES_DATA_MANAGERS:
+ return "DATAMAN";
default:
g_warning ("Unknown type of favorite");
}
@@ -221,8 +223,12 @@ favorite_string_to_type (const gchar *str)
{
if (*str == 'T')
return BROWSER_FAVORITES_TABLES;
- else if (*str == 'D')
- return BROWSER_FAVORITES_DIAGRAMS;
+ else if (*str == 'D') {
+ if (str[1] == 'I')
+ return BROWSER_FAVORITES_DIAGRAMS;
+ else
+ return BROWSER_FAVORITES_DATA_MANAGERS;
+ }
else if (*str == 'Q')
return BROWSER_FAVORITES_QUERIES;
else
diff --git a/tools/browser/browser-favorites.h b/tools/browser/browser-favorites.h
index f74f5c9..3a0ec0e 100644
--- a/tools/browser/browser-favorites.h
+++ b/tools/browser/browser-favorites.h
@@ -45,9 +45,10 @@ typedef struct _BrowserFavoritesPrivate BrowserFavoritesPrivate;
typedef enum {
BROWSER_FAVORITES_TABLES = 1 << 0,
BROWSER_FAVORITES_DIAGRAMS = 1 << 1,
- BROWSER_FAVORITES_QUERIES = 1 << 2
+ BROWSER_FAVORITES_QUERIES = 1 << 2,
+ BROWSER_FAVORITES_DATA_MANAGERS = 1 << 3
} BrowserFavoritesType;
-#define BROWSER_FAVORITES_NB_TYPES 3
+#define BROWSER_FAVORITES_NB_TYPES 4
/**
* BrowserFavoritesAttributes:
diff --git a/tools/browser/browser-stock-icons.c b/tools/browser/browser-stock-icons.c
index bb55b6c..0fa9d4d 100644
--- a/tools/browser/browser-stock-icons.c
+++ b/tools/browser/browser-stock-icons.c
@@ -42,11 +42,12 @@ browser_stock_icons_init (void)
static const GtkStockItem items[] =
{
- { BROWSER_STOCK_HISTORY, N_("History"), 0, 0, NULL },
- { BROWSER_STOCK_BOOKMARKS, N_("Bookmarks"), 0, 0, NULL },
- { BROWSER_STOCK_BEGIN, N_("Begin"), 0, 0, NULL },
- { BROWSER_STOCK_COMMIT, N_("Commit"), 0, 0, NULL },
- { BROWSER_STOCK_ROLLBACK, N_("Rollback"), 0, 0, NULL },
+ { BROWSER_STOCK_HISTORY, N_("History"), 0, 0, NULL },
+ { BROWSER_STOCK_BOOKMARKS, N_("Bookmarks"), 0, 0, NULL },
+ { BROWSER_STOCK_BEGIN, N_("Begin"), 0, 0, NULL },
+ { BROWSER_STOCK_COMMIT, N_("Commit"), 0, 0, NULL },
+ { BROWSER_STOCK_ROLLBACK, N_("Rollback"), 0, 0, NULL },
+ { BROWSER_STOCK_BUILDER, N_("Builder"), 0, 0, NULL },
};
factory = gtk_icon_factory_new ();
diff --git a/tools/browser/browser-stock-icons.h b/tools/browser/browser-stock-icons.h
index 2ade8cf..4f132d4 100644
--- a/tools/browser/browser-stock-icons.h
+++ b/tools/browser/browser-stock-icons.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
#define BROWSER_STOCK_BEGIN "transaction-begin"
#define BROWSER_STOCK_COMMIT "transaction-commit"
#define BROWSER_STOCK_ROLLBACK "transaction-rollback"
+#define BROWSER_STOCK_BUILDER "glade"
/* Named icons defined in fd.o Icon Naming Spec */
#define STOCK_NEW_WINDOW "window-new"
diff --git a/tools/browser/browser-window.c b/tools/browser/browser-window.c
index 9298984..df38f14 100644
--- a/tools/browser/browser-window.c
+++ b/tools/browser/browser-window.c
@@ -64,6 +64,8 @@ static void connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy, gchar
static void connection_added_cb (BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin);
static void connection_removed_cb (BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin);
+static void transaction_status_changed_cb (BrowserConnection *bcnc, BrowserWindow *bwin);
+
/* get a pointer to the parents to be able to call their destructor */
static GObjectClass *parent_class = NULL;
@@ -78,6 +80,7 @@ struct _BrowserWindowPrivate {
GtkWidget *spinner;
GtkUIManager *ui_manager;
GtkActionGroup *agroup;
+ gboolean updating_transaction_status;
GtkToolbarStyle toolbar_style;
GtkActionGroup *cnc_agroup; /* one GtkAction for each BrowserConnection */
@@ -138,6 +141,7 @@ browser_window_init (BrowserWindow *bwin)
bwin->priv->cnc_agroup = NULL;
bwin->priv->cnc_added_sigid = 0;
bwin->priv->cnc_removed_sigid = 0;
+ bwin->priv->updating_transaction_status = FALSE;
}
static void
@@ -165,8 +169,12 @@ browser_window_dispose (GObject *object)
if (bwin->priv->cnc_agroup)
g_object_unref (bwin->priv->cnc_agroup);
- if (bwin->priv->bcnc)
+ if (bwin->priv->bcnc) {
+ g_signal_handlers_disconnect_by_func (bwin->priv->bcnc,
+ G_CALLBACK (transaction_status_changed_cb),
+ bwin);
g_object_unref (bwin->priv->bcnc);
+ }
if (bwin->priv->perspectives) {
g_slist_foreach (bwin->priv->perspectives, (GFunc) perspective_data_free, NULL);
g_slist_free (bwin->priv->perspectives);
@@ -189,6 +197,9 @@ delete_event (GtkWidget *widget, GdkEvent *event, BrowserWindow *bwin)
return TRUE;
}
+static void transaction_begin_cb (GtkAction *action, BrowserWindow *bwin);
+static void transaction_commit_cb (GtkAction *action, BrowserWindow *bwin);
+static void transaction_rollback_cb (GtkAction *action, BrowserWindow *bwin);
static void quit_cb (GtkAction *action, BrowserWindow *bwin);
static void about_cb (GtkAction *action, BrowserWindow *bwin);
static void window_close_cb (GtkAction *action, BrowserWindow *bwin);
@@ -211,7 +222,7 @@ 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>V", N_("Use connection to create\n"
+ { "ConnectionBind", NULL, N_("_Bind connection"), "<control>I", N_("Use connection to create\n"
"a new binding connection to access data\n"
"from multiple databases at once"), G_CALLBACK (connection_bind_cb)},
{ "ConnectionProps", GTK_STOCK_PROPERTIES, "_Properties", NULL, "Connection properties", G_CALLBACK (connection_properties_cb)},
@@ -226,7 +237,13 @@ static const GtkActionEntry ui_actions[] = {
{ "WindowNewOthers", NULL, "New window for _connection", NULL, "Open a new window for a connection", NULL},
{ "WindowClose", GTK_STOCK_CLOSE, "_Close", "", "Close this window", G_CALLBACK (window_close_cb)},
{ "Help", NULL, "_Help", NULL, "Help", NULL },
- { "HelpAbout", GTK_STOCK_ABOUT, "_About", NULL, "About", G_CALLBACK (about_cb) }
+ { "HelpAbout", GTK_STOCK_ABOUT, "_About", NULL, "About", G_CALLBACK (about_cb) },
+ { "TransactionBegin", BROWSER_STOCK_BEGIN, N_("Begin"), NULL, N_("Begin a new transaction"),
+ G_CALLBACK (transaction_begin_cb)},
+ { "TransactionCommit", BROWSER_STOCK_COMMIT, N_("Commit"), NULL, N_("Commit current transaction"),
+ G_CALLBACK (transaction_commit_cb)},
+ { "TransactionRollback", BROWSER_STOCK_ROLLBACK, N_("Rollback"), NULL, N_("Rollback current transaction"),
+ G_CALLBACK (transaction_rollback_cb)},
};
static const gchar *ui_actions_info =
@@ -241,6 +258,10 @@ static const gchar *ui_actions_info =
" <menuitem name='ConnectionBind' action= 'ConnectionBind'/>"
" <menuitem name='ConnectionClose' action= 'ConnectionClose'/>"
" <separator/>"
+ " <menuitem name='TransactionBegin' action= 'TransactionBegin'/>"
+ " <menuitem name='TransactionCommit' action= 'TransactionCommit'/>"
+ " <menuitem name='TransactionRollback' action= 'TransactionRollback'/>"
+ " <separator/>"
" <menuitem name='Quit' action= 'Quit'/>"
" <separator/>"
" </menu>"
@@ -267,6 +288,10 @@ static const gchar *ui_actions_info =
" <toolbar name='ToolBar'>"
" <toolitem action='WindowClose'/>"
" <toolitem action='WindowFullScreen'/>"
+ " <separator/>"
+ " <toolitem action='TransactionBegin'/>"
+ " <toolitem action='TransactionCommit'/>"
+ " <toolitem action='TransactionRollback'/>"
" </toolbar>"
"</ui>";
@@ -297,6 +322,9 @@ browser_window_new (BrowserConnection *bcnc, BrowserPerspectiveFactory *factory)
bwin = BROWSER_WINDOW (g_object_new (BROWSER_TYPE_WINDOW, NULL));
bwin->priv->bcnc = g_object_ref (bcnc);
+ g_signal_connect (bcnc, "transaction-status-changed",
+ G_CALLBACK (transaction_status_changed_cb), bwin);
+
cncname = browser_connection_get_name (bcnc);
if (!cncname)
cncname = _("unnamed");
@@ -333,6 +361,7 @@ browser_window_new (BrowserConnection *bcnc, BrowserPerspectiveFactory *factory)
bwin->priv->agroup = group;
gtk_action_group_add_actions (group, ui_actions, G_N_ELEMENTS (ui_actions), bwin);
gtk_action_group_add_toggle_actions (group, ui_toggle_actions, G_N_ELEMENTS (ui_toggle_actions), bwin);
+ transaction_status_changed_cb (bwin->priv->bcnc, bwin);
ui = gtk_ui_manager_new ();
gtk_ui_manager_insert_action_group (ui, group, 0);
@@ -560,6 +589,20 @@ connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy, gchar *reason, Br
action = gtk_action_group_get_action (bwin->priv->agroup, "ConnectionMetaSync");
gtk_action_set_sensitive (action, !is_busy);
+ gboolean bsens = FALSE, csens = FALSE;
+ if (!is_busy) {
+ if (browser_connection_get_transaction_status (bcnc))
+ csens = TRUE;
+ else
+ bsens = TRUE;
+ }
+ action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionBegin");
+ gtk_action_set_sensitive (action, bsens);
+ action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionCommit");
+ gtk_action_set_sensitive (action, csens);
+ action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionRollback");
+ gtk_action_set_sensitive (action, csens);
+
const gchar *cncname;
cncname = browser_connection_get_name (bcnc);
action = gtk_action_group_get_action (bwin->priv->cnc_agroup, cncname);
@@ -706,6 +749,73 @@ quit_cb (GtkAction *action, BrowserWindow *bwin)
}
static void
+transaction_status_changed_cb (BrowserConnection *bcnc, BrowserWindow *bwin)
+{
+ if (!bwin->priv->agroup)
+ return;
+
+ GtkAction *action;
+ gboolean trans_started;
+
+ trans_started = browser_connection_get_transaction_status (bcnc) ? TRUE : FALSE;
+ bwin->priv->updating_transaction_status = TRUE;
+
+ action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionBegin");
+ gtk_action_set_sensitive (action, !trans_started);
+
+ action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionCommit");
+ gtk_action_set_sensitive (action, trans_started);
+
+ action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionRollback");
+ gtk_action_set_sensitive (action, trans_started);
+
+ bwin->priv->updating_transaction_status = FALSE;
+}
+
+static void
+transaction_begin_cb (GtkAction *action, BrowserWindow *bwin)
+{
+ if (!bwin->priv->updating_transaction_status) {
+ GError *error = NULL;
+ if (! browser_connection_begin (bwin->priv->bcnc, &error)) {
+ browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)),
+ _("Error starting transaction: %s"),
+ error && error->message ? error->message : _("No detail"));
+ g_clear_error (&error);
+ }
+ }
+}
+
+static void
+transaction_commit_cb (GtkAction *action, BrowserWindow *bwin)
+{
+ if (!bwin->priv->updating_transaction_status) {
+ GError *error = NULL;
+ if (! browser_connection_commit (bwin->priv->bcnc, &error)) {
+ browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)),
+ _("Error committing transaction: %s"),
+ error && error->message ? error->message : _("No detail"));
+ g_clear_error (&error);
+ }
+ }
+}
+
+static void
+transaction_rollback_cb (GtkAction *action, BrowserWindow *bwin)
+{
+ if (!bwin->priv->updating_transaction_status) {
+ GError *error = NULL;
+ if (! browser_connection_rollback (bwin->priv->bcnc, &error)) {
+ browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)),
+ _("Error rolling back transaction: %s"),
+ error && error->message ? error->message : _("No detail"));
+ g_clear_error (&error);
+ }
+ }
+}
+
+
+static void
window_close_cb (GtkAction *action, BrowserWindow *bwin)
{
delete_event (NULL, NULL, bwin);
diff --git a/tools/browser/data-manager/Makefile.am b/tools/browser/data-manager/Makefile.am
new file mode 100644
index 0000000..275bf61
--- /dev/null
+++ b/tools/browser/data-manager/Makefile.am
@@ -0,0 +1,42 @@
+noinst_LTLIBRARIES = libperspective.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/tools/browser \
+ -I$(top_builddir) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libgda \
+ $(LIBGDA_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(GTKSOURCEVIEW_CFLAGS)
+
+marshal.h: marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=_dm_marshal > $@
+marshal.c: marshal.list $(GLIB_GENMARSHAL) marshal.h
+ $(GLIB_GENMARSHAL) $< --body --prefix=_dm_marshal > $@
+
+libperspective_la_SOURCES = \
+ marshal.c \
+ marshal.h \
+ data-console.h \
+ data-console.c \
+ data-source.h \
+ data-source.c \
+ data-widget.h \
+ data-widget.c \
+ data-favorite-selector.c \
+ data-favorite-selector.h \
+ perspective-main.c \
+ perspective-main.h \
+ spec-editor.c \
+ spec-editor.h \
+ data-manager-perspective.h \
+ data-manager-perspective.c
+
+$(OBJECTS): marshal.c marshal.h
+
+EXTRA_DIST= \
+ marshal.list
+
+CLEANFILES = \
+ marshal.h \
+ marshal.c
\ No newline at end of file
diff --git a/tools/browser/data-manager/data-console.c b/tools/browser/data-manager/data-console.c
new file mode 100644
index 0000000..79cb246
--- /dev/null
+++ b/tools/browser/data-manager/data-console.c
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2009 - 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include "data-console.h"
+#include "data-widget.h"
+#include "spec-editor.h"
+#include "../dnd.h"
+#include "../support.h"
+#include "../cc-gray-bar.h"
+#include "../browser-window.h"
+#include "../browser-page.h"
+#include "../browser-stock-icons.h"
+#include "../common/popup-container.h"
+#include <libgda/sql-parser/gda-sql-parser.h>
+#include <libgda-ui/libgda-ui.h>
+
+#define PAGE_XML 0
+#define PAGE_DATA 1
+
+typedef enum {
+ LAYOUT_HORIZ,
+ LAYOUT_VERT
+} LayoutType;
+
+struct _DataConsolePrivate {
+ LayoutType layout_type;
+ BrowserConnection *bcnc;
+ GtkWidget *notebook;
+ SpecEditor *sped;
+ GtkWidget *data_box; /* in notebook */
+ GtkWidget *data;
+ GtkActionGroup *agroup;
+
+ GtkToggleButton *params_toggle;
+ GtkWidget *params_top;
+ GtkWidget *params_form_box;
+ GtkWidget *params_form;
+};
+
+static void data_console_class_init (DataConsoleClass *klass);
+static void data_console_init (DataConsole *dconsole, DataConsoleClass *klass);
+static void data_console_dispose (GObject *object);
+static void data_console_show_all (GtkWidget *widget);
+
+/* BrowserPage interface */
+static void data_console_page_init (BrowserPageIface *iface);
+static GtkActionGroup *data_console_page_get_actions_group (BrowserPage *page);
+static const gchar *data_console_page_get_actions_ui (BrowserPage *page);
+static GtkWidget *data_console_page_get_tab_label (BrowserPage *page, GtkWidget **out_close_button);
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint data_console_signals[LAST_SIGNAL] = { };
+static GObjectClass *parent_class = NULL;
+
+/*
+ * DataConsole class implementation
+ */
+
+static void
+data_console_class_init (DataConsoleClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ GTK_WIDGET_CLASS (klass)->show_all = data_console_show_all;
+ object_class->dispose = data_console_dispose;
+}
+
+static void
+data_console_show_all (GtkWidget *widget)
+{
+ DataConsole *dconsole = (DataConsole *) widget;
+ GTK_WIDGET_CLASS (parent_class)->show_all (widget);
+
+ if (!gtk_toggle_button_get_active (dconsole->priv->params_toggle))
+ gtk_widget_hide (dconsole->priv->params_top);
+}
+
+static void
+data_console_page_init (BrowserPageIface *iface)
+{
+ iface->i_get_actions_group = data_console_page_get_actions_group;
+ iface->i_get_actions_ui = data_console_page_get_actions_ui;
+ iface->i_get_tab_label = data_console_page_get_tab_label;
+}
+
+static void
+data_console_init (DataConsole *dconsole, DataConsoleClass *klass)
+{
+ dconsole->priv = g_new0 (DataConsolePrivate, 1);
+ dconsole->priv->layout_type = LAYOUT_HORIZ;
+}
+
+static void
+data_console_dispose (GObject *object)
+{
+ DataConsole *dconsole = (DataConsole *) object;
+
+ /* free memory */
+ if (dconsole->priv) {
+ if (dconsole->priv->bcnc)
+ g_object_unref (dconsole->priv->bcnc);
+ if (dconsole->priv->agroup)
+ g_object_unref (dconsole->priv->agroup);
+ g_free (dconsole->priv);
+ dconsole->priv = NULL;
+ }
+
+ parent_class->dispose (object);
+}
+
+GType
+data_console_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo console = {
+ sizeof (DataConsoleClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) data_console_class_init,
+ NULL,
+ NULL,
+ sizeof (DataConsole),
+ 0,
+ (GInstanceInitFunc) data_console_init
+ };
+
+ static GInterfaceInfo page_console = {
+ (GInterfaceInitFunc) data_console_page_init,
+ NULL,
+ NULL
+ };
+
+ type = g_type_register_static (GTK_TYPE_VBOX, "DataConsole", &console, 0);
+ g_type_add_interface_static (type, BROWSER_PAGE_TYPE, &page_console);
+ }
+ return type;
+}
+
+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);
+
+/**
+ * data_console_new
+ *
+ * Returns: a new #GtkWidget
+ */
+GtkWidget *
+data_console_new (BrowserConnection *bcnc)
+{
+ DataConsole *dconsole;
+
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+
+ dconsole = DATA_CONSOLE (g_object_new (DATA_CONSOLE_TYPE, NULL));
+
+ dconsole->priv->bcnc = g_object_ref (bcnc);
+
+ /* header */
+ GtkWidget *label;
+ gchar *str;
+ str = g_strdup_printf ("<b>%s</b>", _("Data Manager"));
+ label = cc_gray_bar_new (str);
+ g_free (str);
+ gtk_box_pack_start (GTK_BOX (dconsole), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* main container */
+ GtkWidget *hpaned, *nb;
+ hpaned = gtk_hpaned_new ();
+ gtk_box_pack_start (GTK_BOX (dconsole), hpaned, TRUE, TRUE, 0);
+
+ /* variables */
+ GtkWidget *vbox, *sw;
+ vbox = gtk_vbox_new (FALSE, 0);
+ dconsole->priv->params_top = vbox;
+ gtk_paned_pack1 (GTK_PANED (hpaned), vbox, FALSE, TRUE);
+
+ label = gtk_label_new ("");
+ str = g_strdup_printf ("<b>%s</b>", _("Variables' values:"));
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ g_free (str);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ dconsole->priv->params_form_box = gtk_viewport_new (NULL, NULL);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (dconsole->priv->params_form_box), GTK_SHADOW_NONE);
+ gtk_container_add (GTK_CONTAINER (sw), dconsole->priv->params_form_box);
+ gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
+ gtk_widget_set_size_request (dconsole->priv->params_form_box, 250, -1);
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), VARIABLES_HELP);
+ gtk_misc_set_alignment (GTK_MISC (label), -1, 0.);
+ gtk_container_add (GTK_CONTAINER (dconsole->priv->params_form_box), label);
+ dconsole->priv->params_form = label;
+
+ /* main contents */
+ nb = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), FALSE);
+ gtk_paned_pack2 (GTK_PANED (hpaned), nb, TRUE, FALSE);
+ dconsole->priv->notebook = nb;
+
+ /* editor page */
+ GtkWidget *hbox;
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_notebook_append_page (GTK_NOTEBOOK (nb), vbox, NULL);
+
+ label = gtk_label_new ("");
+ str = g_strdup_printf ("<b>%s</b>", _("SQL code to execute:"));
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ g_free (str);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+
+ dconsole->priv->sped = spec_editor_new (dconsole->priv->bcnc);
+ gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (dconsole->priv->sped), TRUE, TRUE, 0);
+
+#define DEFAULT_XML \
+"<data>\n" \
+" <!-- This is an example of XML code, this editor will be replaced by a UI editing,\n" \
+" but will still be visible and useable for quick access\n" \
+" -->\n" \
+"\n <!-- specifies that we want the contents of the 'customers' table -->\n" \
+" <table name=\"customers\"/>\n" \
+"\n <!-- specifies that we want the contents of the 'orders' table, where the order ID \n" \
+" depends on the selected customer's ID -->\n" \
+" <table name=\"orders\">\n" \
+" <link_with>customers</link_with>\n" \
+" </table>\n" \
+"\n <!-- specifies that we want the result of the execution of a SELECT query, notice the WHERE clause\n" \
+" which enables to filter on the previously selected order ID-->\n" \
+" <query title=\"Order's products\" id=\"products\">\n" \
+" SELECT p.ref, p.name FROM products p INNER JOIN order_contents o ON (o.product_ref=p.ref) WHERE o order_id=##orders id::int\n" \
+" </query>\n" \
+"\n <!-- a more complicated query this time giving all the orders (for any customer) containing the \n" \
+" selected product from the previous SELECT query-->\n" \
+" <query title=\"All orders with this product\" id=\"aorders\">\n" \
+" SELECT distinct c.name, o.creation_date, o.delivery_date FROM customers c INNER JOIN orders o ON (o.customer=c.id) INNER JOIN order_contents oc ON (oc.order_id=o.id) INNER JOIN products p ON (oc product_ref=##products ref::string)\n" \
+" </query>\n" \
+"</data>"
+
+ spec_editor_set_xml_text (dconsole->priv->sped, DEFAULT_XML);
+
+ /* buttons */
+ GtkWidget *bbox, *button;
+ bbox = gtk_vbutton_box_new ();
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
+ gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, FALSE, 5);
+
+ button = browser_make_small_button (FALSE, _("Clear"), GTK_STOCK_CLEAR, _("Clear the editor's\ncontents"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (editor_clear_clicked_cb), dconsole);
+
+ button = browser_make_small_button (TRUE, _("Variables"), NULL, _("Show variables needed"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+ dconsole->priv->params_toggle = GTK_TOGGLE_BUTTON (button);
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (variables_clicked_cb), dconsole);
+
+ button = browser_make_small_button (FALSE, _("Execute"), GTK_STOCK_EXECUTE, _("Execute specified\n"
+ "data manager"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (execute_clicked_cb), dconsole);
+
+ button = browser_make_small_button (TRUE, _("View XML"), NULL, _("View specifications\n"
+ "as XML (advanced)"));
+ gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+ spec_editor_get_mode (dconsole->priv->sped) == SPEC_EDITOR_XML ?
+ TRUE : FALSE);
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (spec_editor_toggled_cb), dconsole);
+
+
+ /* data contents page */
+ GtkWidget *wid;
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ dconsole->priv->data_box = vbox;
+ gtk_notebook_append_page (GTK_NOTEBOOK (nb), vbox, NULL);
+
+ wid = gtk_label_new ("");
+ str = g_strdup_printf ("<b>%s</b>", _("BBB:"));
+ gtk_label_set_markup (GTK_LABEL (wid), str);
+ g_free (str);
+ gtk_misc_set_alignment (GTK_MISC (wid), 0., -1);
+
+ gtk_box_pack_start (GTK_BOX (dconsole->priv->data_box), wid, TRUE, TRUE, 0);
+ dconsole->priv->data = wid;
+
+ /* show everything */
+ gtk_widget_show_all (hpaned);
+ gtk_widget_hide (dconsole->priv->params_top);
+
+ return (GtkWidget*) dconsole;
+}
+
+static void
+execute_clicked_cb (GtkButton *button, DataConsole *dconsole)
+{
+ if (dconsole->priv->agroup) {
+ GtkAction *action;
+ action = gtk_action_group_get_action (dconsole->priv->agroup, "ComposeMode");
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
+ }
+}
+
+static void
+variables_clicked_cb (GtkToggleButton *button, DataConsole *dconsole)
+{
+ if (gtk_toggle_button_get_active (button))
+ gtk_widget_show (dconsole->priv->params_top);
+ else
+ gtk_widget_hide (dconsole->priv->params_top);
+}
+
+static void
+spec_editor_toggled_cb (GtkToggleButton *button, DataConsole *dconsole)
+{
+ if (gtk_toggle_button_get_active (button))
+ spec_editor_set_mode (dconsole->priv->sped, SPEC_EDITOR_XML);
+ else
+ spec_editor_set_mode (dconsole->priv->sped, SPEC_EDITOR_UI);
+}
+
+static void
+editor_clear_clicked_cb (GtkButton *button, DataConsole *dconsole)
+{
+ spec_editor_set_xml_text (dconsole->priv->sped, "");
+ gtk_widget_grab_focus (GTK_WIDGET (dconsole->priv->sped));
+}
+
+static GtkWidget *
+create_widget (DataConsole *dconsole, GArray *sources_array, GError **error)
+{
+ GtkWidget *sw, *vp, *dwid;
+
+ if (! sources_array) {
+ g_set_error (error, 0, 0,
+ _("No data source defined"));
+ return NULL;
+ }
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE);
+
+ vp = gtk_viewport_new (NULL, NULL);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (vp), GTK_SHADOW_NONE);
+ gtk_container_add (GTK_CONTAINER (sw), vp);
+
+ dwid = data_widget_new (sources_array);
+ gtk_container_add (GTK_CONTAINER (vp), dwid);
+
+ gtk_widget_show_all (vp);
+ return sw;
+}
+
+
+/*
+ * UI actions
+ */
+static void
+compose_mode_toggled_cb (GtkToggleAction *action, DataConsole *dconsole)
+{
+ gint pagenb;
+
+ pagenb = gtk_notebook_get_current_page (GTK_NOTEBOOK (dconsole->priv->notebook));
+ if (pagenb == PAGE_XML) {
+ /* parse XML and create the data */
+ GArray *sources_array;
+ GError *lerror = NULL;
+ sources_array = spec_editor_get_sources_array (dconsole->priv->sped, &lerror);
+ if (sources_array) {
+ if (dconsole->priv->data) {
+ /* destroy existing data widgets */
+ gtk_widget_destroy (dconsole->priv->data);
+ dconsole->priv->data = NULL;
+ }
+
+ GtkWidget *wid;
+ wid = create_widget (dconsole, sources_array, &lerror);
+ spec_editor_destroy_sources_array (sources_array);
+ if (wid) {
+ dconsole->priv->data = wid;
+ gtk_box_pack_start (GTK_BOX (dconsole->priv->data_box), wid, TRUE, TRUE, 0);
+ gtk_widget_show (wid);
+ pagenb = PAGE_DATA;
+ }
+ }
+ if (lerror) {
+ browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) dconsole),
+ lerror && lerror->message ? lerror->message :
+ _("Error parsing XML specifications"));
+ g_clear_error (&lerror);
+ }
+ }
+ else {
+ /* simply change the current page */
+ pagenb = PAGE_XML;
+ }
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (dconsole->priv->notebook), pagenb);
+}
+
+static GtkToggleActionEntry ui_actions[] = {
+ { "ComposeMode", BROWSER_STOCK_BUILDER, N_("_Toggle mode"), NULL, N_("Switch between compose and execute modes"),
+ G_CALLBACK (compose_mode_toggled_cb), TRUE},
+};
+static const gchar *ui_actions_console =
+ "<ui>"
+ " <menubar name='MenuBar'>"
+ " <placeholder name='MenuExtension'>"
+ " <menu name='Data manager' action='DataManagerMenu'>"
+ " <menuitem name='ComposeMode' action= 'ComposeMode'/>"
+ " </menu>"
+ " </placeholder>"
+ " </menubar>"
+ " <toolbar name='ToolBar'>"
+ " <separator/>"
+ " <toolitem action='ComposeMode'/>"
+ " </toolbar>"
+ "</ui>";
+
+static GtkActionGroup *
+data_console_page_get_actions_group (BrowserPage *page)
+{
+ DataConsole *dconsole;
+ dconsole = DATA_CONSOLE (page);
+ if (! dconsole->priv->agroup) {
+ dconsole->priv->agroup = gtk_action_group_new ("QueryExecConsoleActions");
+ gtk_action_group_add_toggle_actions (dconsole->priv->agroup,
+ ui_actions, G_N_ELEMENTS (ui_actions), page);
+ }
+ return g_object_ref (dconsole->priv->agroup);
+}
+
+static const gchar *
+data_console_page_get_actions_ui (BrowserPage *page)
+{
+ return ui_actions_console;
+}
+
+static GtkWidget *
+data_console_page_get_tab_label (BrowserPage *page, GtkWidget **out_close_button)
+{
+ DataConsole *dconsole;
+ const gchar *tab_name;
+
+ dconsole = DATA_CONSOLE (page);
+ tab_name = _("Data manager");
+ return browser_make_tab_label_with_stock (tab_name,
+ STOCK_CONSOLE,
+ out_close_button ? TRUE : FALSE, out_close_button);
+}
+
+/**
+ * data_console_set_text
+ */
+void
+data_console_set_text (DataConsole *console, const gchar *text)
+{
+ g_return_if_fail (IS_DATA_CONSOLE (console));
+
+ spec_editor_set_xml_text (console->priv->sped, text);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (console->priv->notebook), PAGE_XML);
+}
+
+/**
+ * data_console_get_text
+ */
+gchar *
+data_console_get_text (DataConsole *console)
+{
+ g_return_val_if_fail (IS_DATA_CONSOLE (console), NULL);
+
+ return spec_editor_get_xml_text (console->priv->sped);
+}
diff --git a/tools/browser/data-manager/data-console.h b/tools/browser/data-manager/data-console.h
new file mode 100644
index 0000000..4b5eeb3
--- /dev/null
+++ b/tools/browser/data-manager/data-console.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 - 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __DATA_CONSOLE_H__
+#define __DATA_CONSOLE_H__
+
+#include <gtk/gtk.h>
+#include "../browser-connection.h"
+
+G_BEGIN_DECLS
+
+#define DATA_CONSOLE_TYPE (data_console_get_type())
+#define DATA_CONSOLE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, DATA_CONSOLE_TYPE, DataConsole))
+#define DATA_CONSOLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, DATA_CONSOLE_TYPE, DataConsoleClass))
+#define IS_DATA_CONSOLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, DATA_CONSOLE_TYPE))
+#define IS_DATA_CONSOLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DATA_CONSOLE_TYPE))
+
+typedef struct _DataConsole DataConsole;
+typedef struct _DataConsoleClass DataConsoleClass;
+typedef struct _DataConsolePrivate DataConsolePrivate;
+
+struct _DataConsole {
+ GtkVBox parent;
+ DataConsolePrivate *priv;
+};
+
+struct _DataConsoleClass {
+ GtkVBoxClass parent_class;
+};
+
+GType data_console_get_type (void) G_GNUC_CONST;
+
+GtkWidget *data_console_new (BrowserConnection *bcnc);
+void data_console_set_text (DataConsole *console, const gchar *text);
+gchar *data_console_get_text (DataConsole *console);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/data-manager/data-favorite-selector.c b/tools/browser/data-manager/data-favorite-selector.c
new file mode 100644
index 0000000..9450e14
--- /dev/null
+++ b/tools/browser/data-manager/data-favorite-selector.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2009 - 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <libgda/gda-tree.h>
+#include "data-favorite-selector.h"
+#include "../mgr-favorites.h"
+#include <libgda-ui/gdaui-tree-store.h>
+#include "../dnd.h"
+#include "../support.h"
+#include "marshal.h"
+#include "../cc-gray-bar.h"
+#include "../browser-favorites.h"
+#include <gdk/gdkkeysyms.h>
+#include "../common/popup-container.h"
+
+#ifdef HAVE_GTKSOURCEVIEW
+ #ifdef GTK_DISABLE_SINGLE_INCLUDES
+ #undef GTK_DISABLE_SINGLE_INCLUDES
+ #endif
+
+ #include <gtksourceview/gtksourceview.h>
+ #include <gtksourceview/gtksourcelanguagemanager.h>
+ #include <gtksourceview/gtksourcebuffer.h>
+ #include <gtksourceview/gtksourcestyleschememanager.h>
+ #include <gtksourceview/gtksourcestylescheme.h>
+#endif
+
+struct _DataFavoriteSelectorPrivate {
+ BrowserConnection *bcnc;
+ GdaTree *tree;
+ GtkWidget *treeview;
+ guint idle_update_favorites;
+
+ GtkWidget *popup_menu;
+ GtkWidget *popup_properties;
+ GtkWidget *properties_name;
+ GtkWidget *properties_text;
+ gint properties_id;
+ gint properties_position;
+ guint prop_save_timeout;
+};
+
+static void data_favorite_selector_class_init (DataFavoriteSelectorClass *klass);
+static void data_favorite_selector_init (DataFavoriteSelector *tsel,
+ DataFavoriteSelectorClass *klass);
+static void data_favorite_selector_dispose (GObject *object);
+
+static void favorites_changed_cb (BrowserFavorites *bfav, DataFavoriteSelector *tsel);
+
+enum {
+ SELECTION_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint data_favorite_selector_signals[LAST_SIGNAL] = { 0 };
+static GObjectClass *parent_class = NULL;
+
+/* columns of the resulting GtkTreeModel */
+enum {
+ COLUMN_POSITION = 0,
+ COLUMN_ICON = 1,
+ COLUMN_CONTENTS = 2,
+ COLUMN_TYPE = 3,
+ COLUMN_ID = 4,
+ COLUMN_NAME = 5,
+};
+
+
+/*
+ * DataFavoriteSelector class implementation
+ */
+
+static void
+data_favorite_selector_class_init (DataFavoriteSelectorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ /* signals */
+ data_favorite_selector_signals [SELECTION_CHANGED] =
+ g_signal_new ("selection-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (DataFavoriteSelectorClass, selection_changed),
+ NULL, NULL,
+ _dm_marshal_VOID__INT_ENUM_STRING, G_TYPE_NONE,
+ 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_STRING);
+ klass->selection_changed = NULL;
+
+ object_class->dispose = data_favorite_selector_dispose;
+}
+
+
+static void
+data_favorite_selector_init (DataFavoriteSelector *tsel, DataFavoriteSelectorClass *klass)
+{
+ tsel->priv = g_new0 (DataFavoriteSelectorPrivate, 1);
+ tsel->priv->idle_update_favorites = 0;
+ tsel->priv->prop_save_timeout = 0;
+}
+
+static void
+data_favorite_selector_dispose (GObject *object)
+{
+ DataFavoriteSelector *tsel = (DataFavoriteSelector *) object;
+
+ /* free memory */
+ if (tsel->priv) {
+ if (tsel->priv->idle_update_favorites != 0)
+ g_source_remove (tsel->priv->idle_update_favorites);
+ if (tsel->priv->tree)
+ g_object_unref (tsel->priv->tree);
+
+ if (tsel->priv->bcnc) {
+ g_signal_handlers_disconnect_by_func (browser_connection_get_favorites (tsel->priv->bcnc),
+ G_CALLBACK (favorites_changed_cb), tsel);
+ g_object_unref (tsel->priv->bcnc);
+ }
+
+ if (tsel->priv->popup_properties)
+ gtk_widget_destroy (tsel->priv->popup_properties);
+ if (tsel->priv->popup_menu)
+ gtk_widget_destroy (tsel->priv->popup_menu);
+ if (tsel->priv->prop_save_timeout)
+ g_source_remove (tsel->priv->prop_save_timeout);
+
+ g_free (tsel->priv);
+ tsel->priv = NULL;
+ }
+
+ parent_class->dispose (object);
+}
+
+GType
+data_favorite_selector_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (DataFavoriteSelectorClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) data_favorite_selector_class_init,
+ NULL,
+ NULL,
+ sizeof (DataFavoriteSelector),
+ 0,
+ (GInstanceInitFunc) data_favorite_selector_init
+ };
+ type = g_type_register_static (GTK_TYPE_VBOX, "DataFavoriteSelector",
+ &info, 0);
+ }
+ return type;
+}
+
+static gboolean
+key_press_event_cb (GtkTreeView *treeview, GdkEventKey *event, DataFavoriteSelector *tsel)
+{
+ if (event->keyval == GDK_Delete) {
+ GtkTreeModel *model;
+ GtkTreeSelection *select;
+ GtkTreeIter iter;
+
+ select = gtk_tree_view_get_selection (treeview);
+ if (gtk_tree_selection_get_selected (select, &model, &iter)) {
+ BrowserFavorites *bfav;
+ BrowserFavoritesAttributes fav;
+ GError *lerror = NULL;
+
+ memset (&fav, 0, sizeof (BrowserFavoritesAttributes));
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ID, &(fav.id), -1);
+ bfav = browser_connection_get_favorites (tsel->priv->bcnc);
+ if (!browser_favorites_delete (bfav, 0, &fav, NULL)) {
+ browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*)tsel),
+ _("Could not remove favorite: %s"),
+ lerror && lerror->message ? lerror->message : _("No detail"));
+ if (lerror)
+ g_error_free (lerror);
+ }
+ }
+
+ return TRUE;
+ }
+ return FALSE; /* not handled */
+}
+
+
+static void
+selection_changed_cb (GtkTreeView *treeview, GtkTreePath *path,
+ GtkTreeViewColumn *column, DataFavoriteSelector *tsel)
+{
+ GtkTreeModel *model;
+ GtkTreeSelection *select;
+ GtkTreeIter iter;
+
+ select = gtk_tree_view_get_selection (treeview);
+ if (gtk_tree_selection_get_selected (select, &model, &iter)) {
+ gchar *str;
+ guint type;
+ gint fav_id;
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ID, &fav_id,
+ COLUMN_TYPE, &type,
+ COLUMN_CONTENTS, &str, -1);
+ g_signal_emit (tsel, data_favorite_selector_signals [SELECTION_CHANGED], 0, fav_id, type, str);
+ g_free (str);
+ }
+}
+
+static gboolean
+prop_save_timeout (DataFavoriteSelector *tsel)
+{
+ BrowserFavorites *bfav;
+ BrowserFavoritesAttributes fav;
+ GError *error = NULL;
+
+ memset (&fav, 0, sizeof (BrowserFavoritesAttributes));
+ fav.id = tsel->priv->properties_id;
+ fav.type = BROWSER_FAVORITES_DATA_MANAGERS;
+ fav.name = (gchar*) gtk_entry_get_text (GTK_ENTRY (tsel->priv->properties_name));
+ fav.descr = NULL;
+
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tsel->priv->properties_text));
+ gtk_text_buffer_get_start_iter (buffer, &start);
+ gtk_text_buffer_get_end_iter (buffer, &end);
+ fav.contents = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+
+ bfav = browser_connection_get_favorites (tsel->priv->bcnc);
+ if (! browser_favorites_add (bfav, 0, &fav, ORDER_KEY_DATA_MANAGERS, tsel->priv->properties_position, &error)) {
+ browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) tsel),
+ _("Could not add favorite: %s"),
+ error && error->message ? error->message : _("No detail"));
+ if (error)
+ g_error_free (error);
+ }
+
+ g_free (fav.contents);
+ tsel->priv->prop_save_timeout = 0;
+ return FALSE; /* remove timeout */
+}
+
+static void
+property_changed_cb (GtkWidget *multiple, DataFavoriteSelector *tsel)
+{
+ if (tsel->priv->prop_save_timeout)
+ g_source_remove (tsel->priv->prop_save_timeout);
+ tsel->priv->prop_save_timeout = g_timeout_add (100, (GSourceFunc) prop_save_timeout, tsel);
+}
+
+static void
+properties_activated_cb (GtkMenuItem *mitem, DataFavoriteSelector *tsel)
+{
+ if (! tsel->priv->popup_properties) {
+ GtkWidget *pcont, *vbox, *hbox, *label, *entry, *text, *table;
+ gchar *str;
+
+ pcont = popup_container_new (GTK_WIDGET (mitem));
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (pcont), vbox);
+
+ label = gtk_label_new ("");
+ str = g_strdup_printf ("<b>%s:</b>", _("Favorite's properties"));
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ g_free (str);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 0); /* HIG */
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
+ label = gtk_label_new (" ");
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
+
+ label = gtk_label_new ("");
+ str = g_strdup_printf ("<b>%s:</b>", _("Name"));
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ g_free (str);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new ("");
+ str = g_strdup_printf ("<b>%s:</b>", _("Specifications"));
+ gtk_label_set_markup (GTK_LABEL (label), str);
+ g_free (str);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., 0.);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
+
+ entry = gtk_entry_new ();
+ gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+ tsel->priv->properties_name = entry;
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (property_changed_cb), tsel);
+
+#ifdef HAVE_GTKSOURCEVIEW
+ text = gtk_source_view_new ();
+ gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (text))),
+ TRUE);
+ gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (text))),
+ gtk_source_language_manager_get_language (gtk_source_language_manager_get_default (),
+ "xml"));
+#else
+ text = gtk_text_view_new ();
+#endif
+ GtkWidget *sw;
+ gtk_widget_set_size_request (GTK_WIDGET (text), 400, 300);
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_table_attach_defaults (GTK_TABLE (table), sw, 1, 2, 1, 2);
+ gtk_container_add (GTK_CONTAINER (sw), text);
+ tsel->priv->properties_text = text;
+ g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)), "changed",
+ G_CALLBACK (property_changed_cb), tsel);
+
+ tsel->priv->popup_properties = pcont;
+ gtk_widget_show_all (vbox);
+ }
+
+ /* adjust contents */
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tsel->priv->treeview));
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ gchar *name, *contents;
+ GtkTextBuffer *buffer;
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ID, &(tsel->priv->properties_id),
+ COLUMN_POSITION, &(tsel->priv->properties_position),
+ COLUMN_NAME, &name,
+ COLUMN_CONTENTS, &contents, -1);
+
+ g_signal_handlers_block_by_func (tsel->priv->properties_name,
+ G_CALLBACK (property_changed_cb), tsel);
+ gtk_entry_set_text (GTK_ENTRY (tsel->priv->properties_name), name);
+ g_signal_handlers_unblock_by_func (tsel->priv->properties_name,
+ G_CALLBACK (property_changed_cb), tsel);
+ g_free (name);
+
+ g_signal_handlers_block_by_func (tsel->priv->properties_text,
+ G_CALLBACK (property_changed_cb), tsel);
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tsel->priv->properties_text));
+ if (contents)
+ gtk_text_buffer_set_text (buffer, contents, -1);
+ else
+ gtk_text_buffer_set_text (buffer, "", -1);
+ g_signal_handlers_unblock_by_func (tsel->priv->properties_text,
+ G_CALLBACK (property_changed_cb), tsel);
+ g_free (contents);
+
+ gtk_widget_show (tsel->priv->popup_properties);
+ }
+}
+
+static void
+do_popup_menu (GtkWidget *widget, GdkEventButton *event, DataFavoriteSelector *tsel)
+{
+ int button, event_time;
+
+ if (! tsel->priv->popup_menu) {
+ GtkWidget *menu, *mitem;
+
+ menu = gtk_menu_new ();
+ g_signal_connect (menu, "deactivate",
+ G_CALLBACK (gtk_widget_hide), NULL);
+
+ mitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PROPERTIES, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
+ gtk_widget_show (mitem);
+ g_signal_connect (mitem, "activate",
+ G_CALLBACK (properties_activated_cb), tsel);
+
+ tsel->priv->popup_menu = menu;
+ }
+
+ if (event) {
+ button = event->button;
+ event_time = event->time;
+ }
+ else {
+ button = 0;
+ event_time = gtk_get_current_event_time ();
+ }
+
+ gtk_menu_popup (GTK_MENU (tsel->priv->popup_menu), NULL, NULL, NULL, NULL,
+ button, event_time);
+}
+
+
+static gboolean
+popup_menu_cb (GtkWidget *widget, DataFavoriteSelector *tsel)
+{
+ do_popup_menu (widget, NULL, tsel);
+ return TRUE;
+}
+
+static gboolean
+button_press_event_cb (GtkTreeView *treeview, GdkEventButton *event, DataFavoriteSelector *tsel)
+{
+ if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
+ do_popup_menu ((GtkWidget*) treeview, event, tsel);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data);
+static gboolean idle_update_favorites (DataFavoriteSelector *tsel);
+static gboolean tree_store_drag_drop_cb (GdauiTreeStore *store, const gchar *path,
+ GtkSelectionData *selection_data, DataFavoriteSelector *tsel);
+static gboolean tree_store_drag_can_drag_cb (GdauiTreeStore *store, const gchar *path,
+ DataFavoriteSelector *tsel);
+static gboolean tree_store_drag_get_cb (GdauiTreeStore *store, const gchar *path,
+ GtkSelectionData *selection_data, DataFavoriteSelector *tsel);
+static void trash_data_received_cb (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *selection_data, guint target_type, guint time,
+ DataFavoriteSelector *tsel);
+/**
+ * data_favorite_selector_new
+ *
+ * Returns: a new #GtkWidget
+ */
+GtkWidget *
+data_favorite_selector_new (BrowserConnection *bcnc)
+{
+ DataFavoriteSelector *tsel;
+ GdaTreeManager *manager;
+
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+ tsel = DATA_FAVORITE_SELECTOR (g_object_new (DATA_FAVORITE_SELECTOR_TYPE, NULL));
+
+ tsel->priv->bcnc = g_object_ref (bcnc);
+ g_signal_connect (browser_connection_get_favorites (tsel->priv->bcnc), "favorites-changed",
+ G_CALLBACK (favorites_changed_cb), tsel);
+
+ /* create tree managers */
+ tsel->priv->tree = gda_tree_new ();
+ manager = mgr_favorites_new (bcnc, BROWSER_FAVORITES_DATA_MANAGERS, ORDER_KEY_DATA_MANAGERS);
+ gda_tree_add_manager (tsel->priv->tree, manager);
+ g_object_unref (manager);
+
+ /* update the tree's contents */
+ if (! gda_tree_update_all (tsel->priv->tree, NULL)) {
+ if (tsel->priv->idle_update_favorites == 0)
+ tsel->priv->idle_update_favorites = g_idle_add ((GSourceFunc) idle_update_favorites, tsel);
+ }
+
+ /* header */
+ GtkWidget *label;
+ gchar *str;
+ str = g_strdup_printf ("<b>%s</b>", _("Favorites"));
+ label = cc_gray_bar_new (str);
+ g_free (str);
+ cc_gray_bar_set_icon_from_pixbuf (CC_GRAY_BAR (label), browser_get_pixbuf_icon (BROWSER_ICON_BOOKMARK));
+ gtk_box_pack_start (GTK_BOX (tsel), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* tree model */
+ GtkTreeModel *model;
+ GtkWidget *treeview;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ model = gdaui_tree_store_new (tsel->priv->tree, 6,
+ G_TYPE_INT, MGR_FAVORITES_POSITION_ATT_NAME,
+ G_TYPE_OBJECT, "icon",
+ G_TYPE_STRING, MGR_FAVORITES_CONTENTS_ATT_NAME,
+ G_TYPE_UINT, MGR_FAVORITES_TYPE_ATT_NAME,
+ G_TYPE_INT, MGR_FAVORITES_ID_ATT_NAME,
+ G_TYPE_STRING, MGR_FAVORITES_NAME_ATT_NAME);
+ treeview = gtk_tree_view_new_with_model (model);
+ tsel->priv->treeview = treeview;
+ g_object_unref (model);
+
+ /* icon */
+ column = gtk_tree_view_column_new ();
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute (column, renderer, "pixbuf", COLUMN_ICON);
+ g_object_set ((GObject*) renderer, "yalign", 0., NULL);
+
+ /* text */
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_cell_data_func (column, renderer, (GtkTreeCellDataFunc) cell_data_func,
+ NULL, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+
+ /* scrolled window packing */
+ GtkWidget *sw;
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+ GTK_SHADOW_ETCHED_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (sw), treeview);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+
+ gtk_box_pack_start (GTK_BOX (tsel), sw, TRUE, TRUE, 0);
+ gtk_widget_show_all (sw);
+ g_signal_connect (G_OBJECT (treeview), "row-activated",
+ G_CALLBACK (selection_changed_cb), tsel);
+ g_signal_connect (G_OBJECT (treeview), "key-press-event",
+ G_CALLBACK (key_press_event_cb), tsel);
+ g_signal_connect (G_OBJECT (treeview), "popup-menu",
+ G_CALLBACK (popup_menu_cb), tsel);
+ g_signal_connect (G_OBJECT (treeview), "button-press-event",
+ G_CALLBACK (button_press_event_cb), tsel);
+
+ /* DnD */
+ gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (treeview), dbo_table, G_N_ELEMENTS (dbo_table),
+ GDK_ACTION_COPY);
+ gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (treeview), GDK_BUTTON1_MASK,
+ dbo_table, G_N_ELEMENTS (dbo_table),
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ g_signal_connect (model, "drag-drop",
+ G_CALLBACK (tree_store_drag_drop_cb), tsel);
+ g_signal_connect (model, "drag-can-drag",
+ G_CALLBACK (tree_store_drag_can_drag_cb), tsel);
+ g_signal_connect (model, "drag-get",
+ G_CALLBACK (tree_store_drag_get_cb), tsel);
+
+ return (GtkWidget*) tsel;
+}
+
+static void
+cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ gchar *name;
+ gchar *tmp;
+
+ gtk_tree_model_get (tree_model, iter,
+ COLUMN_NAME, &name, -1);
+ tmp = g_markup_printf_escaped ("%s", name);
+ g_free (name);
+
+ g_object_set ((GObject*) cell, "markup", tmp, NULL);
+ g_free (tmp);
+}
+
+
+static gboolean
+idle_update_favorites (DataFavoriteSelector *tsel)
+{
+ gboolean done;
+ done = gda_tree_update_all (tsel->priv->tree, NULL);
+ if (done)
+ tsel->priv->idle_update_favorites = 0;
+ else
+ tsel->priv->idle_update_favorites = g_timeout_add_seconds (1, (GSourceFunc) idle_update_favorites,
+ tsel);
+ return FALSE;
+}
+
+static gboolean
+tree_store_drag_drop_cb (GdauiTreeStore *store, const gchar *path, GtkSelectionData *selection_data,
+ DataFavoriteSelector *tsel)
+{
+ BrowserFavorites *bfav;
+ BrowserFavoritesAttributes fav;
+ GError *error = NULL;
+ gint pos;
+ gboolean retval = TRUE;
+ gint id;
+ bfav = browser_connection_get_favorites (tsel->priv->bcnc);
+
+#if GTK_CHECK_VERSION(2,18,0)
+ id = browser_favorites_find (bfav, 0, (gchar*) gtk_selection_data_get_data (selection_data),
+ &fav, NULL);
+#else
+ id = browser_favorites_find (bfav, 0, (gchar*) selection_data->data, &fav, NULL);
+#endif
+ if (id < 0) {
+ memset (&fav, 0, sizeof (BrowserFavoritesAttributes));
+ fav.id = -1;
+ fav.type = BROWSER_FAVORITES_DATA_MANAGERS;
+ fav.name = _("Unnamed data manager");
+ fav.descr = NULL;
+#if GTK_CHECK_VERSION(2,18,0)
+ fav.contents = (gchar*) gtk_selection_data_get_data (selection_data);
+#else
+ fav.contents = (gchar*) selection_data->data;
+#endif
+ }
+
+ pos = atoi (path);
+ /*g_print ("%s() path => %s, pos: %d\n", __FUNCTION__, path, pos);*/
+
+ if (! browser_favorites_add (bfav, 0, &fav, ORDER_KEY_DATA_MANAGERS, pos, &error)) {
+ browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) tsel),
+ _("Could not add favorite: %s"),
+ error && error->message ? error->message : _("No detail"));
+ if (error)
+ g_error_free (error);
+ retval = FALSE;
+ }
+
+ if (id >= 0)
+ browser_favorites_reset_attributes (&fav);
+
+ return retval;
+}
+
+static gboolean
+tree_store_drag_can_drag_cb (GdauiTreeStore *store, const gchar *path, DataFavoriteSelector *tsel)
+{
+ GdaTreeNode *node;
+ node = gda_tree_get_node (tsel->priv->tree, path, FALSE);
+ if (node) {
+ const GValue *cvalue;
+ cvalue = gda_tree_node_get_node_attribute (node, "fav_contents");
+ if (cvalue)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+tree_store_drag_get_cb (GdauiTreeStore *store, const gchar *path, GtkSelectionData *selection_data,
+ DataFavoriteSelector *tsel)
+{
+ GdaTreeNode *node;
+ node = gda_tree_get_node (tsel->priv->tree, path, FALSE);
+ if (node) {
+ const GValue *cvalue;
+ cvalue = gda_tree_node_get_node_attribute (node, "fav_contents");
+ if (cvalue) {
+ const gchar *str;
+ str = g_value_get_string (cvalue);
+#if GTK_CHECK_VERSION(2,18,0)
+ gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
+ 8, (guchar*) str, strlen (str));
+#else
+ gtk_selection_data_set (selection_data, selection_data->target,
+ 8, (guchar*) str, strlen (str));
+#endif
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+favorites_changed_cb (BrowserFavorites *bfav, DataFavoriteSelector *tsel)
+{
+ if (! gda_tree_update_all (tsel->priv->tree, NULL)) {
+ if (tsel->priv->idle_update_favorites == 0)
+ tsel->priv->idle_update_favorites = g_idle_add ((GSourceFunc) idle_update_favorites, tsel);
+
+ }
+}
diff --git a/tools/browser/data-manager/data-favorite-selector.h b/tools/browser/data-manager/data-favorite-selector.h
new file mode 100644
index 0000000..aa7a76d
--- /dev/null
+++ b/tools/browser/data-manager/data-favorite-selector.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 - 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __DATA_FAVORITE_SELECTOR_H__
+#define __DATA_FAVORITE_SELECTOR_H__
+
+#include <gtk/gtk.h>
+#include "../browser-connection.h"
+
+G_BEGIN_DECLS
+
+#define DATA_FAVORITE_SELECTOR_TYPE (data_favorite_selector_get_type())
+#define DATA_FAVORITE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, DATA_FAVORITE_SELECTOR_TYPE, DataFavoriteSelector))
+#define DATA_FAVORITE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, DATA_FAVORITE_SELECTOR_TYPE, DataFavoriteSelectorClass))
+#define IS_DATA_FAVORITE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, DATA_FAVORITE_SELECTOR_TYPE))
+#define IS_DATA_FAVORITE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DATA_FAVORITE_SELECTOR_TYPE))
+
+typedef struct _DataFavoriteSelector DataFavoriteSelector;
+typedef struct _DataFavoriteSelectorClass DataFavoriteSelectorClass;
+typedef struct _DataFavoriteSelectorPrivate DataFavoriteSelectorPrivate;
+
+struct _DataFavoriteSelector {
+ GtkVBox parent;
+ DataFavoriteSelectorPrivate *priv;
+};
+
+struct _DataFavoriteSelectorClass {
+ GtkVBoxClass parent_class;
+
+ void (*selection_changed) (DataFavoriteSelector *sel, gint fav_id,
+ BrowserFavoritesType fav_type, const gchar *fav_contents);
+};
+
+GType data_favorite_selector_get_type (void) G_GNUC_CONST;
+
+GtkWidget *data_favorite_selector_new (BrowserConnection *bcnc);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/data-manager/data-manager-perspective.c b/tools/browser/data-manager/data-manager-perspective.c
new file mode 100644
index 0000000..6fe4650
--- /dev/null
+++ b/tools/browser/data-manager/data-manager-perspective.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2009 - 2010 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 "data-manager-perspective.h"
+#include "data-console.h"
+#include "../browser-favorites.h"
+#include "../browser-window.h"
+#include "../browser-page.h"
+#include "data-favorite-selector.h"
+
+/*
+ * Main static functions
+ */
+static void data_manager_perspective_class_init (DataManagerPerspectiveClass *klass);
+static void data_manager_perspective_init (DataManagerPerspective *stmt);
+static void data_manager_perspective_dispose (GObject *object);
+
+/* BrowserPerspective interface */
+static void data_manager_perspective_perspective_init (BrowserPerspectiveIface *iface);
+static GtkActionGroup *data_manager_perspective_get_actions_group (BrowserPerspective *perspective);
+static const gchar *data_manager_perspective_get_actions_ui (BrowserPerspective *perspective);
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+struct _DataManagerPerspectivePriv {
+ GtkWidget *notebook;
+ BrowserWindow *bwin;
+ BrowserConnection *bcnc;
+};
+
+GType
+data_manager_perspective_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+ static const GTypeInfo info = {
+ sizeof (DataManagerPerspectiveClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) data_manager_perspective_class_init,
+ NULL,
+ NULL,
+ sizeof (DataManagerPerspective),
+ 0,
+ (GInstanceInitFunc) data_manager_perspective_init
+ };
+
+ static GInterfaceInfo perspective_info = {
+ (GInterfaceInitFunc) data_manager_perspective_perspective_init,
+ NULL,
+ NULL
+ };
+
+ g_static_mutex_lock (®istering);
+ if (type == 0) {
+ type = g_type_register_static (GTK_TYPE_VBOX, "DataManagerPerspective", &info, 0);
+ g_type_add_interface_static (type, BROWSER_PERSPECTIVE_TYPE, &perspective_info);
+ }
+ g_static_mutex_unlock (®istering);
+ }
+ return type;
+}
+
+static void
+data_manager_perspective_class_init (DataManagerPerspectiveClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = data_manager_perspective_dispose;
+}
+
+static void
+data_manager_perspective_perspective_init (BrowserPerspectiveIface *iface)
+{
+ iface->i_get_actions_group = data_manager_perspective_get_actions_group;
+ iface->i_get_actions_ui = data_manager_perspective_get_actions_ui;
+}
+
+
+static void
+data_manager_perspective_init (DataManagerPerspective *perspective)
+{
+ perspective->priv = g_new0 (DataManagerPerspectivePriv, 1);
+}
+
+static void fav_selection_changed_cb (GtkWidget *widget, gint fav_id, BrowserFavoritesType fav_type,
+ const gchar *selection, DataManagerPerspective *perspective);
+static void nb_switch_page_cb (GtkNotebook *nb, GtkNotebookPage *page, gint page_num,
+ DataManagerPerspective *perspective);
+static void nb_page_removed_cb (GtkNotebook *nb, GtkNotebookPage *page, gint page_num,
+ DataManagerPerspective *perspective);
+static void close_button_clicked_cb (GtkWidget *wid, GtkWidget *page_widget);
+
+/**
+ * data_manager_perspective_new
+ *
+ * Creates new #BrowserPerspective widget which
+ */
+BrowserPerspective *
+data_manager_perspective_new (BrowserWindow *bwin)
+{
+ BrowserConnection *bcnc;
+ BrowserPerspective *bpers;
+ DataManagerPerspective *perspective;
+ bpers = (BrowserPerspective*) g_object_new (TYPE_DATA_MANAGER_PERSPECTIVE, NULL);
+ perspective = (DataManagerPerspective*) bpers;
+
+ perspective->priv->bwin = bwin;
+ bcnc = browser_window_get_connection (bwin);
+ perspective->priv->bcnc = g_object_ref (bcnc);
+
+ /* contents */
+ GtkWidget *paned, *nb, *wid;
+ paned = gtk_hpaned_new ();
+ wid = data_favorite_selector_new (bcnc);
+ g_signal_connect (wid, "selection-changed",
+ G_CALLBACK (fav_selection_changed_cb), bpers);
+ gtk_paned_pack1 (GTK_PANED (paned), wid, FALSE, TRUE);
+
+ nb = gtk_notebook_new ();
+ perspective->priv->notebook = nb;
+ gtk_paned_pack2 (GTK_PANED (paned), nb, TRUE, TRUE);
+ gtk_notebook_set_scrollable (GTK_NOTEBOOK (nb), TRUE);
+ gtk_notebook_popup_enable (GTK_NOTEBOOK (nb));
+ g_signal_connect (G_OBJECT (nb), "switch-page",
+ G_CALLBACK (nb_switch_page_cb), perspective);
+ g_signal_connect (G_OBJECT (nb), "page-removed",
+ G_CALLBACK (nb_page_removed_cb), perspective);
+
+ GtkWidget *page, *tlabel, *button;
+ page = data_console_new (bcnc);
+ tlabel = browser_page_get_tab_label (BROWSER_PAGE (page), &button);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (close_button_clicked_cb), page);
+
+ gtk_notebook_append_page (GTK_NOTEBOOK (nb), page, tlabel);
+
+ gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (nb), page, TRUE);
+ gtk_notebook_set_group (GTK_NOTEBOOK (nb), bcnc + 0x02); /* add 0x01 to differentiate it from SchemaBrowser */
+ gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (perspective->priv->notebook), page,
+ TRUE);
+
+ tlabel = browser_page_get_tab_label (BROWSER_PAGE (page), NULL);
+ gtk_notebook_set_menu_label (GTK_NOTEBOOK (nb), page, tlabel);
+
+ gtk_box_pack_start (GTK_BOX (bpers), paned, TRUE, TRUE, 0);
+ gtk_widget_show_all (paned);
+
+ return bpers;
+}
+
+static DataConsole *
+add_new_data_console (BrowserPerspective *bpers)
+{
+ GtkWidget *page, *tlabel, *button;
+ DataManagerPerspective *perspective;
+ gint page_nb;
+
+ perspective = DATA_MANAGER_PERSPECTIVE (bpers);
+ page = data_console_new (perspective->priv->bcnc);
+ tlabel = browser_page_get_tab_label (BROWSER_PAGE (page), &button);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (close_button_clicked_cb), page);
+
+ page_nb = gtk_notebook_append_page (GTK_NOTEBOOK (perspective->priv->notebook), page, tlabel);
+ gtk_widget_show (page);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (perspective->priv->notebook), page_nb);
+
+ gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (perspective->priv->notebook), page,
+ TRUE);
+
+ tlabel = browser_page_get_tab_label (BROWSER_PAGE (page), NULL);
+ gtk_notebook_set_menu_label (GTK_NOTEBOOK (perspective->priv->notebook), page, tlabel);
+
+ return DATA_CONSOLE (page);
+}
+
+static void
+fav_selection_changed_cb (GtkWidget *widget, gint fav_id, BrowserFavoritesType fav_type,
+ const gchar *selection, DataManagerPerspective *perspective)
+{
+ /* find or create page for this favorite */
+ GtkWidget *page_contents;
+ gint current_page;
+ DataConsole *page_to_reuse = NULL;
+
+ current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (perspective->priv->notebook));
+ if (current_page >= 0) {
+ page_contents = gtk_notebook_get_nth_page (GTK_NOTEBOOK (perspective->priv->notebook), current_page);
+
+ if (IS_DATA_CONSOLE (page_contents)) {
+ gchar *text;
+ text = data_console_get_text (DATA_CONSOLE (page_contents));
+ if (!text || !*text)
+ page_to_reuse = DATA_CONSOLE (page_contents);
+ }
+ }
+
+ if (! page_to_reuse)
+ page_to_reuse = add_new_data_console ((BrowserPerspective*) perspective);
+
+ data_console_set_text (page_to_reuse, selection);
+}
+
+static void
+nb_switch_page_cb (GtkNotebook *nb, GtkNotebookPage *page, gint page_num,
+ DataManagerPerspective *perspective)
+{
+ GtkWidget *page_contents;
+ GtkActionGroup *actions = NULL;
+ const gchar *ui = NULL;
+
+ page_contents = gtk_notebook_get_nth_page (nb, page_num);
+ if (IS_BROWSER_PAGE (page_contents)) {
+ actions = browser_page_get_actions_group (BROWSER_PAGE (page_contents));
+ ui = browser_page_get_actions_ui (BROWSER_PAGE (page_contents));
+ }
+ browser_window_customize_perspective_ui (perspective->priv->bwin,
+ BROWSER_PERSPECTIVE (perspective), actions,
+ ui);
+ if (actions)
+ g_object_unref (actions);
+}
+
+static void
+nb_page_removed_cb (GtkNotebook *nb, GtkNotebookPage *page, gint page_num,
+ DataManagerPerspective *perspective)
+{
+ if (gtk_notebook_get_n_pages (nb) == 0) {
+ browser_window_customize_perspective_ui (perspective->priv->bwin,
+ BROWSER_PERSPECTIVE (perspective),
+ NULL, NULL);
+ }
+}
+
+static void
+close_button_clicked_cb (GtkWidget *wid, GtkWidget *page_widget)
+{
+ gtk_widget_destroy (page_widget);
+}
+
+static void
+data_manager_perspective_dispose (GObject *object)
+{
+ DataManagerPerspective *perspective;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_DATA_MANAGER_PERSPECTIVE (object));
+
+ perspective = DATA_MANAGER_PERSPECTIVE (object);
+ if (perspective->priv) {
+ if (perspective->priv->bcnc)
+ g_object_unref (perspective->priv->bcnc);
+
+ g_signal_handlers_disconnect_by_func (perspective->priv->notebook,
+ G_CALLBACK (nb_page_removed_cb), perspective);
+ g_free (perspective->priv);
+ perspective->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->dispose (object);
+}
+
+static void
+manager_new_cb (GtkAction *action, BrowserPerspective *bpers)
+{
+ add_new_data_console (bpers);
+}
+
+static GtkActionEntry ui_actions[] = {
+ { "DataManagerMenu", NULL, "_Manager", NULL, "ManagerMenu", NULL },
+ { "NewDataManager", GTK_STOCK_NEW, "_New data manager", NULL, "New data manager",
+ G_CALLBACK (manager_new_cb)},
+};
+
+static const gchar *ui_actions_info =
+ "<ui>"
+ " <menubar name='MenuBar'>"
+ " <placeholder name='MenuExtension'>"
+ " <menu name='Data manager' action='DataManagerMenu'>"
+ " <menuitem name='NewDataManager' action= 'NewDataManager'/>"
+ " </menu>"
+ " </placeholder>"
+ " </menubar>"
+ " <toolbar name='ToolBar'>"
+ " <separator/>"
+ " <toolitem action='NewDataManager'/>"
+ " </toolbar>"
+ "</ui>";
+
+static GtkActionGroup *
+data_manager_perspective_get_actions_group (BrowserPerspective *bpers)
+{
+ GtkActionGroup *agroup;
+ agroup = gtk_action_group_new ("DataManagerActions");
+ gtk_action_group_add_actions (agroup, ui_actions, G_N_ELEMENTS (ui_actions), bpers);
+
+ return agroup;
+}
+
+static const gchar *
+data_manager_perspective_get_actions_ui (BrowserPerspective *bpers)
+{
+ return ui_actions_info;
+}
diff --git a/tools/browser/data-manager/data-manager-perspective.h b/tools/browser/data-manager/data-manager-perspective.h
new file mode 100644
index 0000000..f98879a
--- /dev/null
+++ b/tools/browser/data-manager/data-manager-perspective.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 - 2010 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 __DATA_MANAGER_PERSPECTIVE_H_
+#define __DATA_MANAGER_PERSPECTIVE_H_
+
+#include <glib-object.h>
+#include "../browser-perspective.h"
+
+G_BEGIN_DECLS
+
+#define TYPE_DATA_MANAGER_PERSPECTIVE (data_manager_perspective_get_type())
+#define DATA_MANAGER_PERSPECTIVE(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, data_manager_perspective_get_type(), DataManagerPerspective)
+#define DATA_MANAGER_PERSPECTIVE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, data_manager_perspective_get_type (), DataManagerPerspectiveClass)
+#define IS_DATA_MANAGER_PERSPECTIVE(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, data_manager_perspective_get_type ())
+
+typedef struct _DataManagerPerspective DataManagerPerspective;
+typedef struct _DataManagerPerspectiveClass DataManagerPerspectiveClass;
+typedef struct _DataManagerPerspectivePriv DataManagerPerspectivePriv;
+
+/* struct for the object's data */
+struct _DataManagerPerspective
+{
+ GtkVBox object;
+ DataManagerPerspectivePriv *priv;
+};
+
+/* struct for the object's class */
+struct _DataManagerPerspectiveClass
+{
+ GtkVBoxClass parent_class;
+};
+
+GType data_manager_perspective_get_type (void) G_GNUC_CONST;
+BrowserPerspective *data_manager_perspective_new (BrowserWindow *bwin);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/data-manager/data-source.c b/tools/browser/data-manager/data-source.c
new file mode 100644
index 0000000..9c3521b
--- /dev/null
+++ b/tools/browser/data-manager/data-source.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 2009 - 2010 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-connection.h"
+#include <libgda/thread-wrapper/gda-thread-wrapper.h>
+#include "support.h"
+#include "marshal.h"
+#include <sql-parser/gda-sql-parser.h>
+#include <libgda/gda-data-model-extra.h>
+#include <libgda/gda-sql-builder.h>
+
+#include "data-source.h"
+
+
+/* signals */
+enum {
+ EXEC_STARTED,
+ EXEC_FINISHED,
+ LAST_SIGNAL
+};
+
+gint data_source_signals [LAST_SIGNAL] = {0, 0};
+
+/*
+ * Main static functions
+ */
+static void data_source_class_init (DataSourceClass *klass);
+static void data_source_init (DataSource *source);
+static void data_source_dispose (GObject *object);
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+struct _DataSourcePrivate {
+ BrowserConnection *bcnc;
+ gchar *title;
+ gchar *id;
+ GError *init_error;
+ GArray *export_names; /* array of strings, memory allocated in export_columns */
+ GHashTable *export_columns; /* key = export name, value = column number */
+
+ gchar *select_sql;
+ guint exec_id;
+
+ GdaStatement *stmt;
+ GdaSet *params;
+ gboolean need_rerun; /* set to %TRUE if @params has changed since the last exec */
+
+ GError *exec_error;
+
+ GdaDataModel *model;
+};
+
+GType
+data_source_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+ static const GTypeInfo info = {
+ sizeof (DataSourceClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) data_source_class_init,
+ NULL,
+ NULL,
+ sizeof (DataSource),
+ 0,
+ (GInstanceInitFunc) data_source_init
+ };
+
+
+ g_static_mutex_lock (®istering);
+ if (type == 0)
+ type = g_type_register_static (G_TYPE_OBJECT, "DataSource", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+ return type;
+}
+
+static void
+data_source_class_init (DataSourceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ parent_class = g_type_class_peek_parent (klass);
+
+ /* signals */
+ data_source_signals [EXEC_STARTED] =
+ g_signal_new ("execution-started",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (DataSourceClass, execution_started),
+ NULL, NULL,
+ _dm_marshal_VOID__VOID, G_TYPE_NONE, 0);
+ data_source_signals [EXEC_FINISHED] =
+ g_signal_new ("execution-finished",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (DataSourceClass, execution_finished),
+ NULL, NULL,
+ _dm_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+ klass->execution_started = NULL;
+ klass->execution_finished = NULL;
+
+ object_class->dispose = data_source_dispose;
+}
+
+static void
+data_source_init (DataSource *source)
+{
+ source->priv = g_new0 (DataSourcePrivate, 1);
+ source->priv->bcnc = NULL;
+ source->priv->need_rerun = FALSE;
+}
+
+static void
+params_changed_cb (GdaSet *params, GdaHolder *holder, DataSource *source)
+{
+ source->priv->need_rerun = TRUE;
+}
+
+static void
+data_source_dispose (GObject *object)
+{
+ DataSource *source;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_DATA_SOURCE (object));
+
+ source = DATA_SOURCE (object);
+ if (source->priv) {
+ if (source->priv->bcnc)
+ g_object_unref (source->priv->bcnc);
+ g_clear_error (& source->priv->init_error);
+ if (source->priv->stmt)
+ g_object_unref (source->priv->stmt);
+ if (source->priv->params) {
+ g_signal_handlers_disconnect_by_func (source->priv->params,
+ G_CALLBACK (params_changed_cb), source);
+ g_object_unref (source->priv->params);
+ }
+
+ g_free (source->priv->id);
+ g_free (source->priv->title);
+ g_free (source->priv->select_sql);
+
+ g_clear_error (&source->priv->exec_error);
+ if (source->priv->model)
+ g_object_unref (source->priv->model);
+
+ if (source->priv->export_names)
+ g_array_free (source->priv->export_names, TRUE);
+ if (source->priv->export_columns)
+ g_hash_table_destroy (source->priv->export_columns);
+
+ g_free (source->priv);
+ source->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->dispose (object);
+}
+
+static void init_from_query (DataSource *source, xmlNodePtr node);
+static gboolean init_from_table_node (DataSource *source, xmlNodePtr node, GError **error);
+
+/**
+ * data_source_new
+ * @bcnc: a #BrowserConnection
+ * @node:
+ * @error:
+ *
+ * Creates a new #DataSource object
+ *
+ * Returns: a new object
+ */
+DataSource*
+data_source_new_from_xml_node (BrowserConnection *bcnc, xmlNodePtr node, GError **error)
+{
+ DataSource *source;
+
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+ g_return_val_if_fail (node, NULL);
+
+ source = DATA_SOURCE (g_object_new (DATA_SOURCE_TYPE, NULL));
+ source->priv->bcnc = g_object_ref (bcnc);
+ xmlChar *prop;
+ prop = xmlGetProp (node, BAD_CAST "title");
+ if (prop) {
+ source->priv->title = g_strdup ((gchar*) prop);
+ xmlFree (prop);
+ }
+ prop = xmlGetProp (node, BAD_CAST "id");
+ if (prop) {
+ source->priv->id = g_strdup ((gchar*) prop);
+ xmlFree (prop);
+ }
+
+ if (!strcmp ((gchar*)node->name, "table")) {
+ if (! init_from_table_node (source, node, error)) {
+ g_object_unref (source);
+ source = NULL;
+ }
+ }
+ else if (!strcmp ((gchar*)node->name, "query")) {
+ init_from_query (source, node);
+ }
+ else {
+ g_set_error (error, 0, 0,
+ _("Node must be \"table\" or \"query\", and is \"%s\""), (gchar*)node->name);
+ g_object_unref (source);
+ source = NULL;
+ }
+
+ return source;
+}
+
+static void
+init_from_query (DataSource *source, xmlNodePtr node)
+{
+ GdaSqlParser *parser;
+ const gchar *remain;
+ xmlChar *contents;
+
+ contents = xmlNodeGetContent (node);
+
+ g_clear_error (& source->priv->init_error);
+ parser = browser_connection_create_parser (source->priv->bcnc);
+ if (contents) {
+ source->priv->stmt = gda_sql_parser_parse_string (parser, (gchar*) contents,
+ &remain, &source->priv->init_error);
+ xmlFree (contents);
+ }
+ g_object_unref (parser);
+
+ if (source->priv->stmt) {
+ if (remain)
+ g_set_error (& source->priv->init_error, 0, 0,
+ _("Multiple statements detected, only the first will be used"));
+
+ /* try to normalize the statement */
+ GdaSqlStatement *sqlst;
+ g_object_get ((GObject*) source->priv->stmt, "structure", &sqlst, NULL);
+ if (browser_connection_normalize_sql_statement (source->priv->bcnc, sqlst, NULL))
+ g_object_set ((GObject*) source->priv->stmt, "structure", sqlst, NULL);
+
+ /* compute export data */
+ if (source->priv->id) {
+ if (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) {
+ GdaSqlStatementSelect *selst;
+ selst = (GdaSqlStatementSelect*) sqlst->contents;
+ GSList *list;
+ gint i;
+ for (i = 0, list = selst->expr_list; list; i++, list = list->next) {
+ gchar *tmp;
+ if (! source->priv->export_names)
+ source->priv->export_names = g_array_new (FALSE, FALSE,
+ sizeof (gchar*));
+ if (! source->priv->export_columns)
+ source->priv->export_columns =
+ g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ tmp = g_strdup_printf ("%s %d", source->priv->id, i);
+ 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); */
+
+ GdaSqlSelectField *sf = (GdaSqlSelectField *) list->data;
+ if (sf->validity_meta_table_column) {
+ tmp = g_strdup_printf ("%s %s", source->priv->id,
+ sf->validity_meta_table_column->column_name);
+ 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); */
+ }
+ }
+ }
+ }
+ gda_sql_statement_free (sqlst);
+
+ /* compute parameters */
+ source->priv->need_rerun = FALSE;
+ gda_statement_get_parameters (source->priv->stmt, &source->priv->params,
+ &source->priv->init_error);
+ if (source->priv->params) {
+ GSList *list;
+ for (list = source->priv->params->holders; list; list = list->next)
+ gda_holder_set_not_null (GDA_HOLDER (list->data), FALSE);
+
+ g_signal_connect (source->priv->params, "holder-changed",
+ G_CALLBACK (params_changed_cb), source);
+ }
+ }
+}
+
+static GdaMetaTable *
+get_meta_table (DataSource *source, const gchar *table_name, GError **error)
+{
+ GdaMetaStruct *mstruct;
+ GdaMetaDbObject *dbo;
+ GValue *vname;
+
+ mstruct = browser_connection_get_meta_struct (source->priv->bcnc);
+ if (! mstruct) {
+ g_set_error (error, 0, 0,
+ _("Not ready"));
+ return NULL;
+ }
+
+ g_value_set_string ((vname = gda_value_new (G_TYPE_STRING)), table_name);
+ dbo = gda_meta_struct_get_db_object (mstruct, NULL, NULL, vname);
+ gda_value_free (vname);
+ if (! dbo) {
+ g_set_error (error, 0, 0,
+ _("Could not find the \"%s\" table"), table_name);
+ return NULL;
+ }
+ if ((dbo->obj_type != GDA_META_DB_TABLE) && (dbo->obj_type != GDA_META_DB_VIEW)) {
+ g_set_error (error, 0, 0,
+ _("The \"%s\" object is not a table"), table_name);
+ return NULL;
+ }
+ return GDA_META_TABLE (dbo);
+}
+
+static gboolean
+init_from_table_node (DataSource *source, xmlNodePtr node, GError **error)
+{
+ xmlChar *tname;
+ tname = xmlGetProp (node, BAD_CAST "name");
+ if (!tname) {
+ g_set_error (error, 0, 0,
+ _("Missing attribute \"name\" for table"));
+ return FALSE;
+ }
+
+ if (! source->priv->title)
+ source->priv->title = g_strdup_printf (_("Contents of '%s'"), (gchar*) tname);
+
+ /* locate table */
+ GdaMetaTable *mtable;
+ mtable = get_meta_table (source, (gchar*) tname, error);
+ if (!mtable) {
+ xmlFree (tname);
+ return FALSE;
+ }
+
+ /* build statement */
+ GSList *list;
+ GdaSqlBuilder *b;
+ gint i;
+
+ b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
+ if (! gda_sql_builder_select_add_target (b, (gchar*) tname, NULL)) {
+ g_set_error (error, 0, 0,
+ _("Could not build SELECT statement"));
+ xmlFree (tname);
+ return FALSE;
+ }
+
+ for (i = 0, list = mtable->columns; list; i++, list = list->next) {
+ GdaMetaTableColumn *mcol;
+ mcol = GDA_META_TABLE_COLUMN (list->data);
+ gda_sql_builder_select_add_field (b, mcol->column_name, NULL, NULL);
+
+ /* export value */
+ gchar *tmp;
+ if (source->priv->id)
+ tmp = g_strdup_printf ("%s %s", source->priv->id, mcol->column_name);
+ else
+ tmp = g_strdup_printf ("%s %s", (gchar*) tname, mcol->column_name);
+ if (! source->priv->export_names)
+ source->priv->export_names = g_array_new (FALSE, FALSE,
+ sizeof (gchar*));
+ if (! source->priv->export_columns)
+ source->priv->export_columns =
+ g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ 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);
+
+ if (source->priv->id)
+ tmp = g_strdup_printf ("%s %d", source->priv->id, i + 1);
+ else
+ tmp = g_strdup_printf ("%s %d", (gchar*) tname, i + 1);
+ 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);
+ }
+ xmlFree (tname);
+
+ /* linking */
+ xmlNodePtr subnode;
+ for (subnode = node->children; subnode; subnode = subnode->next) {
+ if (!strcmp ((gchar*)subnode->name, "link_with")) {
+ xmlChar *contents, *id;
+ GdaMetaTable *mlinked;
+
+ contents = xmlNodeGetContent (subnode);
+ mlinked = get_meta_table (source, (gchar*) contents, error);
+ if (!mlinked) {
+ xmlFree (contents);
+ g_object_unref (b);
+ return FALSE;
+ }
+ id = xmlGetProp (subnode, BAD_CAST "id");
+
+ /* find foreign key to linked table */
+ GdaMetaTableForeignKey *fk = NULL;
+ for (list = mtable->fk_list; list; list = list->next) {
+ if (GDA_META_TABLE_FOREIGN_KEY (list->data)->depend_on == GDA_META_DB_OBJECT (mlinked)) {
+ fk = GDA_META_TABLE_FOREIGN_KEY (list->data);
+ break;
+ }
+ }
+ if (!fk) {
+ g_set_error (error, 0, 0,
+ _("Could not find any foreign key to \"%s\""), (gchar*) contents);
+ xmlFree (contents);
+ if (id) xmlFree (id);
+ g_object_unref (b);
+ return FALSE;
+ }
+ else if (fk->cols_nb <= 0) {
+ g_set_error (error, 0, 0,
+ _("The fields involved in the foreign key to \"%s\" are not known"),
+ (gchar*) contents);
+ xmlFree (contents);
+ if (id) xmlFree (id);
+ g_object_unref (b);
+ return FALSE;
+ }
+ else if (fk->cols_nb == 1) {
+ gchar *tmp;
+ GdaMetaTableColumn *col;
+ col = GDA_META_TABLE_COLUMN (g_slist_nth_data (mlinked->columns, fk->fk_cols_array [0]));
+ g_assert (col);
+ gda_sql_builder_add_id (b, 1, fk->fk_names_array [0]);
+ tmp = g_strdup_printf ("%s %s", id ? (gchar*) id : (gchar*) contents,
+ fk->ref_pk_names_array [0]);
+ gda_sql_builder_add_param (b, 2, tmp, col->gtype, FALSE);
+ g_free (tmp);
+ gda_sql_builder_add_cond (b, 3, GDA_SQL_OPERATOR_TYPE_EQ, 1, 2, 0);
+ gda_sql_builder_set_where (b, 3);
+ }
+ else {
+ TO_IMPLEMENT;
+ }
+
+ xmlFree (contents);
+ if (id)
+ xmlFree (id);
+ break;
+ }
+ }
+
+ source->priv->stmt = gda_sql_builder_get_statement (b, error);
+
+ /* compute parameters */
+ gda_statement_get_parameters (source->priv->stmt, &source->priv->params,
+ &source->priv->init_error);
+ if (source->priv->params) {
+ GSList *list;
+ for (list = source->priv->params->holders; list; list = list->next)
+ gda_holder_set_not_null (GDA_HOLDER (list->data), FALSE);
+
+ g_signal_connect (source->priv->params, "holder-changed",
+ G_CALLBACK (params_changed_cb), source);
+ }
+
+ /* g_print ("SQL [%s]\n", gda_statement_to_sql (source->priv->stmt, NULL, NULL)); */
+ g_object_unref (b);
+
+ return source->priv->stmt ? TRUE : FALSE;
+}
+
+
+/**
+ * data_source_to_xml_node
+ */
+xmlNodePtr
+data_source_to_xml_node (DataSource *source)
+{
+ TO_IMPLEMENT;
+ return NULL;
+}
+
+static gboolean
+exec_end_timeout_cb (DataSource *source)
+{
+ GObject *obj;
+
+ g_clear_error (&source->priv->exec_error);
+ obj = browser_connection_execution_get_result (source->priv->bcnc,
+ source->priv->exec_id, NULL,
+ &source->priv->exec_error);
+ if (obj) {
+ if (GDA_IS_DATA_MODEL (obj)) {
+ if (source->priv->model != GDA_DATA_MODEL (obj)) {
+ if (source->priv->model)
+ g_object_unref (source->priv->model);
+ source->priv->model = GDA_DATA_MODEL (obj);
+ g_object_set (source->priv->model, "auto-reset", FALSE, NULL);
+ }
+ else {
+ gda_data_model_thaw (source->priv->model);
+ gda_data_model_reset (source->priv->model);
+ }
+ }
+ 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);
+ 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);
+ return FALSE;
+ }
+ else
+ return TRUE; /* keep timer */
+}
+
+/**
+ * data_source_execution_going_on
+ */
+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;
+}
+
+/**
+ * data_source_get_import
+ *
+ * Returns: a pointer to a read-only #GdaSet, or %NULL (must not be modified)
+ */
+GdaSet *
+data_source_get_import (DataSource *source)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+ return source->priv->params;
+}
+
+/**
+ * data_source_get_export_template
+ *
+ * Returns: an array of strings, or %NULL
+ */
+GArray *
+data_source_get_export_names (DataSource *source)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+ return source->priv->export_names;
+}
+
+/**
+ * data_source_get_export_columns
+ *
+ * Returns: a #GHashTable where key is an export name and value is its column number (use GPOINTER_TO_INT)
+ */
+GHashTable *
+data_source_get_export_columns (DataSource *source)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+ return source->priv->export_columns;
+}
+
+/**
+ * data_source_start_execution
+ */
+void
+data_source_execute (DataSource *source, GError **error)
+{
+ GError *lerror = NULL;
+ gboolean has_exec = TRUE;
+ g_return_if_fail (IS_DATA_SOURCE (source));
+
+ if (! source->priv->stmt) {
+ if (source->priv->init_error)
+ g_propagate_error (error, source->priv->init_error);
+ else
+ g_set_error (error, 0, 0,
+ _("No SELECT statement to execute"));
+ }
+
+ if (source->priv->model) {
+ if (source->priv->need_rerun) {
+ /* freeze source->priv->model to avoid that it emits signals while being in the
+ * 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);
+ }
+ 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);
+ if (has_exec) {
+ g_signal_emit (source, data_source_signals [EXEC_STARTED], 0);
+ if (! source->priv->exec_id) {
+ g_signal_emit (source, data_source_signals [EXEC_FINISHED], 0, lerror);
+ g_propagate_error (error, lerror);
+ }
+ else {
+ /* monitor the end of execution */
+ g_timeout_add (50, (GSourceFunc) exec_end_timeout_cb, source);
+ }
+ }
+}
+
+/*
+ * creates a new string where double underscores '__' are replaced by a single underscore '_'
+ */
+static gchar *
+replace_double_underscores (const gchar *str)
+{
+ gchar **arr;
+ gchar *ret;
+
+ arr = g_strsplit (str, "__", 0);
+ ret = g_strjoinv ("_", arr);
+ g_strfreev (arr);
+
+ return ret;
+}
+
+/**
+ * data_source_create_grid
+ *
+ * Returns: a new #GdauiRawGrid, or %NULL if an error occurred
+ */
+GdauiRawGrid *
+data_source_create_grid (DataSource *source)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+
+ if (! source->priv->model)
+ return NULL;
+
+ GdauiRawGrid *grid;
+ grid = (GdauiRawGrid*) gdaui_raw_grid_new (source->priv->model);
+
+ GList *columns, *list;
+ columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (grid));
+ for (list = columns; list; list = list->next) {
+ /* reduce column's title */
+ const gchar *title;
+ GtkWidget *header;
+ title = gtk_tree_view_column_get_title (GTK_TREE_VIEW_COLUMN (list->data));
+ header = gtk_label_new ("");
+ if (title) {
+ gchar *tmp, *str;
+ str = replace_double_underscores (title);
+ tmp = g_markup_printf_escaped ("<small>%s</small>", str);
+ g_free (str);
+ gtk_label_set_markup (GTK_LABEL (header), tmp);
+ g_free (tmp);
+ }
+ else
+ gtk_label_set_markup (GTK_LABEL (header), "<small></small>");
+ gtk_widget_show (header);
+ gtk_tree_view_column_set_widget (GTK_TREE_VIEW_COLUMN (list->data),
+ header);
+
+ /* reduce text's size */
+ GList *renderers, *list2;
+ renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (list->data));
+ for (list2 = renderers; list2; list2 = list2->next) {
+ if (GTK_IS_CELL_RENDERER_TEXT (list2->data))
+ g_object_set ((GObject*) list2->data,
+ "scale", 0.7, NULL);
+ }
+ g_list_free (renderers);
+ }
+
+ /*if (!columns || !columns->next)*/
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (grid), FALSE);
+ g_list_free (columns);
+ return grid;
+}
+
+/**
+ * data_source_get_title
+ */
+const gchar *
+data_source_get_title (DataSource *source)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+
+ if (source->priv->title)
+ return source->priv->title;
+ else if (source->priv->id)
+ return source->priv->id;
+ else
+ return _("No name");
+}
diff --git a/tools/browser/data-manager/data-source.h b/tools/browser/data-manager/data-source.h
new file mode 100644
index 0000000..391eca6
--- /dev/null
+++ b/tools/browser/data-manager/data-source.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 - 2010 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 __DATA_SOURCE_H_
+#define __DATA_SOURCE_H_
+
+#include <libgda-ui/libgda-ui.h>
+#include "browser-favorites.h"
+#include "decl.h"
+
+G_BEGIN_DECLS
+
+#define DATA_SOURCE_TYPE (data_source_get_type())
+#define DATA_SOURCE(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, data_source_get_type(), DataSource)
+#define DATA_SOURCE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, data_source_get_type (), DataSourceClass)
+#define IS_DATA_SOURCE(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, data_source_get_type ())
+
+typedef struct _DataSource DataSource;
+typedef struct _DataSourceClass DataSourceClass;
+typedef struct _DataSourcePrivate DataSourcePrivate;
+
+/* struct for the object's data */
+struct _DataSource
+{
+ GObject object;
+ DataSourcePrivate *priv;
+};
+
+/* struct for the object's class */
+struct _DataSourceClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*execution_started) (DataSource *source);
+ void (*execution_finished) (DataSource *source, GError *error);
+};
+
+GType data_source_get_type (void) G_GNUC_CONST;
+
+DataSource *data_source_new_from_xml_node (BrowserConnection *bcnc, xmlNodePtr node, GError **error);
+xmlNodePtr data_source_to_xml_node (DataSource *source);
+
+GdaSet *data_source_get_import (DataSource *source);
+GArray *data_source_get_export_names (DataSource *source);
+GHashTable *data_source_get_export_columns (DataSource *source);
+
+void data_source_execute (DataSource *source, GError **error);
+gboolean data_source_execution_going_on (DataSource *source);
+GdauiRawGrid *data_source_create_grid (DataSource *source);
+const gchar *data_source_get_title (DataSource *source);
+
+/*
+DataSource *data_source_new_from_table (BrowserConnection *bcnc,
+ const gchar *table_schema, const gchar *table_name);
+DataSource *data_source_new_from_select (BrowserConnection *bcnc, const gchar *select_sql);
+*/
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/data-manager/data-widget.c b/tools/browser/data-manager/data-widget.c
new file mode 100644
index 0000000..7a3bc46
--- /dev/null
+++ b/tools/browser/data-manager/data-widget.c
@@ -0,0 +1,499 @@
+/* GNOME DB library
+ * Copyright (C) 2010 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include "data-widget.h"
+#include "../browser-connection.h"
+#include "../browser-spinner.h"
+
+typedef struct {
+ DataWidget *dwid;
+ DataSource *source;
+
+ GtkWidget *top;
+ GtkNotebook *nb; /* page 0: spinner
+ page 1 or 2, depends on @data_widget_page */
+ gint data_widget_page;
+ gint error_widget_page;
+ BrowserSpinner *spinner;
+ GtkWidget *data_widget;
+ GtkWidget *error_widget;
+ GdaSet *export_data;
+
+ GSList *dep_parts; /* list of DataPart which need to be re-run when anything in @export_data
+ * changes */
+} DataPart;
+#define DATA_PART(x) ((DataPart*)(x))
+
+static DataPart *data_part_find (DataWidget *dwid, DataSource *source);
+static void data_part_free (DataPart *part);
+
+struct _DataWidgetPrivate {
+ GtkWidget *hpaned;
+ GSList *parts;
+};
+
+static void data_widget_class_init (DataWidgetClass *klass);
+static void data_widget_init (DataWidget *dwid, DataWidgetClass *klass);
+static void data_widget_dispose (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+/*
+ * DataWidget class implementation
+ */
+static void
+data_widget_class_init (DataWidgetClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = data_widget_dispose;
+}
+
+
+static void
+data_widget_init (DataWidget *dwid, DataWidgetClass *klass)
+{
+ g_return_if_fail (IS_DATA_WIDGET (dwid));
+
+ /* allocate private structure */
+ dwid->priv = g_new0 (DataWidgetPrivate, 1);
+}
+
+GType
+data_widget_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (DataWidgetClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) data_widget_class_init,
+ NULL,
+ NULL,
+ sizeof (DataWidget),
+ 0,
+ (GInstanceInitFunc) data_widget_init
+ };
+ type = g_type_register_static (GTK_TYPE_VBOX, "DataWidget", &info, 0);
+ }
+ return type;
+}
+
+static void
+data_widget_dispose (GObject *object)
+{
+ DataWidget *dwid = (DataWidget*) object;
+ if (dwid->priv) {
+ if (dwid->priv->parts) {
+ g_slist_foreach (dwid->priv->parts, (GFunc) data_part_free, NULL);
+ g_slist_free (dwid->priv->parts);
+ }
+ g_free (dwid->priv);
+ dwid->priv = NULL;
+ }
+ parent_class->dispose (object);
+}
+
+static void source_exec_started_cb (DataSource *source, DataPart *part);
+static void source_exec_finished_cb (DataSource *source, GError *error, DataPart *part);
+
+static DataPart *
+create_part (DataWidget *dwid, DataSource *source)
+{
+ DataPart *part;
+ part = g_new0 (DataPart, 1);
+ part->dwid = dwid;
+ part->source = g_object_ref (source);
+ g_signal_connect (source, "execution-started",
+ G_CALLBACK (source_exec_started_cb), part);
+ g_signal_connect (source, "execution-finished",
+ G_CALLBACK (source_exec_finished_cb), part);
+
+ dwid->priv->parts = g_slist_append (dwid->priv->parts, part);
+
+ GtkWidget *vbox;
+ vbox = gtk_vbox_new (FALSE, 0);
+ part->top = vbox;
+
+ GtkWidget *header;
+ const gchar *cstr;
+ header = gtk_label_new ("");
+ cstr = data_source_get_title (source);
+ if (cstr) {
+ gchar *tmp;
+ tmp = g_markup_printf_escaped ("<b><small>%s</small></b>", cstr);
+ gtk_label_set_markup (GTK_LABEL (header), tmp);
+ g_free (tmp);
+ }
+ else
+ gtk_label_set_markup (GTK_LABEL (header), "<b><small> </small></b>");
+ gtk_misc_set_alignment (GTK_MISC (header), 0., -1);
+ gtk_widget_set_size_request (header, 150, -1);
+ gtk_label_set_ellipsize (GTK_LABEL (header), PANGO_ELLIPSIZE_END);
+ gtk_box_pack_start (GTK_BOX (vbox), header, FALSE, FALSE, 0);
+
+ GtkWidget *nb;
+ nb = gtk_notebook_new ();
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (nb), FALSE);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), FALSE);
+ part->nb = GTK_NOTEBOOK (nb);
+
+ part->spinner = BROWSER_SPINNER (browser_spinner_new ());
+ gtk_notebook_append_page (GTK_NOTEBOOK (nb), GTK_WIDGET (part->spinner), NULL);
+ part->data_widget = NULL;
+
+ gtk_box_pack_start (GTK_BOX (vbox), nb, TRUE, TRUE, 0);
+
+ gtk_widget_show_all (vbox);
+ if (data_source_execution_going_on (source))
+ source_exec_started_cb (source, part);
+
+ return part;
+}
+
+/* make a super-container to contain @size items: the list
+ * will have @size-2 paned widgets */
+GSList *
+make_paned_list (gint size, gboolean horiz)
+{
+ GSList *list = NULL;
+ gint i;
+ GtkWidget *paned;
+
+ g_assert (size >= 2);
+ paned = horiz ? gtk_hpaned_new () : gtk_vpaned_new ();
+ list = g_slist_prepend (list, paned);
+
+ for (i = 2; i < size; i++) {
+ GtkWidget *paned2;
+ paned2 = horiz ? gtk_hpaned_new () : gtk_vpaned_new ();
+ gtk_paned_add2 (GTK_PANED (paned), paned2);
+ list = g_slist_prepend (list, paned2);
+ paned = paned2;
+ }
+ return g_slist_reverse (list);
+}
+
+static void
+pack_in_paned_list (GSList *paned_list, gint length, gint pos, GtkWidget *wid)
+{
+ GtkPaned *paned;
+ if (pos < length - 1) {
+ paned = g_slist_nth_data (paned_list, pos);
+ gtk_paned_add1 (paned, wid);
+ }
+ else {
+ paned = g_slist_nth_data (paned_list, pos - 1);
+ gtk_paned_add2 (paned, wid);
+ }
+}
+
+/**
+ * data_widget_new
+ *
+ * Returns: the newly created widget.
+ */
+GtkWidget *
+data_widget_new (GArray *sources_array)
+{
+ DataWidget *dwid;
+
+ g_return_val_if_fail (sources_array, NULL);
+ dwid = g_object_new (DATA_WIDGET_TYPE, NULL);
+
+ if (sources_array->len == 1) {
+ GArray *subarray = g_array_index (sources_array, GArray*, 0);
+ if (subarray->len == 1) {
+ DataPart *part;
+ DataSource *source;
+ source = g_array_index (subarray, DataSource*, 0);
+ part = create_part (dwid, source);
+ gtk_box_pack_start (GTK_BOX (dwid), part->top, TRUE, TRUE, 0);
+
+ data_source_execute (source, NULL);
+ }
+ else {
+ GSList *paned_list;
+ gint i;
+ paned_list = make_paned_list (subarray->len, FALSE);
+ gtk_box_pack_start (GTK_BOX (dwid), GTK_WIDGET (paned_list->data), TRUE, TRUE, 0);
+ for (i = 0; i < subarray->len; i++) {
+ DataPart *part;
+ DataSource *source;
+ source = g_array_index (subarray, DataSource*, i);
+ part = create_part (dwid, source);
+ pack_in_paned_list (paned_list, subarray->len, i, part->top);
+
+ data_source_execute (source, NULL);
+ }
+ g_slist_free (paned_list);
+ }
+ }
+ else {
+ GSList *top_paned_list;
+ gint j;
+
+ top_paned_list = make_paned_list (sources_array->len, TRUE);
+ gtk_box_pack_start (GTK_BOX (dwid), GTK_WIDGET (top_paned_list->data), TRUE, TRUE, 0);
+ for (j = 0; j < sources_array->len; j++) {
+ GArray *subarray = g_array_index (sources_array, GArray*, j);
+ DataSource *source;
+
+ if (subarray->len == 1) {
+ DataPart *part;
+ source = g_array_index (subarray, DataSource*, 0);
+ part = create_part (dwid, source);
+ pack_in_paned_list (top_paned_list, sources_array->len, j, part->top);
+
+ data_source_execute (source, NULL);
+ }
+ else {
+ GSList *paned_list;
+ gint i;
+ paned_list = make_paned_list (subarray->len, FALSE);
+ pack_in_paned_list (top_paned_list, sources_array->len, j,
+ GTK_WIDGET (paned_list->data));
+ for (i = 0; i < subarray->len; i++) {
+ DataPart *part;
+ source = g_array_index (subarray, DataSource*, i);
+ part = create_part (dwid, source);
+ pack_in_paned_list (paned_list, subarray->len, i, part->top);
+
+ data_source_execute (source, NULL);
+ }
+ g_slist_free (paned_list);
+ }
+ }
+ g_slist_free (top_paned_list);
+ }
+
+ return GTK_WIDGET (dwid);
+}
+
+static void
+data_part_free (DataPart *part)
+{
+ if (part->source)
+ g_object_unref (part->source);
+ if (part->export_data)
+ g_object_unref (part->export_data);
+ if (part->dep_parts)
+ g_slist_free (part->dep_parts);
+ g_free (part);
+}
+
+static DataPart *
+data_part_find (DataWidget *dwid, DataSource *source)
+{
+ GSList *list;
+ for (list = dwid->priv->parts; list; list = list->next) {
+ if (DATA_PART (list->data)->source == source)
+ return DATA_PART (list->data);
+ }
+ return NULL;
+}
+
+static void
+source_exec_started_cb (DataSource *source, DataPart *part)
+{
+ gtk_notebook_set_current_page (part->nb, 0);
+ browser_spinner_start (part->spinner);
+}
+
+static void data_part_selection_changed_cb (GdauiDataSelector *gdauidataselector, DataPart *part);
+static void compute_sources_dependencies (DataPart *part);
+static void
+source_exec_finished_cb (DataSource *source, GError *error, DataPart *part)
+{
+ GtkWidget *wid;
+ browser_spinner_stop (part->spinner);
+
+ /*g_print ("Execution of source [%s] finished\n", data_source_get_title (part->source));*/
+ if (error) {
+ gchar *tmp;
+ tmp = g_markup_printf_escaped ("\n<b>Error:\n</b>%s",
+ error->message ? error->message : _("Error: no detail"));
+ if (! part->error_widget) {
+ part->error_widget = gtk_label_new ("");
+ gtk_misc_set_alignment (GTK_MISC (part->error_widget), 0., 0.);
+ part->error_widget_page = gtk_notebook_append_page (part->nb, part->error_widget,
+ NULL);
+ gtk_widget_show (part->error_widget);
+ }
+ gtk_label_set_markup (GTK_LABEL (part->error_widget), tmp);
+ g_free (tmp);
+ gtk_notebook_set_current_page (part->nb, part->error_widget_page);
+ return;
+ }
+
+ if (! part->data_widget) {
+ wid = (GtkWidget*) data_source_create_grid (part->source);
+ part->data_widget = wid;
+ part->data_widget_page = gtk_notebook_append_page (part->nb, wid, NULL);
+ gtk_widget_show (part->data_widget);
+ g_print ("Creating data widget for source [%s]\n", data_source_get_title (part->source));
+
+ /* compute part->export_data */
+ GArray *export_names;
+ export_names = data_source_get_export_names (part->source);
+ if (export_names && (export_names->len > 0)) {
+ GSList *holders = NULL;
+ GdaDataModel *model;
+ GHashTable *export_columns;
+ gint i;
+ GdaDataModelIter *iter;
+
+ iter = gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (wid));
+ g_object_get (wid, "model", &model, NULL);
+
+ export_columns = data_source_get_export_columns (part->source);
+ for (i = 0; i < export_names->len; i++) {
+ gint col;
+ GdaHolder *bindto;
+ col = GPOINTER_TO_INT (g_hash_table_lookup (export_columns,
+ g_array_index (export_names,
+ gchar*, i))) - 1;
+ bindto = gda_data_model_iter_get_holder_for_field (iter, col);
+ if (bindto) {
+ GdaHolder *holder;
+ holder = gda_holder_copy (bindto);
+ g_object_set ((GObject*) holder, "id",
+ g_array_index (export_names, gchar*, i), NULL);
+ holders = g_slist_prepend (holders, holder);
+#ifdef DEBUG_NO
+ g_print ("HOLDER [%s::%s]\n",
+ gda_holder_get_id (holder),
+ g_type_name (gda_holder_get_g_type (holder)));
+#endif
+ g_assert (gda_holder_set_bind (holder, bindto, NULL));
+ }
+ }
+
+ g_object_unref (model);
+ if (holders) {
+ part->export_data = gda_set_new (holders);
+ g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
+ g_slist_free (holders);
+
+ g_signal_connect (wid, "selection-changed",
+ G_CALLBACK (data_part_selection_changed_cb), part);
+ }
+ }
+ }
+ gtk_notebook_set_current_page (part->nb, part->data_widget_page);
+ compute_sources_dependencies (part);
+}
+
+static void
+data_part_selection_changed_cb (GdauiDataSelector *gdauidataselector, DataPart *part)
+{
+ if (part->export_data) {
+ GSList *list;
+#ifdef DEBUG_NO
+ for (list = part->export_data->holders; list; list = list->next) {
+ GdaHolder *holder = GDA_HOLDER (list->data);
+ gchar *tmp;
+ tmp = gda_value_stringify (gda_holder_get_value (holder));
+ g_print ("%s=>[%s]\n", gda_holder_get_id (holder), tmp);
+ g_free (tmp);
+ }
+#endif
+
+ for (list = part->dep_parts; list; list = list->next) {
+ DataPart *spart = DATA_PART (list->data);
+ data_source_execute (spart->source, NULL);
+ }
+ }
+}
+
+static void
+compute_sources_dependencies (DataPart *part)
+{
+ GdaSet *import;
+ import = data_source_get_import (part->source);
+ if (!import)
+ return;
+
+ GSList *holders;
+ for (holders = import->holders; holders; holders = holders->next) {
+ GdaHolder *holder = (GdaHolder*) holders->data;
+ const gchar *hid = gda_holder_get_id (holder);
+ GSList *list;
+
+ for (list = part->dwid->priv->parts; list; list = list->next) {
+ DataPart *opart = DATA_PART (list->data);
+ if (opart == part)
+ continue;
+
+ GdaSet *export;
+ GdaHolder *holder2;
+ export = data_widget_get_export (part->dwid, opart->source);
+ if (!export)
+ continue;
+
+ holder2 = gda_set_get_holder (export, hid);
+ if (holder2) {
+ GError *lerror = NULL;
+ if (! gda_holder_set_bind (holder, holder2, &lerror)) {
+ TO_IMPLEMENT;
+ g_print ("Error: %s\n", lerror && lerror->message ?
+ lerror->message : "???");
+ g_clear_error (&lerror);
+ }
+ g_print ("[%s.][%s] bound to [%s].[%s]\n",
+ data_source_get_title (part->source),
+ hid,
+ data_source_get_title (opart->source),
+ gda_holder_get_id (holder2));
+
+ if (! g_slist_find (opart->dep_parts, part))
+ opart->dep_parts = g_slist_append (opart->dep_parts, part);
+ continue;
+ }
+ }
+ }
+}
+
+/**
+ * data_widget_get_export
+ *
+ * Returns: the #GdaSet or %NULL, no ref held to it by the caller
+ */
+GdaSet *
+data_widget_get_export (DataWidget *dwid, DataSource *source)
+{
+ DataPart *part;
+ g_return_val_if_fail (IS_DATA_WIDGET (dwid), NULL);
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+ part = data_part_find (dwid, source);
+ if (!part) {
+ g_warning ("Can't find DataPart for DataSource");
+ return NULL;
+ }
+ return part->export_data;
+}
diff --git a/tools/browser/data-manager/data-widget.h b/tools/browser/data-manager/data-widget.h
new file mode 100644
index 0000000..03bb1b3
--- /dev/null
+++ b/tools/browser/data-manager/data-widget.h
@@ -0,0 +1,59 @@
+/* GNOME DB library
+ * Copyright (C) 2010 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __DATA_WIDGET_H__
+#define __DATA_WIDGET_H__
+
+#include <gtk/gtk.h>
+#include <libgda/libgda.h>
+#include "data-source.h"
+
+G_BEGIN_DECLS
+
+#define DATA_WIDGET_TYPE (data_widget_get_type())
+#define DATA_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, DATA_WIDGET_TYPE, DataWidget))
+#define DATA_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, DATA_WIDGET_TYPE, DataWidgetClass))
+#define IS_DATA_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, DATA_WIDGET_TYPE))
+#define IS_DATA_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DATA_WIDGET_TYPE))
+
+
+typedef struct _DataWidget DataWidget;
+typedef struct _DataWidgetClass DataWidgetClass;
+typedef struct _DataWidgetPrivate DataWidgetPrivate;
+
+struct _DataWidget {
+ GtkVBox parent;
+ DataWidgetPrivate *priv;
+};
+
+struct _DataWidgetClass {
+ GtkVBoxClass parent_class;
+};
+
+
+GType data_widget_get_type (void) G_GNUC_CONST;
+GtkWidget *data_widget_new (GArray *sources_array);
+GdaSet *data_widget_get_export (DataWidget *dwid, DataSource *source);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/data-manager/marshal.list b/tools/browser/data-manager/marshal.list
new file mode 100644
index 0000000..9ab3792
--- /dev/null
+++ b/tools/browser/data-manager/marshal.list
@@ -0,0 +1,27 @@
+# see glib-genmarshal(1) for a detailed description of the file format,
+# possible parameter types are:
+# VOID indicates no return type, or no extra
+# parameters. if VOID is used as the parameter
+# list, no additional parameters may be present.
+# BOOLEAN for boolean types (gboolean)
+# CHAR for signed char types (gchar)
+# UCHAR for unsigned char types (guchar)
+# INT for signed integer types (gint)
+# UINT for unsigned integer types (guint)
+# LONG for signed long integer types (glong)
+# ULONG for unsigned long integer types (gulong)
+# ENUM for enumeration types (gint)
+# FLAGS for flag enumeration types (guint)
+# FLOAT for single-precision float types (gfloat)
+# DOUBLE for double-precision float types (gdouble)
+# STRING for string types (gchar*)
+# PARAM for GParamSpec or derived types (GParamSpec*)
+# BOXED for boxed (anonymous but reference counted) types (GBoxed*)
+# POINTER for anonymous pointer types (gpointer)
+# OBJECT for GObject or derived types (GObject*)
+# NONE deprecated alias for VOID
+# BOOL deprecated alias for BOOLEAN
+
+VOID:VOID
+VOID:POINTER
+VOID:INT,ENUM,STRING
diff --git a/tools/browser/data-manager/perspective-main.c b/tools/browser/data-manager/perspective-main.c
new file mode 100644
index 0000000..3d1df2b
--- /dev/null
+++ b/tools/browser/data-manager/perspective-main.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 - 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include "perspective-main.h"
+#include "data-manager-perspective.h"
+
+static BrowserPerspectiveFactory bfact;
+
+BrowserPerspectiveFactory *
+data_manager_perspective_get_factory (void)
+{
+ bfact.perspective_name = "Data manager";
+ bfact.menu_shortcut ="<control>D";
+ bfact.perspective_create = data_manager_perspective_new;
+
+ return &bfact;
+}
diff --git a/tools/browser/data-manager/perspective-main.h b/tools/browser/data-manager/perspective-main.h
new file mode 100644
index 0000000..3a2e085
--- /dev/null
+++ b/tools/browser/data-manager/perspective-main.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 - 2010 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "../decl.h"
+
+G_BEGIN_DECLS
+
+BrowserPerspectiveFactory *data_manager_perspective_get_factory (void);
+
+G_END_DECLS
+
diff --git a/tools/browser/data-manager/spec-editor.c b/tools/browser/data-manager/spec-editor.c
new file mode 100644
index 0000000..dabc74b
--- /dev/null
+++ b/tools/browser/data-manager/spec-editor.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2010 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include "spec-editor.h"
+#include "data-source.h"
+#include <libgda/libgda.h>
+#include "../support.h"
+
+#ifdef HAVE_GTKSOURCEVIEW
+ #ifdef GTK_DISABLE_SINGLE_INCLUDES
+ #undef GTK_DISABLE_SINGLE_INCLUDES
+ #endif
+
+ #include <gtksourceview/gtksourceview.h>
+ #include <gtksourceview/gtksourcelanguagemanager.h>
+ #include <gtksourceview/gtksourcebuffer.h>
+ #include <gtksourceview/gtksourcestyleschememanager.h>
+ #include <gtksourceview/gtksourcestylescheme.h>
+#endif
+
+struct _SpecEditorPrivate {
+ BrowserConnection *bcnc;
+
+ SpecEditorMode mode;
+ GtkNotebook *notebook;
+
+ guint params_compute_id; /* timout ID to compute params */
+
+ /* reference for all views */
+ xmlDocPtr doc;
+
+ /* XML view */
+ gboolean xml_view_up_to_date;
+ GtkWidget *text;
+ GtkTextBuffer *buffer;
+
+ /* UI view */
+ gboolean ui_view_up_to_date;
+};
+
+static void spec_editor_class_init (SpecEditorClass *klass);
+static void spec_editor_init (SpecEditor *sped, SpecEditorClass *klass);
+static void spec_editor_dispose (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+/*
+ * SpecEditor class implementation
+ */
+static void
+spec_editor_class_init (SpecEditorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = spec_editor_dispose;
+}
+
+
+static void
+spec_editor_init (SpecEditor *sped, SpecEditorClass *klass)
+{
+ g_return_if_fail (IS_SPEC_EDITOR (sped));
+
+ /* allocate private structure */
+ sped->priv = g_new0 (SpecEditorPrivate, 1);
+ sped->priv->params_compute_id = 0;
+ sped->priv->mode = SPEC_EDITOR_XML;
+}
+
+GType
+spec_editor_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (SpecEditorClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) spec_editor_class_init,
+ NULL,
+ NULL,
+ sizeof (SpecEditor),
+ 0,
+ (GInstanceInitFunc) spec_editor_init
+ };
+ type = g_type_register_static (GTK_TYPE_VBOX, "SpecEditor", &info, 0);
+ }
+ return type;
+}
+
+static void
+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->bcnc)
+ g_object_unref (sped->priv->bcnc);
+
+ if (sped->priv->doc)
+ xmlFreeDoc (sped->priv->doc);
+ g_free (sped->priv);
+ sped->priv = NULL;
+ }
+ parent_class->dispose (object);
+}
+
+static gboolean
+compute_params (SpecEditor *sped)
+{
+ TO_IMPLEMENT;
+
+ /* remove timeout */
+ sped->priv->params_compute_id = 0;
+ return FALSE;
+}
+
+
+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);
+}
+
+/**
+ * spec_editor_new
+ *
+ * Returns: the newly created editor.
+ */
+SpecEditor *
+spec_editor_new (BrowserConnection *bcnc)
+{
+ SpecEditor *sped;
+ GtkWidget *sw, *nb;
+
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+
+ sped = g_object_new (SPEC_EDITOR_TYPE, NULL);
+ sped->priv->bcnc = g_object_ref (bcnc);
+
+ nb = gtk_notebook_new ();
+ gtk_box_pack_start (GTK_BOX (sped), nb, TRUE, TRUE, 0);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (nb), FALSE);
+ sped->priv->notebook = (GtkNotebook*) nb;
+
+ /* XML editor page */
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_OUT);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ gtk_notebook_append_page (GTK_NOTEBOOK (nb), sw, NULL);
+
+#ifdef HAVE_GTKSOURCEVIEW
+ sped->priv->text = gtk_source_view_new ();
+ gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (sped->priv->text))),
+ TRUE);
+
+ gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (sped->priv->text))),
+ gtk_source_language_manager_get_language (gtk_source_language_manager_get_default (),
+ "xml"));
+#else
+ sped->priv->text = gtk_text_view_new ();
+#endif
+ gtk_container_add (GTK_CONTAINER (sw), sped->priv->text);
+ sped->priv->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (sped->priv->text));
+
+ g_signal_connect (sped->priv->buffer, "changed",
+ G_CALLBACK (editor_changed_cb), sped);
+
+ /* UI page */
+ GtkWidget *wid;
+ wid = gtk_label_new ("TODO");
+ gtk_notebook_append_page (GTK_NOTEBOOK (nb), wid, NULL);
+
+ gtk_widget_show_all (nb);
+
+ return SPEC_EDITOR (sped);
+}
+
+/**
+ * spec_editor_set_xml_text
+ */
+void
+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);
+}
+
+gchar *
+spec_editor_get_xml_text (SpecEditor *sped)
+{
+ GtkTextIter start, end;
+ g_return_val_if_fail (IS_SPEC_EDITOR (sped), NULL);
+ gtk_text_buffer_get_start_iter (sped->priv->buffer, &start);
+ gtk_text_buffer_get_end_iter (sped->priv->buffer, &end);
+
+ return gtk_text_buffer_get_text (sped->priv->buffer, &start, &end, FALSE);
+}
+
+/**
+ * spec_editor_set_mode
+ */
+void
+spec_editor_set_mode (SpecEditor *sped, SpecEditorMode mode)
+{
+ g_return_if_fail (IS_SPEC_EDITOR (sped));
+ switch (mode) {
+ case SPEC_EDITOR_XML:
+ gtk_notebook_set_current_page (sped->priv->notebook, 0);
+ break;
+ case SPEC_EDITOR_UI:
+ gtk_notebook_set_current_page (sped->priv->notebook, 1);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * spec_editor_get_mode
+ */
+SpecEditorMode
+spec_editor_get_mode (SpecEditor *sped)
+{
+ g_return_val_if_fail (IS_SPEC_EDITOR (sped), SPEC_EDITOR_UI);
+ return sped->priv->mode;
+}
+
+static GArray *compute_sources (SpecEditor *sped, GError **error);
+
+
+/**
+ * spec_editor_get_sources_array
+ */
+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);
+ }
+ return compute_sources (sped, error);
+}
+
+/**
+ * spec_editor_destroy_sources_array
+ */
+void
+spec_editor_destroy_sources_array (GArray *array)
+{
+ gint i;
+ for (i = 0; i < array->len; i++) {
+ GArray *subarray;
+ subarray = g_array_index (array, GArray *, i);
+ gint j;
+ for (j = 0; j < subarray->len; j++) {
+ DataSource *source;
+ source = g_array_index (subarray, DataSource *, j);
+ g_object_unref (source);
+ }
+
+ g_array_free (subarray, TRUE);
+ }
+ g_array_free (array, TRUE);
+}
+
+/*
+ * Tells if @source1 has an import which can be satisfied by an export in @source2
+ * Returns: %TRUE if there is a dependency
+ */
+static gboolean
+source_depends_on (DataSource *source1, DataSource *source2)
+{
+ GdaSet *import;
+ import = data_source_get_import (source1);
+ if (!import)
+ return FALSE;
+
+ GSList *holders;
+ GHashTable *export_columns;
+ export_columns = data_source_get_export_columns (source2);
+ for (holders = import->holders; holders; holders = holders->next) {
+ GdaHolder *holder = (GdaHolder*) holders->data;
+ if (GPOINTER_TO_INT (g_hash_table_lookup (export_columns, gda_holder_get_id (holder))) >= 1)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Returns: an array of arrays of pointer to the #DataSource objects
+ *
+ * No ref is actually held by any of these pointers, all refs to DataSource are held by
+ * the @sources_list pointers
+ */
+static GArray *
+create_sources_array (GSList *sources_list, GError **error)
+{
+ GSList *list;
+ GArray *array = NULL;
+ g_print ("** Creating DataSource arrays\n");
+ for (list = sources_list; list; list = list->next) {
+ DataSource *source;
+ source = DATA_SOURCE (g_object_ref (G_OBJECT (list->data)));
+ g_print ("Taking into account source [%s]\n",
+ data_source_get_title (source));
+
+ GdaSet *import;
+ import = data_source_get_import (source);
+ if (!import) {
+ if (! array) {
+ array = g_array_new (FALSE, FALSE, sizeof (GArray*));
+ GArray *subarray = g_array_new (FALSE, FALSE, sizeof (DataSource*));
+ g_array_append_val (array, subarray);
+ g_array_append_val (subarray, source);
+ }
+ else {
+ GArray *subarray = g_array_index (array, GArray*, 0);
+ g_array_append_val (subarray, source);
+ }
+ continue;
+ }
+
+ if (array) {
+ gint i;
+ gboolean dep_found = FALSE;
+ for (i = array->len - 1; i >= 0 ; i--) {
+ GArray *subarray = g_array_index (array, GArray*, i);
+ gint j;
+ for (j = 0; j < subarray->len; j++) {
+ DataSource *source2 = g_array_index (subarray, DataSource*, j);
+ g_print ("Source [%s] %s on source [%s]\n",
+ data_source_get_title (source),
+ source_depends_on (source, source2) ?
+ "depends" : "does not depend",
+ data_source_get_title (source2));
+ if (source_depends_on (source, source2)) {
+ dep_found = TRUE;
+ /* add source to column i+1 */
+ if (i == array->len - 1) {
+ GArray *subarray = g_array_new (FALSE, FALSE,
+ sizeof (DataSource*));
+ g_array_append_val (array, subarray);
+ g_array_append_val (subarray, source);
+ }
+ else {
+ GArray *subarray = g_array_index (array, GArray*, i+1);
+ g_array_append_val (subarray, source);
+ }
+ continue;
+ }
+ }
+
+ if (dep_found)
+ break;
+ }
+ if (! dep_found) {
+ /* add source to column 0 */
+ GArray *subarray = g_array_index (array, GArray*, 0);
+ g_array_append_val (subarray, source);
+ }
+ }
+ else {
+ /* add source to column 0 */
+ array = g_array_new (FALSE, FALSE, sizeof (GArray*));
+ GArray *subarray = g_array_new (FALSE, FALSE, sizeof (DataSource*));
+ g_array_append_val (array, subarray);
+ g_array_append_val (subarray, source);
+ }
+ }
+
+ g_print ("** DataSource arrays created\n");
+ return array;
+}
+
+static GArray *
+compute_sources (SpecEditor *sped, GError **error)
+{
+ gchar *xml;
+ xmlDocPtr doc = NULL;
+ GError *lerror = NULL;
+ GSList *sources_list = NULL;
+
+ /* create sources_list from XML */
+ GtkTextIter start, end;
+ gtk_text_buffer_get_start_iter (sped->priv->buffer, &start);
+ gtk_text_buffer_get_end_iter (sped->priv->buffer, &end);
+ xml = gtk_text_buffer_get_text (sped->priv->buffer, &start, &end, FALSE);
+ if (xml) {
+ doc = xmlParseDoc (BAD_CAST xml);
+ g_free (xml);
+ }
+
+ if (!doc) {
+ g_set_error (&lerror, 0, 0,
+ _("Error parsing XML specifications"));
+ goto onerror;
+ }
+
+ xmlNodePtr node;
+ node = xmlDocGetRootElement (doc);
+ if (!node) {
+ /* nothing to do => finished */
+ xmlFreeDoc (doc);
+ return NULL;
+ }
+
+ for (node = node->children; node; node = node->next) {
+ 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);
+ if (!source)
+ goto onerror;
+ else
+ sources_list = g_slist_prepend (sources_list, source);
+ }
+ }
+ xmlFreeDoc (doc);
+ doc = NULL;
+ sources_list = g_slist_reverse (sources_list);
+
+ /* reorder sources_list */
+ GArray *sources_array;
+ sources_array = create_sources_array (sources_list, &lerror);
+ 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 sources_array;
+
+ onerror:
+ if (doc)
+ xmlFreeDoc (doc);
+ if (sources_list) {
+ g_slist_foreach (sources_list, (GFunc) g_object_unref, NULL);
+ g_slist_free (sources_list);
+ }
+ 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;
+}
diff --git a/tools/browser/data-manager/spec-editor.h b/tools/browser/data-manager/spec-editor.h
new file mode 100644
index 0000000..624975b
--- /dev/null
+++ b/tools/browser/data-manager/spec-editor.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SPEC_EDITOR_H__
+#define __SPEC_EDITOR_H__
+
+#include <gtk/gtk.h>
+#include "../browser-connection.h"
+
+G_BEGIN_DECLS
+
+#define SPEC_EDITOR_TYPE (spec_editor_get_type())
+#define SPEC_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, SPEC_EDITOR_TYPE, SpecEditor))
+#define SPEC_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, SPEC_EDITOR_TYPE, SpecEditorClass))
+#define IS_SPEC_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, SPEC_EDITOR_TYPE))
+#define IS_SPEC_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPEC_EDITOR_TYPE))
+
+
+typedef struct _SpecEditor SpecEditor;
+typedef struct _SpecEditorClass SpecEditorClass;
+typedef struct _SpecEditorPrivate SpecEditorPrivate;
+
+struct _SpecEditor {
+ GtkVBox parent;
+ SpecEditorPrivate *priv;
+};
+
+struct _SpecEditorClass {
+ GtkVBoxClass parent_class;
+};
+
+typedef enum {
+ SPEC_EDITOR_XML,
+ SPEC_EDITOR_UI
+} SpecEditorMode;
+
+
+GType spec_editor_get_type (void) G_GNUC_CONST;
+SpecEditor *spec_editor_new (BrowserConnection *bcnc);
+
+void spec_editor_set_xml_text (SpecEditor *sped, const gchar *xml);
+gchar *spec_editor_get_xml_text (SpecEditor *sped);
+void spec_editor_set_mode (SpecEditor *sped, SpecEditorMode mode);
+SpecEditorMode spec_editor_get_mode (SpecEditor *sped);
+
+GArray *spec_editor_get_sources_array (SpecEditor *sped, GError **error);
+void spec_editor_destroy_sources_array (GArray *array);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/data/Makefile.am b/tools/browser/data/Makefile.am
index a7697e2..bea8cab 100644
--- a/tools/browser/data/Makefile.am
+++ b/tools/browser/data/Makefile.am
@@ -10,17 +10,22 @@ public_icons = \
private_icons = \
hicolor_actions_16x16_bookmark-view.png \
hicolor_actions_16x16_history-view.png \
+ hicolor_actions_16x16_glade.png \
hicolor_actions_22x22_bookmark-view.png \
hicolor_actions_22x22_history-view.png \
+ hicolor_actions_22x22_glade.png \
hicolor_actions_24x24_bookmark-view.png \
hicolor_actions_24x24_history-view.png \
hicolor_actions_24x24_transaction-begin.png \
hicolor_actions_24x24_transaction-commit.png \
hicolor_actions_24x24_transaction-rollback.png \
+ hicolor_actions_24x24_glade.png \
hicolor_actions_32x32_bookmark-view.png \
hicolor_actions_32x32_history-view.png \
+ hicolor_actions_32x32_glade.png \
hicolor_actions_scalable_bookmark-view.svg \
hicolor_actions_scalable_history-view.svg \
+ hicolor_actions_scalable_glade.svg \
$(NULL)
noinst_DATA = \
diff --git a/tools/browser/data/hicolor_actions_16x16_glade.png b/tools/browser/data/hicolor_actions_16x16_glade.png
new file mode 100644
index 0000000..4a962f7
Binary files /dev/null and b/tools/browser/data/hicolor_actions_16x16_glade.png differ
diff --git a/tools/browser/data/hicolor_actions_22x22_glade.png b/tools/browser/data/hicolor_actions_22x22_glade.png
new file mode 100644
index 0000000..e29ea62
Binary files /dev/null and b/tools/browser/data/hicolor_actions_22x22_glade.png differ
diff --git a/tools/browser/data/hicolor_actions_24x24_glade.png b/tools/browser/data/hicolor_actions_24x24_glade.png
new file mode 100644
index 0000000..7edbe84
Binary files /dev/null and b/tools/browser/data/hicolor_actions_24x24_glade.png differ
diff --git a/tools/browser/data/hicolor_actions_32x32_glade.png b/tools/browser/data/hicolor_actions_32x32_glade.png
new file mode 100644
index 0000000..9b6dd6b
Binary files /dev/null and b/tools/browser/data/hicolor_actions_32x32_glade.png differ
diff --git a/tools/browser/data/hicolor_actions_scalable_glade.svg b/tools/browser/data/hicolor_actions_scalable_glade.svg
new file mode 100644
index 0000000..a549daa
--- /dev/null
+++ b/tools/browser/data/hicolor_actions_scalable_glade.svg
@@ -0,0 +1,648 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48px"
+ height="48px"
+ id="svg4908"
+ sodipodi:version="0.32"
+ inkscape:version="0.44+devel"
+ sodipodi:docname="glade5.svg"
+ sodipodi:docbase="/home/andreas/project/application icons/48x48"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/home/andreas/project/application icons/48x48/glade5.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:modified="true">
+ <defs
+ id="defs4910">
+ <linearGradient
+ id="linearGradient22140">
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="0"
+ id="stop22142" />
+ <stop
+ id="stop22148"
+ offset="0.5"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop22144" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22140"
+ id="linearGradient23044"
+ gradientUnits="userSpaceOnUse"
+ x1="18.142136"
+ y1="35"
+ x2="18.142136"
+ y2="42.040661" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22122"
+ id="radialGradient23042"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1.000001,1.142856,0,-89.10259,-31.49999)"
+ cx="7"
+ cy="39.464806"
+ fx="7"
+ fy="39.464806"
+ r="3.5" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient22122">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop22124" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop22126" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22122"
+ id="radialGradient23040"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1.000001,1.142856,0,-41.10259,45.50001)"
+ cx="7"
+ cy="39.464806"
+ fx="7"
+ fy="39.464806"
+ r="3.5" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7025">
+ <stop
+ style="stop-color:#e6ce46;stop-opacity:1"
+ offset="0"
+ id="stop7027" />
+ <stop
+ style="stop-color:#d6ba1c;stop-opacity:1"
+ offset="1"
+ id="stop7029" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7025"
+ id="linearGradient10840"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(53,1.428571)"
+ x1="13.630114"
+ y1="28.5"
+ x2="25.208096"
+ y2="41.180992" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7780">
+ <stop
+ style="stop-color:#888a85;stop-opacity:1;"
+ offset="0"
+ id="stop7782" />
+ <stop
+ style="stop-color:#888a85;stop-opacity:0;"
+ offset="1"
+ id="stop7784" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7752">
+ <stop
+ style="stop-color:#888a85;stop-opacity:1"
+ offset="0"
+ id="stop7754" />
+ <stop
+ style="stop-color:#888a85;stop-opacity:0"
+ offset="1"
+ id="stop7756" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7744">
+ <stop
+ style="stop-color:#888a85;stop-opacity:1"
+ offset="0"
+ id="stop7746" />
+ <stop
+ style="stop-color:#888a85;stop-opacity:0"
+ offset="1"
+ id="stop7748" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7736">
+ <stop
+ style="stop-color:#c1c7bc;stop-opacity:1;"
+ offset="0"
+ id="stop7738" />
+ <stop
+ style="stop-color:#e8eae6;stop-opacity:1"
+ offset="1"
+ id="stop7740" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7728">
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0"
+ id="stop7730" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="1"
+ id="stop7732" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7720">
+ <stop
+ style="stop-color:#555753;stop-opacity:1;"
+ offset="0"
+ id="stop7722" />
+ <stop
+ style="stop-color:#555753;stop-opacity:0;"
+ offset="1"
+ id="stop7724" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7686">
+ <stop
+ style="stop-color:#555753;stop-opacity:1;"
+ offset="0"
+ id="stop7688" />
+ <stop
+ style="stop-color:#555753;stop-opacity:0;"
+ offset="1"
+ id="stop7690" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6997">
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1;"
+ offset="0"
+ id="stop6999" />
+ <stop
+ style="stop-color:#d7d9d5;stop-opacity:1"
+ offset="1"
+ id="stop7001" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6905">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop6907" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop6909" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4790">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop4792" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop4794" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4790"
+ id="radialGradient4796"
+ cx="37.030354"
+ cy="12.98915"
+ fx="37.030354"
+ fy="12.98915"
+ r="4.2929163"
+ gradientTransform="matrix(-2.1313511,0,0,1.283833,86.543976,-0.1277984)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient269">
+ <stop
+ id="stop270"
+ offset="0.0000000"
+ style="stop-color:#a3a3a3;stop-opacity:1.0000000;" />
+ <stop
+ id="stop271"
+ offset="1"
+ style="stop-color:#8a8a8a;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient259">
+ <stop
+ id="stop260"
+ offset="0.0000000"
+ style="stop-color:#729fcf;stop-opacity:1" />
+ <stop
+ id="stop261"
+ offset="1.0000000"
+ style="stop-color:#204a87;stop-opacity:1.0000000" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2251">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2253" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2255" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2251"
+ id="linearGradient8166"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.277938e-2,-1.0071302,-0.999463,-3.303084e-2,45.620229,49.233341)"
+ x1="32.862488"
+ y1="36.028366"
+ x2="34.170048"
+ y2="38.070381" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6905"
+ id="linearGradient6959"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(11.30501,19.746952)"
+ x1="-15.909902"
+ y1="16.003418"
+ x2="-23"
+ y2="16.091806" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6905"
+ id="linearGradient6962"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-35,-4.5078057)"
+ x1="-15.909902"
+ y1="16.003418"
+ x2="-23"
+ y2="16.091806" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6997"
+ id="linearGradient7003"
+ x1="-17.235727"
+ y1="17.947962"
+ x2="-17.324116"
+ y2="32.53204"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7686"
+ id="linearGradient7692"
+ x1="35.47406"
+ y1="36.912945"
+ x2="35.47406"
+ y2="39.351414"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,1.0045696,0,-0.1855194)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7720"
+ id="linearGradient7726"
+ x1="-8.28125"
+ y1="12.475584"
+ x2="-8.28125"
+ y2="6.2509766"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.2909091,0,0,0.3497268,-33.090909,9.251366)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7728"
+ id="radialGradient7734"
+ cx="8.3376141"
+ cy="40.582108"
+ fx="8.3376141"
+ fy="40.582108"
+ r="20.500002"
+ gradientTransform="matrix(-0.9959857,6.9120707e-8,1.181422e-6,0.8780487,46.845968,3.0487798)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7736"
+ id="linearGradient7742"
+ x1="38.944931"
+ y1="12.11484"
+ x2="37.306168"
+ y2="13.392819"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1,0,0,1,47.000004,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7744"
+ id="linearGradient7750"
+ x1="18.384777"
+ y1="22"
+ x2="23.292892"
+ y2="22"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7752"
+ id="linearGradient7758"
+ x1="15.114408"
+ y1="27"
+ x2="20.019962"
+ y2="27"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7780"
+ id="linearGradient7786"
+ x1="20.875"
+ y1="14.249998"
+ x2="20.875"
+ y2="18.437498"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22122"
+ id="radialGradient5157"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1.000001,1.142856,0,-41.10259,45.50001)"
+ cx="7"
+ cy="39.464806"
+ fx="7"
+ fy="39.464806"
+ r="3.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22122"
+ id="radialGradient5159"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1.000001,1.142856,0,-89.10259,-31.49999)"
+ cx="7"
+ cy="39.464806"
+ fx="7"
+ fy="39.464806"
+ r="3.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22140"
+ id="linearGradient5161"
+ gradientUnits="userSpaceOnUse"
+ x1="18.142136"
+ y1="35"
+ x2="18.142136"
+ y2="42.040661" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.999999"
+ inkscape:cx="27.406385"
+ inkscape:cy="33.127804"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1674"
+ inkscape:window-height="968"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ showguides="true"
+ inkscape:guide-bbox="true" />
+ <metadata
+ id="metadata4913">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g5149"
+ style="opacity:0.3"
+ transform="matrix(-0.9583333,0,0,0.714282,47,15.000156)">
+ <rect
+ y="35"
+ x="0"
+ height="7"
+ width="4"
+ id="rect5151"
+ style="opacity:1;fill:url(#radialGradient5157);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+ <rect
+ transform="scale(-1,-1)"
+ y="-42"
+ x="-48"
+ height="7"
+ width="4"
+ id="rect5153"
+ style="opacity:1;fill:url(#radialGradient5159);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+ <rect
+ y="35"
+ x="4"
+ height="7"
+ width="40"
+ id="rect5155"
+ style="opacity:1;fill:url(#linearGradient5161);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+ </g>
+ <path
+ style="fill:url(#radialGradient7734);fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+ d="M 43.215995,7.5 L 13.471509,7.5 C 13.314168,7.5 3.5,17.314168 3.5,17.471508 L 3.5,42.215992 C 3.5,42.373332 3.626668,42.5 3.784009,42.5 L 43.215995,42.5 C 43.373336,42.5 43.500004,42.373332 43.500004,42.215992 L 43.500004,7.7840084 C 43.500004,7.6266678 43.373336,7.5 43.215995,7.5 z "
+ id="rect4916"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:url(#linearGradient7692);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 35.532117,40.598798 L 35.532117,14.5 L 7.5130099,14.5 L 7.5130099,36.544822 L 24.393398,36.544822"
+ id="path4974"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="opacity:0.64130435;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+ d="M 4.5,16.875001 L 13.062499,8.5 L 42.5,8.5 L 42.5,41.5 L 4.5,41.5 L 4.5,16.875001 z "
+ id="rect5887"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#555753;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 6.0648146,18.566679 L 35.435184,18.566679"
+ id="path4976" />
+ <path
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ style="opacity:0.35714285;color:#000000;fill:url(#radialGradient4796);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4,17.212006 C 4.8898017,15.865378 11.455677,13.481495 14.873341,12.681969 C 14.666262,14.254915 15.023334,19 15.023334,19 C 12.503686,17.625 4.9537451,17.049892 4,17.212006 z "
+ id="path5348"
+ sodipodi:nodetypes="cccc" />
+ <rect
+ style="opacity:0.64130435;fill:url(#linearGradient7786);fill-opacity:1.0;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7778"
+ width="27"
+ height="3"
+ x="8"
+ y="15" />
+ <path
+ style="opacity:1;color:#000000;fill:url(#linearGradient7742);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+ d="M 3.500024,17.60468 C 3.486859,16.189538 9.852559,7.3974268 13.735143,7.500906 C 12.762105,7.733901 11.984788,13.668936 13.374508,16.481436 C 10.624508,16.481436 4.463889,15.746506 3.500024,17.60468 z "
+ id="path2210"
+ sodipodi:nodetypes="cccc"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2247"
+ d="M 5.78902,15.499999 C 6.517382,14.143041 9.947557,10.391559 11.870143,9.1450438 C 11.631203,10.581831 11.333088,12.855721 11.948728,15.437757 C 11.948728,15.437757 6.569724,15.336642 5.78902,15.499999 z "
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient8166);stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.7826087;fill:none;fill-opacity:1;stroke:#555753;stroke-width:1.62018538;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path4978"
+ sodipodi:cx="11.136932"
+ sodipodi:cy="23.604815"
+ sodipodi:rx="2.3864856"
+ sodipodi:ry="2.4748738"
+ d="M 13.523418 23.604815 A 2.3864856 2.4748738 0 1 1 8.7504468,23.604815 A 2.3864856 2.4748738 0 1 1 13.523418 23.604815 z"
+ transform="matrix(0.6285393,0,0,0.6060913,3.9999997,7.6933267)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.7826087;fill:none;fill-opacity:1;stroke:#555753;stroke-width:1.62018538;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5951"
+ sodipodi:cx="11.136932"
+ sodipodi:cy="23.604815"
+ sodipodi:rx="2.3864856"
+ sodipodi:ry="2.4748738"
+ d="M 13.523418 23.604815 A 2.3864856 2.4748738 0 1 1 8.7504468,23.604815 A 2.3864856 2.4748738 0 1 1 13.523418 23.604815 z"
+ transform="matrix(0.6285393,0,0,0.6060915,4.0000003,12.693323)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient7750);fill-opacity:1.0;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect5955"
+ width="10"
+ height="2"
+ x="14"
+ y="21"
+ rx="0"
+ ry="0" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient7758);fill-opacity:1.0;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect5957"
+ width="7"
+ height="2"
+ x="14"
+ y="26"
+ rx="0"
+ ry="0" />
+ <rect
+ style="opacity:1;fill:#555753;fill-opacity:1;stroke:#555753;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect5963"
+ width="0.15951318"
+ height="3"
+ x="-14.659513"
+ y="-38.5"
+ transform="matrix(0,-1,-1,0,0,0)" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#555753;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ d="M 23.906407,31.559768 L 15.5,31.559768 L 15.5,34.500001 L 25.525275,34.500001 L 25.525275,33.295103"
+ id="path5965"
+ sodipodi:nodetypes="ccccc" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient7726);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7718"
+ width="1"
+ height="4"
+ x="-36"
+ y="11"
+ transform="scale(-1,1)" />
+ <g
+ id="g22150"
+ style="opacity:0.3"
+ transform="matrix(-0.916667,0,0,0.714282,48,18.00012)">
+ <rect
+ y="35"
+ x="0"
+ height="7"
+ width="4"
+ id="rect22120"
+ style="opacity:1;fill:url(#radialGradient23040);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+ <rect
+ transform="scale(-1,-1)"
+ y="-42"
+ x="-48"
+ height="7"
+ width="4"
+ id="rect22134"
+ style="opacity:1;fill:url(#radialGradient23042);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+ <rect
+ y="35"
+ x="4"
+ height="7"
+ width="40"
+ id="rect22138"
+ style="opacity:1;fill:url(#linearGradient23044);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+ </g>
+ <g
+ id="g10824"
+ transform="matrix(-1,0,0,1,103,0.5714291)">
+ <path
+ id="path4319"
+ d="M 57.5,14.928571 L 57.5,44.928571 L 96.5,44.928571 L 57.5,14.928571 z M 63.5,27.928571 L 78.5,38.928571 L 63.5,38.928571 L 63.5,27.928571 z "
+ style="fill:url(#linearGradient10840);fill-opacity:1;fill-rule:evenodd;stroke:#a38503;stroke-width:1.00000024px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4326"
+ d="M 61.5,44.928571 L 61.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4328"
+ d="M 67.5,44.928571 L 67.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4330"
+ d="M 73.5,44.928571 L 73.5,41.964285"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4332"
+ d="M 79.5,44.928571 L 79.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4334"
+ d="M 85.5,44.928571 L 85.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ id="path6126"
+ d="M 58.500002,16.928575 L 58.500002,43.928586 L 93.500014,43.928586 L 58.500002,16.928575 z "
+ style="opacity:0.4;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <path
+ style="opacity:0.4;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 40.498252,40.542446 L 40.542447,26.532894 L 21.458408,40.563262 L 40.498252,40.542446 z "
+ id="path12221"
+ sodipodi:nodetypes="cccc" />
+ </g>
+</svg>
diff --git a/tools/browser/decl.h b/tools/browser/decl.h
index d800ffa..7bcc667 100644
--- a/tools/browser/decl.h
+++ b/tools/browser/decl.h
@@ -47,6 +47,7 @@ typedef struct {
#define ORDER_KEY_SCHEMA 1
#define ORDER_KEY_QUERIES 2
+#define ORDER_KEY_DATA_MANAGERS 3
G_END_DECLS
diff --git a/tools/browser/doc/tmpl/browser-favorites.sgml b/tools/browser/doc/tmpl/browser-favorites.sgml
index 3146364..520b444 100644
--- a/tools/browser/doc/tmpl/browser-favorites.sgml
+++ b/tools/browser/doc/tmpl/browser-favorites.sgml
@@ -34,6 +34,7 @@ Favorites management
@BROWSER_FAVORITES_TABLES:
@BROWSER_FAVORITES_DIAGRAMS:
@BROWSER_FAVORITES_QUERIES:
+ BROWSER_FAVORITES_DATA_MANAGERS:
<!-- ##### MACRO BROWSER_FAVORITES_NB_TYPES ##### -->
<para>
diff --git a/tools/browser/main.c b/tools/browser/main.c
index 00b81bf..ef8f74e 100644
--- a/tools/browser/main.c
+++ b/tools/browser/main.c
@@ -34,7 +34,8 @@
/* Perspectives' factories */
#include "schema-browser/perspective-main.h"
#include "query-exec/perspective-main.h"
-#include "dummy-perspective/perspective-main.h"
+#include "data-manager/perspective-main.h"
+/* #include "dummy-perspective/perspective-main.h" */
extern BrowserCoreInitFactories browser_core_init_factories;
@@ -45,7 +46,8 @@ main_browser_core_init_factories (void)
GSList *factories = NULL;
factories = g_slist_append (factories, schema_browser_perspective_get_factory ());
factories = g_slist_append (factories, query_exec_perspective_get_factory ());
- factories = g_slist_append (factories, dummy_perspective_get_factory ());
+ factories = g_slist_append (factories, data_manager_perspective_get_factory ());
+ /* factories = g_slist_append (factories, dummy_perspective_get_factory ()); */
return factories;
}
diff --git a/tools/browser/mgr-favorites.c b/tools/browser/mgr-favorites.c
index c5f1035..14336cf 100644
--- a/tools/browser/mgr-favorites.c
+++ b/tools/browser/mgr-favorites.c
@@ -484,6 +484,43 @@ mgr_favorites_update_children (GdaTreeManager *manager, GdaTreeNode *node, const
av, NULL);
gda_value_free (av);
}
+ else if (fav->type == BROWSER_FAVORITES_DATA_MANAGERS) {
+ if (!snode) {
+ snode = gda_tree_manager_create_node (manager, node, NULL);
+
+ g_value_set_int ((av = gda_value_new (G_TYPE_INT)), fav->id);
+ gda_tree_node_set_node_attribute (snode,
+ MGR_FAVORITES_ID_ATT_NAME,
+ av, NULL);
+ gda_value_free (av);
+
+ g_value_set_int ((av = gda_value_new (G_TYPE_INT)), pos);
+ gda_tree_node_set_node_attribute (snode,
+ MGR_FAVORITES_POSITION_ATT_NAME,
+ av, NULL);
+ gda_value_free (av);
+
+ /* icon */
+ GdkPixbuf *pixbuf;
+ pixbuf = browser_get_pixbuf_icon (BROWSER_ICON_TABLE);
+ av = gda_value_new (G_TYPE_OBJECT);
+ g_value_set_object (av, pixbuf);
+ gda_tree_node_set_node_attribute (snode, "icon", av, NULL);
+ gda_value_free (av);
+ }
+
+ g_value_set_string ((av = gda_value_new (G_TYPE_STRING)),
+ fav->contents);
+ gda_tree_node_set_node_attribute (snode,
+ MGR_FAVORITES_CONTENTS_ATT_NAME,
+ av, NULL);
+ gda_value_free (av);
+
+ g_value_set_string ((av = gda_value_new (G_TYPE_STRING)), fav->name);
+ gda_tree_node_set_node_attribute (snode, MGR_FAVORITES_NAME_ATT_NAME,
+ av, NULL);
+ gda_value_free (av);
+ }
else {
TO_IMPLEMENT;
}
diff --git a/tools/browser/query-exec/perspective-main.c b/tools/browser/query-exec/perspective-main.c
index c2d4914..9f53593 100644
--- a/tools/browser/query-exec/perspective-main.c
+++ b/tools/browser/query-exec/perspective-main.c
@@ -29,7 +29,7 @@ static BrowserPerspectiveFactory bfact;
BrowserPerspectiveFactory *
query_exec_perspective_get_factory (void)
{
- bfact.perspective_name = "Query execution";
+ bfact.perspective_name = "Query execution (SQL)";
bfact.menu_shortcut = "<control>S";
bfact.perspective_create = query_exec_perspective_new;
diff --git a/tools/browser/query-exec/query-console.c b/tools/browser/query-exec/query-console.c
index 2493578..91e774e 100644
--- a/tools/browser/query-exec/query-console.c
+++ b/tools/browser/query-exec/query-console.c
@@ -36,17 +36,6 @@
#include <libgda/sql-parser/gda-sql-parser.h>
#include <libgda-ui/libgda-ui.h>
-#define VARIABLES_HELP _("<small>This area allows to give values to\n" \
- "variables defined in the SQL code\n" \
- "using the following syntax:\n" \
- "<b><tt>##<variable name>::<type>[::null]</tt></b>\n" \
- "For example:\n" \
- "<span foreground=\"#4e9a06\"><b><tt>##id::int</tt></b></span>\n defines <b>id</b> as a non NULL integer\n" \
- "<span foreground=\"#4e9a06\"><b><tt>##age::string::null</tt></b></span>\n defines <b>age</b> as a a string\n\n" \
- "Valid types are: <tt>string</tt>, <tt>boolean</tt>, <tt>int</tt>,\n" \
- "<tt>date</tt>, <tt>time</tt>, <tt>timestamp</tt>, <tt>guint</tt>, <tt>blob</tt> and\n" \
- "<tt>binary</tt></small>")
-
/*
* Statement execution structures
*/
@@ -230,6 +219,8 @@ query_console_dispose (GObject *object)
g_source_remove (tconsole->priv->params_compute_id);
if (tconsole->priv->params_popup)
gtk_widget_destroy (tconsole->priv->params_popup);
+ if (tconsole->priv->agroup)
+ g_object_unref (tconsole->priv->agroup);
g_free (tconsole->priv);
tconsole->priv = NULL;
@@ -268,9 +259,6 @@ query_console_get_type (void)
return type;
}
-static GtkWidget *make_small_button (gboolean is_toggle,
- const gchar *label, const gchar *stock_id, const gchar *tooltip);
-
static void editor_changed_cb (QueryEditor *editor, QueryConsole *tconsole);
static void editor_execute_request_cb (QueryEditor *editor, QueryConsole *tconsole);
static void sql_clear_clicked_cb (GtkButton *button, QueryConsole *tconsole);
@@ -367,6 +355,7 @@ query_console_new (BrowserConnection *bcnc)
wid = gtk_label_new ("");
gtk_label_set_markup (GTK_LABEL (wid), VARIABLES_HELP);
+ gtk_misc_set_alignment (GTK_MISC (wid), -1, 0.);
gtk_container_add (GTK_CONTAINER (tconsole->priv->params_form_box), wid);
tconsole->priv->params_form = wid;
@@ -374,24 +363,24 @@ query_console_new (BrowserConnection *bcnc)
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, FALSE, 5);
- button = make_small_button (FALSE, _("Clear"), GTK_STOCK_CLEAR, _("Clear the editor"));
+ button = browser_make_small_button (FALSE, _("Clear"), GTK_STOCK_CLEAR, _("Clear the editor's\ncontents"));
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (sql_clear_clicked_cb), tconsole);
- button = make_small_button (TRUE, _("Variables"), NULL, _("Show variables needed\nto execute SQL"));
+ button = browser_make_small_button (TRUE, _("Variables"), NULL, _("Show variables needed\nto execute SQL"));
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
tconsole->priv->params_toggle = GTK_TOGGLE_BUTTON (button);
g_signal_connect (button, "toggled",
G_CALLBACK (sql_variables_clicked_cb), tconsole);
- button = make_small_button (FALSE, _("Execute"), GTK_STOCK_EXECUTE, _("Execute SQL in editor"));
+ button = browser_make_small_button (FALSE, _("Execute"), GTK_STOCK_EXECUTE, _("Execute SQL in editor"));
tconsole->priv->exec_button = button;
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (sql_execute_clicked_cb), tconsole);
- button = make_small_button (FALSE, _("Indent"), GTK_STOCK_INDENT, _("Indent SQL in editor\n"
+ button = browser_make_small_button (FALSE, _("Indent"), GTK_STOCK_INDENT, _("Indent SQL in editor\n"
"and make the code more readable\n"
"(removes comments)"));
tconsole->priv->indent_button = button;
@@ -399,7 +388,7 @@ query_console_new (BrowserConnection *bcnc)
g_signal_connect (button, "clicked",
G_CALLBACK (sql_indent_clicked_cb), tconsole);
- button = make_small_button (FALSE, _("Favorite"), STOCK_ADD_BOOKMARK, _("Add SQL to favorite"));
+ button = browser_make_small_button (FALSE, _("Favorite"), STOCK_ADD_BOOKMARK, _("Add SQL to favorite"));
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (sql_favorite_clicked_cb), tconsole);
@@ -431,14 +420,14 @@ query_console_new (BrowserConnection *bcnc)
gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
- button = make_small_button (FALSE, _("Copy"), GTK_STOCK_COPY, _("Copy selected history\nto editor"));
+ button = browser_make_small_button (FALSE, _("Copy"), GTK_STOCK_COPY, _("Copy selected history\nto editor"));
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (history_copy_clicked_cb), tconsole);
tconsole->priv->history_copy_button = button;
gtk_widget_set_sensitive (button, FALSE);
- button = make_small_button (FALSE, _("Clear"), GTK_STOCK_CLEAR, _("Clear history"));
+ button = browser_make_small_button (FALSE, _("Clear"), GTK_STOCK_CLEAR, _("Clear history"));
gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (history_clear_clicked_cb), tconsole);
@@ -489,45 +478,6 @@ connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy, gchar *reason, Qu
}
}
-static GtkWidget *
-make_small_button (gboolean is_toggle, const gchar *label, const gchar *stock_id, const gchar *tooltip)
-{
- GtkWidget *button, *hbox = NULL;
-
- if (is_toggle)
- button = gtk_toggle_button_new ();
- else
- button = gtk_button_new ();
- if (label && stock_id) {
- hbox = gtk_hbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (button), hbox);
- gtk_widget_show (hbox);
- }
-
- if (stock_id) {
- GtkWidget *image;
- image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
- if (hbox)
- gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
- else
- gtk_container_add (GTK_CONTAINER (button), image);
- gtk_widget_show (image);
- }
- if (label) {
- GtkWidget *wid;
- wid = gtk_label_new (label);
- if (hbox)
- gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 5);
- else
- gtk_container_add (GTK_CONTAINER (button), wid);
- gtk_widget_show (wid);
- }
-
- if (tooltip)
- gtk_widget_set_tooltip_text (button, tooltip);
- return button;
-}
-
static void
history_changed_cb (QueryEditor *history, QueryConsole *tconsole)
{
@@ -717,6 +667,7 @@ static void
sql_clear_clicked_cb (GtkButton *button, QueryConsole *tconsole)
{
query_editor_set_text (tconsole->priv->editor, NULL);
+ gtk_widget_grab_focus (GTK_WIDGET (tconsole->priv->editor));
}
static void
diff --git a/tools/browser/query-exec/query-console.h b/tools/browser/query-exec/query-console.h
index 3b26769..6f86e66 100644
--- a/tools/browser/query-exec/query-console.h
+++ b/tools/browser/query-exec/query-console.h
@@ -20,7 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
-#ifndef __QUERY_INFO_H__
+#ifndef __QUERY_CONSOLE_H__
#define __QUERY_CONSOLE_H__
#include <gtk/gtk.h>
diff --git a/tools/browser/query-exec/query-exec-perspective.c b/tools/browser/query-exec/query-exec-perspective.c
index 52f1601..cceea2d 100644
--- a/tools/browser/query-exec/query-exec-perspective.c
+++ b/tools/browser/query-exec/query-exec-perspective.c
@@ -52,7 +52,6 @@ struct _QueryExecPerspectivePrivate {
BrowserConnection *bcnc;
GtkActionGroup *action_group;
- gboolean updating_transaction_status;
};
GType
@@ -134,10 +133,6 @@ static void nb_page_removed_cb (GtkNotebook *nb, GtkNotebookPage *page, gint pag
QueryExecPerspective *perspective);
static void close_button_clicked_cb (GtkWidget *wid, GtkWidget *page_widget);
-static void transaction_status_changed_cb (BrowserConnection *bcnc, QueryExecPerspective *perspective);
-
-static void connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy,
- gchar *reason, QueryExecPerspective *perspective);
/**
* query_exec_perspective_new
*
@@ -195,44 +190,12 @@ query_exec_perspective_new (BrowserWindow *bwin)
gtk_box_pack_start (GTK_BOX (bpers), paned, TRUE, TRUE, 0);
gtk_widget_show_all (paned);
- /* transaction status detection */
- g_signal_connect (bcnc, "transaction-status-changed",
- G_CALLBACK (transaction_status_changed_cb), bpers);
-
gtk_widget_grab_focus (page);
- /* busy connection handling */
- connection_busy_cb (perspective->priv->bcnc, browser_connection_is_busy (perspective->priv->bcnc, NULL),
- NULL, perspective);
- g_signal_connect (perspective->priv->bcnc, "busy",
- G_CALLBACK (connection_busy_cb), perspective);
-
return bpers;
}
static void
-connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy,
- gchar *reason, QueryExecPerspective *perspective)
-{
- if (perspective->priv->action_group) {
- GtkAction *action;
- gboolean bsens = FALSE, csens = FALSE;
- if (!is_busy) {
- if (browser_connection_get_transaction_status (bcnc))
- csens = TRUE;
- else
- bsens = TRUE;
- }
- action = gtk_action_group_get_action (perspective->priv->action_group, "QueryExecBegin");
- gtk_action_set_sensitive (action, bsens);
- action = gtk_action_group_get_action (perspective->priv->action_group, "QueryExecCommit");
- gtk_action_set_sensitive (action, csens);
- action = gtk_action_group_get_action (perspective->priv->action_group, "QueryExecRollback");
- gtk_action_set_sensitive (action, csens);
- }
-}
-
-static void
fav_selection_changed_cb (GtkWidget *widget, gint fav_id, BrowserFavoritesType fav_type,
const gchar *selection, QueryExecPerspective *perspective)
{
@@ -299,13 +262,8 @@ query_exec_perspective_dispose (GObject *object)
perspective = QUERY_EXEC_PERSPECTIVE (object);
if (perspective->priv) {
- g_signal_handlers_disconnect_by_func (perspective->priv->bcnc,
- G_CALLBACK (transaction_status_changed_cb), perspective);
- if (perspective->priv->bcnc) {
- g_signal_handlers_disconnect_by_func (perspective->priv->bcnc,
- G_CALLBACK (connection_busy_cb), perspective);
+ if (perspective->priv->bcnc)
g_object_unref (perspective->priv->bcnc);
- }
if (perspective->priv->action_group)
g_object_unref (perspective->priv->action_group);
@@ -351,98 +309,10 @@ query_exec_add_cb (GtkAction *action, BrowserPerspective *bpers)
gtk_widget_grab_focus (page);
}
-static void
-transaction_status_changed_cb (BrowserConnection *bcnc, QueryExecPerspective *perspective)
-{
- if (!perspective->priv->action_group)
- return;
-
- GtkAction *action;
- gboolean trans_started;
-
- trans_started = browser_connection_get_transaction_status (bcnc) ? TRUE : FALSE;
- perspective->priv->updating_transaction_status = TRUE;
-
- action = gtk_action_group_get_action (perspective->priv->action_group, "QueryExecBegin");
- gtk_action_set_sensitive (action, !trans_started);
-
- action = gtk_action_group_get_action (perspective->priv->action_group, "QueryExecCommit");
- gtk_action_set_sensitive (action, trans_started);
-
- action = gtk_action_group_get_action (perspective->priv->action_group, "QueryExecRollback");
- gtk_action_set_sensitive (action, trans_started);
-
- perspective->priv->updating_transaction_status = FALSE;
-}
-
-static void
-transaction_begin_cb (GtkAction *action, BrowserPerspective *bpers)
-{
- QueryExecPerspective *perspective;
- BrowserConnection *bcnc;
-
- perspective = QUERY_EXEC_PERSPECTIVE (bpers);
- bcnc = perspective->priv->bcnc;
- if (!perspective->priv->updating_transaction_status) {
- GError *error = NULL;
- if (! browser_connection_begin (bcnc, &error)) {
- browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bpers)),
- _("Error starting transaction: %s"),
- error && error->message ? error->message : _("No detail"));
- g_clear_error (&error);
- }
- }
-}
-
-static void
-transaction_commit_cb (GtkAction *action, BrowserPerspective *bpers)
-{
- QueryExecPerspective *perspective;
- BrowserConnection *bcnc;
-
- perspective = QUERY_EXEC_PERSPECTIVE (bpers);
- bcnc = perspective->priv->bcnc;
- if (!perspective->priv->updating_transaction_status) {
- GError *error = NULL;
- if (! browser_connection_commit (bcnc, &error)) {
- browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bpers)),
- _("Error committing transaction: %s"),
- error && error->message ? error->message : _("No detail"));
- g_clear_error (&error);
- }
- }
-}
-
-static void
-transaction_rollback_cb (GtkAction *action, BrowserPerspective *bpers)
-{
- QueryExecPerspective *perspective;
- BrowserConnection *bcnc;
-
- perspective = QUERY_EXEC_PERSPECTIVE (bpers);
- bcnc = perspective->priv->bcnc;
- if (!perspective->priv->updating_transaction_status) {
- GError *error = NULL;
- if (! browser_connection_rollback (bcnc, &error)) {
- browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bpers)),
- _("Error rolling back transaction: %s"),
- error && error->message ? error->message : _("No detail"));
- g_clear_error (&error);
- }
- }
-}
-
static GtkActionEntry ui_actions[] = {
{ "QueryExecMenu", NULL, N_("_Query"), NULL, "QueryExecMenu", NULL },
{ "QueryExecItem1", STOCK_CONSOLE, N_("_New editor"), "<control>T", N_("Open a new query editor"),
G_CALLBACK (query_exec_add_cb)},
- { "QueryExecBegin", BROWSER_STOCK_BEGIN, N_("_Begin"), NULL, N_("Begin a new transaction"),
- G_CALLBACK (transaction_begin_cb)},
- { "QueryExecCommit", BROWSER_STOCK_COMMIT, N_("_Commit"), NULL, N_("Commit current transaction"),
- G_CALLBACK (transaction_commit_cb)},
- { "QueryExecRollback", BROWSER_STOCK_ROLLBACK, N_("_Rollback"), NULL, N_("Rollback current transaction"),
- G_CALLBACK (transaction_rollback_cb)},
-
};
static const gchar *ui_actions_info =
@@ -451,18 +321,12 @@ static const gchar *ui_actions_info =
" <placeholder name='MenuExtension'>"
" <menu name='QueryExec' action='QueryExecMenu'>"
" <menuitem name='QueryExecItem1' action= 'QueryExecItem1'/>"
- " <menuitem name='QueryExecBegin' action= 'QueryExecBegin'/>"
- " <menuitem name='QueryExecCommit' action= 'QueryExecCommit'/>"
- " <menuitem name='QueryExecRollback' action= 'QueryExecRollback'/>"
" </menu>"
" </placeholder>"
" </menubar>"
" <toolbar name='ToolBar'>"
" <separator/>"
" <toolitem action='QueryExecItem1'/>"
- " <toolitem action='QueryExecBegin'/>"
- " <toolitem action='QueryExecCommit'/>"
- " <toolitem action='QueryExecRollback'/>"
" </toolbar>"
"</ui>";
@@ -477,13 +341,8 @@ query_exec_perspective_get_actions_group (BrowserPerspective *perspective)
agroup = gtk_action_group_new ("QueryExecActions");
gtk_action_group_add_actions (agroup, ui_actions, G_N_ELEMENTS (ui_actions), bpers);
bpers->priv->action_group = g_object_ref (agroup);
-
- connection_busy_cb (bpers->priv->bcnc, browser_connection_is_busy (bpers->priv->bcnc, NULL),
- NULL, bpers);
}
- transaction_status_changed_cb (bpers->priv->bcnc, bpers);
-
return bpers->priv->action_group;
}
diff --git a/tools/browser/query-exec/query-favorite-selector.c b/tools/browser/query-exec/query-favorite-selector.c
index 00e24fd..3aebbb2 100644
--- a/tools/browser/query-exec/query-favorite-selector.c
+++ b/tools/browser/query-exec/query-favorite-selector.c
@@ -245,6 +245,7 @@ prop_save_timeout (QueryFavoriteSelector *tsel)
g_error_free (error);
}
+ g_free (fav.contents);
tsel->priv->prop_save_timeout = 0;
return FALSE; /* remove timeout */
}
@@ -535,12 +536,15 @@ cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
COLUMN_NAME, &name, COLUMN_SUMMARY, &summary, -1);
tmp1 = g_markup_printf_escaped ("%s", name);
tmp2 = g_markup_printf_escaped ("%s", summary);
+ g_free (name);
+ g_free (summary);
+
markup = g_strdup_printf ("%s\n<small>%s</small>", tmp1, tmp2);
- g_object_set ((GObject*) cell, "markup", markup, NULL);
g_free (tmp1);
g_free (tmp2);
- g_free (name);
- g_free (summary);
+
+ g_object_set ((GObject*) cell, "markup", markup, NULL);
+ g_free (markup);
}
diff --git a/tools/browser/support.c b/tools/browser/support.c
index 4f54b4c..c3363c6 100644
--- a/tools/browser/support.c
+++ b/tools/browser/support.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The GNOME Foundation.
+ * Copyright (C) 2009 - 2010The GNOME Foundation.
*
* AUTHORS:
* Vivien Malerba <malerba gnome-db org>
@@ -429,3 +429,42 @@ connection_removed_cb (BrowserCore *bcore, BrowserConnection *bcnc, GdaDataModel
}
}
}
+
+GtkWidget *
+browser_make_small_button (gboolean is_toggle, const gchar *label, const gchar *stock_id, const gchar *tooltip)
+{
+ GtkWidget *button, *hbox = NULL;
+
+ if (is_toggle)
+ button = gtk_toggle_button_new ();
+ else
+ button = gtk_button_new ();
+ if (label && stock_id) {
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (button), hbox);
+ gtk_widget_show (hbox);
+ }
+
+ if (stock_id) {
+ GtkWidget *image;
+ image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
+ if (hbox)
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+ else
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_widget_show (image);
+ }
+ if (label) {
+ GtkWidget *wid;
+ wid = gtk_label_new (label);
+ if (hbox)
+ gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 5);
+ else
+ gtk_container_add (GTK_CONTAINER (button), wid);
+ gtk_widget_show (wid);
+ }
+
+ if (tooltip)
+ gtk_widget_set_tooltip_text (button, tooltip);
+ return button;
+}
diff --git a/tools/browser/support.h b/tools/browser/support.h
index 8409d97..8f15e1f 100644
--- a/tools/browser/support.h
+++ b/tools/browser/support.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The GNOME Foundation.
+ * Copyright (C) 2009 - 2010 The GNOME Foundation.
*
* AUTHORS:
* Vivien Malerba <malerba gnome-db org>
@@ -40,10 +40,13 @@ GtkWidget* browser_make_tab_label_with_pixbuf (const gchar *label,
GdkPixbuf *pixbuf, gboolean with_close,
GtkWidget **out_close_button);
+GtkWidget *browser_make_small_button (gboolean is_toggle,
+ const gchar *label, const gchar *stock_id, const gchar *tooltip);
+
/*
* Widgets navigation
*/
-GtkWidget *browser_find_parent_widget (GtkWidget *current, GType requested_type);
+GtkWidget *browser_find_parent_widget (GtkWidget *current, GType requested_type);
/*
* icons
@@ -64,7 +67,7 @@ typedef enum {
BROWSER_ICON_LAST
} BrowserIconType;
-GdkPixbuf *browser_get_pixbuf_icon (BrowserIconType type);
+GdkPixbuf *browser_get_pixbuf_icon (BrowserIconType type);
/*
* Connections list
@@ -75,7 +78,18 @@ enum
CNC_LIST_COLUMN_NAME = 1,
CNC_LIST_NUM_COLUMNS
};
-GdaDataModel *browser_get_connections_list (void);
+GdaDataModel *browser_get_connections_list (void);
+
+#define VARIABLES_HELP _("<small>This area allows to give values to\n" \
+ "variables defined in the SQL code\n" \
+ "using the following syntax:\n" \
+ "<b><tt>##<variable name>::<type>[::null]</tt></b>\n" \
+ "For example:\n" \
+ "<span foreground=\"#4e9a06\"><b><tt>##id::int</tt></b></span>\n defines <b>id</b> as a non NULL integer\n" \
+ "<span foreground=\"#4e9a06\"><b><tt>##age::string::null</tt></b></span>\n defines <b>age</b> as a a string\n\n" \
+ "Valid types are: <tt>string</tt>, <tt>boolean</tt>, <tt>int</tt>,\n" \
+ "<tt>date</tt>, <tt>time</tt>, <tt>timestamp</tt>, <tt>guint</tt>, <tt>blob</tt> and\n" \
+ "<tt>binary</tt></small>")
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]