[libgda] GdaBrowser: new data source editor for the data manager perspective
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] GdaBrowser: new data source editor for the data manager perspective
- Date: Wed, 1 Sep 2010 14:22:34 +0000 (UTC)
commit 2ad2914689d6686dcde552b57a4777e022706d84
Author: Vivien Malerba <malerba gnome-db org>
Date: Wed Sep 1 15:55:56 2010 +0200
GdaBrowser: new data source editor for the data manager perspective
po/POTFILES.in | 1 +
tools/browser/browser-window.c | 41 +-
tools/browser/browser-window.h | 1 +
tools/browser/data-manager/DataSourceEdition.dia | Bin 0 -> 2492 bytes
tools/browser/data-manager/Makefile.am | 2 +
tools/browser/data-manager/data-console.c | 192 +++++-
.../data-manager/data-manager-perspective.c | 23 +-
tools/browser/data-manager/data-source-editor.c | 319 ++++++++
tools/browser/data-manager/data-source-editor.h | 60 ++
tools/browser/data-manager/data-source-manager.c | 92 ++-
tools/browser/data-manager/data-source-manager.h | 7 +-
tools/browser/data-manager/data-source.c | 842 +++++++++++++-------
tools/browser/data-manager/data-source.h | 26 +-
tools/browser/data-manager/marshal.list | 1 +
tools/browser/data-manager/ui-spec-editor.c | 282 ++++++-
tools/browser/data-manager/ui-spec-editor.h | 5 +-
tools/browser/data-manager/xml-spec-editor.c | 79 ++-
tools/browser/doc/gda-browser-sections.txt | 1 +
tools/browser/doc/tmpl/browser-window.sgml | 9 +
tools/browser/support.c | 3 +
20 files changed, 1642 insertions(+), 344 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 54a4c70..4826287 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -255,6 +255,7 @@ tools/browser/data-manager/data-console.c
tools/browser/data-manager/data-favorite-selector.c
tools/browser/data-manager/data-manager-perspective.c
tools/browser/data-manager/data-source.c
+tools/browser/data-manager/data-source-editor.c
tools/browser/data-manager/data-widget.c
tools/browser/data-manager/ui-spec-editor.c
tools/browser/data-manager/xml-spec-editor.c
diff --git a/tools/browser/browser-window.c b/tools/browser/browser-window.c
index d3d8f5e..9a1b728 100644
--- a/tools/browser/browser-window.c
+++ b/tools/browser/browser-window.c
@@ -30,6 +30,7 @@
#include "browser-spinner.h"
#include "browser-stock-icons.h"
#include "connection-binding-properties.h"
+#include <gdk/gdkkeysyms.h>
/*
* structure representing a 'tab' in a window
@@ -59,6 +60,7 @@ static void browser_window_init (BrowserWindow *bwin);
static void browser_window_dispose (GObject *object);
static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event);
+static gboolean key_press_event (GtkWidget *widget, GdkEventKey *event);
static void connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy, gchar *reason, BrowserWindow *bwin);
static void connection_added_cb (BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin);
@@ -137,6 +139,7 @@ browser_window_class_init (BrowserWindowClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->window_state_event = window_state_event;
+ widget_class->key_press_event = key_press_event;
parent_class = g_type_class_peek_parent (klass);
browser_window_signals[FULLSCREEN_CHANGED] =
@@ -883,13 +886,30 @@ window_close_cb (GtkAction *action, BrowserWindow *bwin)
static void
window_fullscreen_cb (GtkToggleAction *action, BrowserWindow *bwin)
{
- if (gtk_toggle_action_get_active (action))
+ if (gtk_toggle_action_get_active (action)) {
gtk_window_fullscreen (GTK_WINDOW (bwin));
+ browser_show_notice (GTK_WINDOW (bwin),
+ "fullscreen-esc",
+ _("Hit the Escape key\nto leave the fullscreen mode"));
+ }
else
gtk_window_unfullscreen (GTK_WINDOW (bwin));
}
static gboolean
+key_press_event (GtkWidget *widget, GdkEventKey *event)
+{
+ if ((event->keyval == GDK_Escape) &&
+ browser_window_is_fullscreen (BROWSER_WINDOW (widget))) {
+ browser_window_set_fullscreen (BROWSER_WINDOW (widget), FALSE);
+ return TRUE;
+ }
+
+ /* parent class */
+ return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
+}
+
+static gboolean
window_state_event (GtkWidget *widget, GdkEventWindowState *event)
{
BrowserWindow *bwin = BROWSER_WINDOW (widget);
@@ -1330,6 +1350,8 @@ browser_window_change_perspective (BrowserWindow *bwin, const gchar *perspective
/**
* browser_window_is_fullscreen
* @bwin: a #BrowserWindow
+ *
+ * Returns: %TRUE if @bwin is fullscreen
*/
gboolean
browser_window_is_fullscreen (BrowserWindow *bwin)
@@ -1337,3 +1359,20 @@ browser_window_is_fullscreen (BrowserWindow *bwin)
g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), FALSE);
return bwin->priv->fullscreen;
}
+
+/**
+ * browser_window_set_fullscreen
+ * @bwin: a #BrowserWindow
+ * @fullscreen:
+ *
+ * Requires @bwin to be fullscreen if @fullscreen is %TRUE
+ */
+void
+browser_window_set_fullscreen (BrowserWindow *bwin, gboolean fullscreen)
+{
+ GtkAction *action;
+ g_return_if_fail (BROWSER_IS_WINDOW (bwin));
+
+ action = gtk_action_group_get_action (bwin->priv->agroup, "WindowFullScreen");
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fullscreen);
+}
diff --git a/tools/browser/browser-window.h b/tools/browser/browser-window.h
index 302214a..3c97bd3 100644
--- a/tools/browser/browser-window.h
+++ b/tools/browser/browser-window.h
@@ -65,6 +65,7 @@ void browser_window_customize_perspective_ui (BrowserWindow *bwin
BrowserPerspective *browser_window_change_perspective (BrowserWindow *bwin, const gchar *perspective);
+void browser_window_set_fullscreen (BrowserWindow *bwin, gboolean fullscreen);
gboolean browser_window_is_fullscreen (BrowserWindow *bwin);
G_END_DECLS
diff --git a/tools/browser/data-manager/DataSourceEdition.dia b/tools/browser/data-manager/DataSourceEdition.dia
new file mode 100644
index 0000000..97ca7af
Binary files /dev/null and b/tools/browser/data-manager/DataSourceEdition.dia differ
diff --git a/tools/browser/data-manager/Makefile.am b/tools/browser/data-manager/Makefile.am
index 7548c98..f9e130a 100644
--- a/tools/browser/data-manager/Makefile.am
+++ b/tools/browser/data-manager/Makefile.am
@@ -34,6 +34,8 @@ libperspective_la_SOURCES = \
ui-spec-editor.h \
data-manager-perspective.h \
data-manager-perspective.c \
+ data-source-editor.h \
+ data-source-editor.c \
data-source-manager.h \
data-source-manager.c
diff --git a/tools/browser/data-manager/data-console.c b/tools/browser/data-manager/data-console.c
index a935668..8c4b24b 100644
--- a/tools/browser/data-manager/data-console.c
+++ b/tools/browser/data-manager/data-console.c
@@ -37,6 +37,7 @@
#include <libgda/sql-parser/gda-sql-parser.h>
#include <libgda-ui/libgda-ui.h>
#include "data-source-manager.h"
+#include <gdk/gdkkeysyms.h>
#define MAIN_PAGE_EDITORS 0
#define MAIN_PAGE_DATA 1
@@ -78,6 +79,11 @@ struct _DataConsolePrivate {
GtkWidget *popup_container; /* to enter canvas's name */
GtkWidget *name_entry;
GtkWidget *real_save_button;
+
+ GtkWidget *clear_xml_button;
+ GtkWidget *add_source_button;
+ GtkWidget *add_source_menu;
+ gpointer add_source_menu_index; /* used to know if @add_source_menu needs to be rebuilt */
};
static void data_console_class_init (DataConsoleClass *klass);
@@ -85,8 +91,11 @@ static void data_console_init (DataConsole *dconsole, DataConsoleClass *kl
static void data_console_dispose (GObject *object);
static void data_console_show_all (GtkWidget *widget);
static void data_console_grab_focus (GtkWidget *widget);
+static gboolean key_press_event (GtkWidget *widget, GdkEventKey *event);
+
static void data_source_mgr_changed_cb (DataSourceManager *mgr, DataConsole *dconsole);
+static void data_source_source_changed_cb (DataSourceManager *mgr, DataSource *source, DataConsole *dconsole);
/* BrowserPage interface */
static void data_console_page_init (BrowserPageIface *iface);
@@ -109,6 +118,7 @@ data_console_class_init (DataConsoleClass *klass)
GTK_WIDGET_CLASS (klass)->show_all = data_console_show_all;
GTK_WIDGET_CLASS (klass)->grab_focus = data_console_grab_focus;
+ GTK_WIDGET_CLASS (klass)->key_press_event = key_press_event;
object_class->dispose = data_console_dispose;
}
@@ -131,6 +141,25 @@ data_console_grab_focus (GtkWidget *widget)
gtk_widget_grab_focus (GTK_WIDGET (dconsole->priv->xml_sped));
}
+static gboolean
+key_press_event (GtkWidget *widget, GdkEventKey *event)
+{
+ DataConsole *dconsole;
+ dconsole = DATA_CONSOLE (widget);
+ if ((event->keyval == GDK_Escape) &&
+ (gtk_notebook_get_current_page (GTK_NOTEBOOK (dconsole->priv->main_notebook)) == MAIN_PAGE_DATA)) {
+ 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), TRUE);
+ return TRUE;
+ }
+ }
+
+ /* parent class */
+ return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
+}
+
static void
data_console_page_init (BrowserPageIface *iface)
{
@@ -155,6 +184,8 @@ data_console_dispose (GObject *object)
/* free memory */
if (dconsole->priv) {
+ if (dconsole->priv->add_source_menu)
+ gtk_widget_destroy (dconsole->priv->add_source_menu);
if (dconsole->priv->params_form)
gtk_widget_destroy (dconsole->priv->params_form);
if (dconsole->priv->popup_container)
@@ -167,6 +198,9 @@ data_console_dispose (GObject *object)
g_signal_handlers_disconnect_by_func (dconsole->priv->mgr,
G_CALLBACK (data_source_mgr_changed_cb),
dconsole);
+ g_signal_handlers_disconnect_by_func (dconsole->priv->mgr,
+ G_CALLBACK (data_source_source_changed_cb),
+ dconsole);
g_object_unref (dconsole->priv->mgr);
}
g_free (dconsole->priv);
@@ -222,6 +256,7 @@ data_console_new_with_fav_id (BrowserConnection *bcnc, gint fav_id)
}
static void editor_clear_clicked_cb (GtkButton *button, DataConsole *dconsole);
+static void add_source_clicked_cb (GtkButton *button, DataConsole *dconsole);
static void variables_clicked_cb (GtkToggleButton *button, DataConsole *dconsole);
static void execute_clicked_cb (GtkButton *button, DataConsole *dconsole);
#ifdef HAVE_GDU
@@ -246,8 +281,10 @@ data_console_new (BrowserConnection *bcnc)
dconsole->priv->bcnc = g_object_ref (bcnc);
dconsole->priv->mgr = data_source_manager_new (bcnc);
- g_signal_connect (dconsole->priv->mgr, "changed",
+ g_signal_connect (dconsole->priv->mgr, "list-changed",
G_CALLBACK (data_source_mgr_changed_cb), dconsole);
+ g_signal_connect (dconsole->priv->mgr, "source-changed",
+ G_CALLBACK (data_source_source_changed_cb), dconsole);
/* header */
GtkWidget *hbox, *label, *wid;
@@ -329,10 +366,12 @@ data_console_new (BrowserConnection *bcnc)
dconsole->priv->editors_notebook = nb;
dconsole->priv->xml_sped = xml_spec_editor_new (dconsole->priv->mgr);
+ gtk_widget_show (dconsole->priv->xml_sped);
gtk_notebook_append_page (GTK_NOTEBOOK (dconsole->priv->editors_notebook),
dconsole->priv->xml_sped, NULL);
dconsole->priv->ui_sped = ui_spec_editor_new (dconsole->priv->mgr);
+ gtk_widget_show (dconsole->priv->ui_sped);
gtk_notebook_append_page (GTK_NOTEBOOK (dconsole->priv->editors_notebook),
dconsole->priv->ui_sped, NULL);
@@ -342,11 +381,20 @@ data_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 = browser_make_small_button (FALSE, _("Clear"), GTK_STOCK_CLEAR, _("Clear the editor's\ncontents"));
+ button = browser_make_small_button (FALSE, _("Reset"), GTK_STOCK_CLEAR,
+ _("Reset the editor's\ncontents"));
+ dconsole->priv->clear_xml_button = button;
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 (FALSE, _("Add data source"), GTK_STOCK_ADD,
+ _("Add a new data source"));
+ dconsole->priv->add_source_button = button;
+ gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (add_source_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);
@@ -362,7 +410,7 @@ data_console_new (BrowserConnection *bcnc)
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), TRUE);
+ spec_editor_toggled_cb (GTK_TOGGLE_BUTTON (button), dconsole);
g_signal_connect (button, "toggled",
G_CALLBACK (spec_editor_toggled_cb), dconsole);
@@ -416,8 +464,22 @@ data_console_new (BrowserConnection *bcnc)
" 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>"
+#undef DEFAULT_XML
+
+
+#define DEFAULT_XML \
+"<data>\n" \
+" <!--\n\n" \
+" <table name=\"\"/>\n" \
+" <depend foreign_key_table=\"\"/>\n" \
+" </table>\n" \
+" <query title=\"\" id=\"\">\n" \
+" SELECT ...\n" \
+" </query>\n\n" \
+" -->\n" \
+"</data>"
- //xml_spec_editor_set_xml_text (XML_SPEC_EDITOR (dconsole->priv->xml_sped), DEFAULT_XML);
+ xml_spec_editor_set_xml_text (XML_SPEC_EDITOR (dconsole->priv->xml_sped), DEFAULT_XML);
gtk_widget_grab_focus (dconsole->priv->xml_sped);
return (GtkWidget*) dconsole;
@@ -578,8 +640,22 @@ variables_clicked_cb (GtkToggleButton *button, DataConsole *dconsole)
static void
spec_editor_toggled_cb (GtkToggleButton *button, DataConsole *dconsole)
{
+ gint display;
+ display = gtk_toggle_button_get_active (button) ? EDITOR_PAGE_XML : EDITOR_PAGE_UI;
gtk_notebook_set_current_page (GTK_NOTEBOOK (dconsole->priv->editors_notebook),
- (gtk_toggle_button_get_active (button) ? EDITOR_PAGE_XML : EDITOR_PAGE_UI));
+ display);
+ switch (display) {
+ case EDITOR_PAGE_XML:
+ gtk_widget_set_sensitive (dconsole->priv->clear_xml_button, TRUE);
+ gtk_widget_set_sensitive (dconsole->priv->add_source_button, FALSE);
+ break;
+ case EDITOR_PAGE_UI:
+ gtk_widget_set_sensitive (dconsole->priv->clear_xml_button, FALSE);
+ gtk_widget_set_sensitive (dconsole->priv->add_source_button, TRUE);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
}
static void
@@ -593,6 +669,12 @@ param_activated_cb (GdauiBasicForm *form, DataConsole *dconsole)
}
static void
+data_source_source_changed_cb (DataSourceManager *mgr, DataSource *source, DataConsole *dconsole)
+{
+ data_source_mgr_changed_cb (mgr, dconsole);
+}
+
+static void
data_source_mgr_changed_cb (DataSourceManager *mgr, DataConsole *dconsole)
{
if (dconsole->priv->params_form) {
@@ -618,18 +700,100 @@ data_source_mgr_changed_cb (DataSourceManager *mgr, DataConsole *dconsole)
gtk_container_add (GTK_CONTAINER (dconsole->priv->params_form_box),
dconsole->priv->params_form);
gtk_widget_show (dconsole->priv->params_form);
-
- /* force showing variables */
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dconsole->priv->params_toggle), show_variables);
}
static void
editor_clear_clicked_cb (GtkButton *button, DataConsole *dconsole)
{
- xml_spec_editor_set_xml_text (XML_SPEC_EDITOR (dconsole->priv->xml_sped), "");
+ xml_spec_editor_set_xml_text (XML_SPEC_EDITOR (dconsole->priv->xml_sped), DEFAULT_XML);
gtk_widget_grab_focus (dconsole->priv->xml_sped);
}
+static void
+add_source_mitem_activated_cb (GtkMenuItem *mitem, DataConsole *dconsole)
+{
+ const gchar *table;
+ DataSource *source;
+ gchar *str;
+ GSList *list;
+
+ table = (gchar*) g_object_get_data ((GObject*) mitem, "_table");
+ g_print ("Add data source for [%s]\n", table);
+
+ source = data_source_new (dconsole->priv->bcnc, DATA_SOURCE_UNKNOWN);
+ list = (GSList*) data_source_manager_get_sources (dconsole->priv->mgr);
+ str = g_strdup_printf (_("source%d"), g_slist_length (list) + 1);
+ data_source_set_id (source, str);
+ g_free (str);
+ if (table)
+ data_source_set_table (source, table, NULL);
+ else
+ data_source_set_query (source, "SELECT", NULL);
+ data_source_manager_add_source (dconsole->priv->mgr, source);
+ ui_spec_editor_select_source (UI_SPEC_EDITOR (dconsole->priv->ui_sped), source);
+ g_object_unref (source);
+}
+
+static void
+add_source_clicked_cb (GtkButton *button, DataConsole *dconsole)
+{
+ GdaMetaStruct *mstruct;
+ mstruct = browser_connection_get_meta_struct (dconsole->priv->bcnc);
+
+ if (dconsole->priv->add_source_menu &&
+ (dconsole->priv->add_source_menu_index != (gpointer) mstruct)) {
+ gtk_widget_destroy (dconsole->priv->add_source_menu);
+ dconsole->priv->add_source_menu = NULL;
+ dconsole->priv->add_source_menu_index = NULL;
+ }
+ if (dconsole->priv->add_source_menu) {
+ gtk_menu_popup (GTK_MENU (dconsole->priv->add_source_menu), NULL, NULL,
+ NULL, NULL, 0,
+ gtk_get_current_event_time ());
+ return;
+ }
+
+ GtkWidget *menu, *mitem;
+ menu = gtk_menu_new ();
+ mitem = gtk_menu_item_new_with_label (_("Data source from query"));
+ g_signal_connect (mitem, "activate",
+ G_CALLBACK (add_source_mitem_activated_cb), dconsole);
+ gtk_widget_show (mitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
+
+ if (mstruct) {
+ gboolean sep_added = FALSE;
+ GSList *dbo_list, *list;
+ dbo_list = gda_meta_struct_get_all_db_objects (mstruct);
+ for (list = dbo_list; list; list = list->next) {
+ GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (list->data);
+ gchar *str;
+ if (dbo->obj_type != GDA_META_DB_TABLE)
+ continue;
+ if (! sep_added) {
+ mitem = gtk_separator_menu_item_new ();
+ gtk_widget_show (mitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
+ sep_added = TRUE;
+ }
+ str = g_strdup_printf (_("For table: %s"), dbo->obj_short_name);
+ mitem = gtk_menu_item_new_with_label (str);
+ g_object_set_data_full ((GObject*) mitem, "_table",
+ g_strdup (dbo->obj_short_name), g_free);
+ g_signal_connect (mitem, "activate",
+ G_CALLBACK (add_source_mitem_activated_cb), dconsole);
+ gtk_widget_show (mitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
+ }
+ g_slist_free (dbo_list);
+ }
+ dconsole->priv->add_source_menu_index = (gpointer) mstruct;
+ dconsole->priv->add_source_menu = menu;
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+ NULL, NULL, 0,
+ gtk_get_current_event_time ());
+}
+
static GtkWidget *
create_widget (DataConsole *dconsole, GArray *sources_array, GError **error)
{
@@ -666,6 +830,11 @@ compose_mode_toggled_cb (GtkToggleAction *action, DataConsole *dconsole)
{
gint pagenb;
+ /* show variables if necessary */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dconsole->priv->params_toggle),
+ dconsole->priv->params_form &&
+ GDAUI_IS_BASIC_FORM (dconsole->priv->params_form) ? TRUE : FALSE);
+
if (dconsole->priv->toggling) {
dconsole->priv->toggling = FALSE;
return;
@@ -710,6 +879,11 @@ compose_mode_toggled_cb (GtkToggleAction *action, DataConsole *dconsole)
pagenb = MAIN_PAGE_EDITORS;
}
+ if (pagenb == MAIN_PAGE_DATA)
+ browser_show_notice ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) dconsole),
+ "data-manager-exec-mode-switched",
+ _("Switching to execution mode.\n\nHit the Escape key\n"
+ "to return to the compose mode"));
gtk_notebook_set_current_page (GTK_NOTEBOOK (dconsole->priv->main_notebook), pagenb);
}
diff --git a/tools/browser/data-manager/data-manager-perspective.c b/tools/browser/data-manager/data-manager-perspective.c
index bc330f7..e41bbf7 100644
--- a/tools/browser/data-manager/data-manager-perspective.c
+++ b/tools/browser/data-manager/data-manager-perspective.c
@@ -249,15 +249,34 @@ fav_selection_changed_cb (GtkWidget *widget, gint fav_id, BrowserFavoritesType f
{
/* find or create page for this favorite */
GtkWidget *page_contents;
- gint current_page;
+ gint current_page, npages, i;
DataConsole *page_to_reuse = NULL;
if (fav_type != BROWSER_FAVORITES_DATA_MANAGERS)
return;
+ /* change current page if possible */
+ npages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (perspective->priv->notebook));
+ for (i = 0; i < npages; i++) {
+ page_contents = gtk_notebook_get_nth_page (GTK_NOTEBOOK (perspective->priv->notebook),
+ i);
+
+ if (IS_DATA_CONSOLE (page_contents)) {
+ gchar *text;
+ text = data_console_get_text (DATA_CONSOLE (page_contents));
+ if (text && selection && !strcmp (text, selection)) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (perspective->priv->notebook),
+ i);
+ return;
+ }
+ }
+ }
+
+ /* create a new page, or reuse the current empty one */
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);
+ page_contents = gtk_notebook_get_nth_page (GTK_NOTEBOOK (perspective->priv->notebook),
+ current_page);
if (IS_DATA_CONSOLE (page_contents)) {
gchar *text;
diff --git a/tools/browser/data-manager/data-source-editor.c b/tools/browser/data-manager/data-source-editor.c
new file mode 100644
index 0000000..1026d33
--- /dev/null
+++ b/tools/browser/data-manager/data-source-editor.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 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-source-editor.h"
+
+/* signals */
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+gint data_source_editor_signals [LAST_SIGNAL] = { 0 };
+
+/*
+ * Main static functions
+ */
+static void data_source_editor_class_init (DataSourceEditorClass *klass);
+static void data_source_editor_init (DataSourceEditor *editor);
+static void data_source_editor_dispose (GObject *object);
+
+static void attribute_changed_cb (GdaSet *set, GdaHolder *holder, DataSourceEditor *editor);
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+struct _DataSourceEditorPrivate {
+ DataSource *source;
+ GdaSet *attributes;
+ GdauiBasicForm *form;
+};
+
+GType
+data_source_editor_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+ static const GTypeInfo info = {
+ sizeof (DataSourceEditorClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) data_source_editor_class_init,
+ NULL,
+ NULL,
+ sizeof (DataSourceEditor),
+ 0,
+ (GInstanceInitFunc) data_source_editor_init
+ };
+
+
+ g_static_mutex_lock (®istering);
+ if (type == 0)
+ type = g_type_register_static (GTK_TYPE_VBOX, "DataSourceEditor", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+ return type;
+}
+
+static void
+data_source_editor_class_init (DataSourceEditorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ parent_class = g_type_class_peek_parent (klass);
+
+ /* signals */
+ /*data_source_editor_signals [CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (DataSourceEditorClass, changed),
+ NULL, NULL,
+ _dm_marshal_VOID__VOID, G_TYPE_NONE, 0);*/
+
+ object_class->dispose = data_source_editor_dispose;
+}
+
+static void
+data_source_editor_init (DataSourceEditor *editor)
+{
+ editor->priv = g_new0 (DataSourceEditorPrivate, 1);
+ editor->priv->attributes = gda_set_new_inline (4,
+ "id", G_TYPE_STRING, "",
+ "descr", G_TYPE_STRING, "",
+ "table", G_TYPE_STRING, "",
+ "sql", G_TYPE_STRING, "");
+ g_signal_connect (editor->priv->attributes, "holder-changed",
+ G_CALLBACK (attribute_changed_cb), editor);
+
+ GdaHolder *holder;
+ GValue *value;
+ holder = gda_set_get_holder (editor->priv->attributes, "id");
+ g_object_set ((GObject*) holder, "name", _("Id"),
+ "description",
+ _("Data source's ID\n"
+ "(as referenced by other data sources)"), NULL);
+
+ holder = gda_set_get_holder (editor->priv->attributes, "descr");
+ g_object_set ((GObject*) holder, "name", _("Description"),
+ "description", _("Data source's description"), NULL);
+
+ holder = gda_set_get_holder (editor->priv->attributes, "table");
+ g_object_set ((GObject*) holder, "name", _("Table"),
+ "description", _("Table to display data from, leave empty\n"
+ "to specify a SELECT statement instead"), NULL);
+
+ holder = gda_set_get_holder (editor->priv->attributes, "sql");
+ g_object_set ((GObject*) holder, "name", _("SELECT\nSQL"),
+ "description", _("SQL to select data"), NULL);
+ value = gda_value_new_from_string ("text:PROG_LANG=gda-sql", G_TYPE_STRING);
+ gda_holder_set_attribute_static (holder, GDAUI_ATTRIBUTE_PLUGIN, value);
+ gda_value_free (value);
+
+ GtkWidget *form;
+ form = gdaui_basic_form_new (editor->priv->attributes);
+ editor->priv->form = GDAUI_BASIC_FORM (form);
+ gtk_box_pack_start (GTK_BOX (editor), form, TRUE, TRUE, 0);
+ gtk_widget_show (form);
+}
+
+static void
+data_source_editor_dispose (GObject *object)
+{
+ DataSourceEditor *editor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_DATA_SOURCE_EDITOR (object));
+
+ editor = DATA_SOURCE_EDITOR (object);
+ if (editor->priv) {
+ if (editor->priv->source)
+ g_object_unref (editor->priv->source);
+ if (editor->priv->attributes) {
+ g_signal_handlers_disconnect_by_func (editor->priv->attributes,
+ G_CALLBACK (attribute_changed_cb), editor);
+
+ g_object_unref (editor->priv->attributes);
+ }
+
+ g_free (editor->priv);
+ editor->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->dispose (object);
+}
+
+/**
+ * data_source_editor_new
+ *
+ * Creates a new #DataSourceEditor widget
+ *
+ * Returns: a new widget
+ */
+GtkWidget *
+data_source_editor_new (void)
+{
+ DataSourceEditor *editor;
+
+ editor = DATA_SOURCE_EDITOR (g_object_new (DATA_SOURCE_EDITOR_TYPE, NULL));
+
+ return (GtkWidget*) editor;
+}
+
+/**
+ * data_source_editor_display_source
+ * @editor: a #DataSourceEditor widget
+ * @source: the #DataSource for which properties are displayed, or %NULL
+ *
+ * Update @editor's display with @source's properties
+ */
+void
+data_source_editor_display_source (DataSourceEditor *editor, DataSource *source)
+{
+ g_return_if_fail (IS_DATA_SOURCE_EDITOR (editor));
+ g_return_if_fail (! source || IS_DATA_SOURCE (source));
+ GdaStatement *stmt;
+ gchar *sql = NULL;
+
+ g_signal_handlers_block_by_func (editor->priv->attributes,
+ G_CALLBACK (attribute_changed_cb), editor);
+
+ if (editor->priv->source)
+ g_object_unref (editor->priv->source);
+ if (source) {
+ editor->priv->source = g_object_ref (source);
+ g_assert (gda_set_set_holder_value (editor->priv->attributes, NULL,
+ "id", data_source_get_id (source)));
+ g_assert (gda_set_set_holder_value (editor->priv->attributes, NULL,
+ "descr", data_source_get_title (source)));
+ g_assert (gda_set_set_holder_value (editor->priv->attributes, NULL,
+ "table", data_source_get_table (source)));
+ stmt = data_source_get_statement (source);
+ if (stmt)
+ sql = gda_statement_to_sql_extended (stmt, NULL, NULL,
+ GDA_STATEMENT_SQL_PRETTY | GDA_STATEMENT_SQL_PARAMS_SHORT,
+ NULL, NULL);
+ g_assert (gda_set_set_holder_value (editor->priv->attributes, NULL, "sql", sql));
+ g_free (sql);
+
+ switch (data_source_get_source_type (source)) {
+ case DATA_SOURCE_TABLE:
+ gdaui_basic_form_entry_set_editable (editor->priv->form,
+ gda_set_get_holder (editor->priv->attributes, "sql"),
+ FALSE);
+ break;
+ case DATA_SOURCE_SELECT:
+ gdaui_basic_form_entry_set_editable (editor->priv->form,
+ gda_set_get_holder (editor->priv->attributes, "sql"),
+ TRUE);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ }
+ else {
+ editor->priv->source = NULL;
+ g_assert (gda_set_set_holder_value (editor->priv->attributes, NULL,
+ "id", NULL));
+ g_assert (gda_set_set_holder_value (editor->priv->attributes, NULL,
+ "descr", NULL));
+ g_assert (gda_set_set_holder_value (editor->priv->attributes, NULL,
+ "table", NULL));
+ g_assert (gda_set_set_holder_value (editor->priv->attributes, NULL,
+ "sql", NULL));
+ }
+ gtk_widget_set_sensitive (GTK_WIDGET (editor), source ? TRUE : FALSE);
+
+ g_signal_handlers_unblock_by_func (editor->priv->attributes,
+ G_CALLBACK (attribute_changed_cb), editor);
+}
+
+static void
+attribute_changed_cb (GdaSet *set, GdaHolder *holder, DataSourceEditor *editor)
+{
+ const gchar *id, *str = NULL;
+ const GValue *cvalue;
+
+ if (! editor->priv->source)
+ return;
+
+ g_signal_handlers_block_by_func (editor->priv->attributes,
+ G_CALLBACK (attribute_changed_cb), editor);
+
+ id = gda_holder_get_id (holder);
+ cvalue = gda_holder_get_value (holder);
+ if (G_VALUE_TYPE (cvalue) == G_TYPE_STRING)
+ str = g_value_get_string (cvalue);
+
+ g_assert (id);
+ if (!strcmp (id, "id")) {
+ data_source_set_id (editor->priv->source, str);
+ }
+ else if (!strcmp (id, "descr")) {
+ data_source_set_title (editor->priv->source, str);
+ }
+ else if (!strcmp (id, "table")) {
+ GdaHolder *holder;
+ holder = gda_set_get_holder (editor->priv->attributes, "sql");
+
+ if (!str || !*str) {
+ GdaStatement *stmt;
+ gchar *sql = NULL;
+
+ stmt = data_source_get_statement (editor->priv->source);
+ if (stmt)
+ sql = gda_statement_to_sql_extended (stmt, NULL, NULL,
+ GDA_STATEMENT_SQL_PRETTY |
+ GDA_STATEMENT_SQL_PARAMS_SHORT,
+ NULL, NULL);
+ data_source_set_query (editor->priv->source, sql, NULL);
+ g_free (sql);
+ gdaui_basic_form_entry_set_editable (editor->priv->form, holder, TRUE);
+ }
+ else {
+ data_source_set_table (editor->priv->source, str, NULL);
+ gdaui_basic_form_entry_set_editable (editor->priv->form, holder, FALSE);
+
+ GdaStatement *stmt;
+ gchar *sql = NULL;
+
+ stmt = data_source_get_statement (editor->priv->source);
+ if (stmt)
+ sql = gda_statement_to_sql_extended (stmt, NULL, NULL,
+ GDA_STATEMENT_SQL_PRETTY |
+ GDA_STATEMENT_SQL_PARAMS_SHORT,
+ NULL, NULL);
+ g_assert (gda_holder_set_value_str (holder, NULL, sql, NULL));
+ g_free (sql);
+ }
+ }
+ else if (!strcmp (id, "sql"))
+ data_source_set_query (editor->priv->source, str, NULL);
+ else
+ g_assert_not_reached ();
+
+ g_signal_handlers_unblock_by_func (editor->priv->attributes,
+ G_CALLBACK (attribute_changed_cb), editor);
+}
diff --git a/tools/browser/data-manager/data-source-editor.h b/tools/browser/data-manager/data-source-editor.h
new file mode 100644
index 0000000..7ca4437
--- /dev/null
+++ b/tools/browser/data-manager/data-source-editor.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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_EDITOR_H_
+#define __DATA_SOURCE_EDITOR_H_
+
+#include "data-source.h"
+
+G_BEGIN_DECLS
+
+#define DATA_SOURCE_EDITOR_TYPE (data_source_editor_get_type())
+#define DATA_SOURCE_EDITOR(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, data_source_editor_get_type(), DataSourceEditor)
+#define DATA_SOURCE_EDITOR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, data_source_editor_get_type (), DataSourceEditorClass)
+#define IS_DATA_SOURCE_EDITOR(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, data_source_editor_get_type ())
+
+typedef struct _DataSourceEditor DataSourceEditor;
+typedef struct _DataSourceEditorClass DataSourceEditorClass;
+typedef struct _DataSourceEditorPrivate DataSourceEditorPrivate;
+
+/* struct for the object's data */
+struct _DataSourceEditor
+{
+ GtkVBox object;
+ DataSourceEditorPrivate *priv;
+};
+
+/* struct for the object's class */
+struct _DataSourceEditorClass
+{
+ GtkVBoxClass parent_class;
+
+ /* signals */
+ /*void (*changed) (DataSourceEditor *mgr);*/
+};
+
+GType data_source_editor_get_type (void) G_GNUC_CONST;
+
+GtkWidget *data_source_editor_new (void);
+void data_source_editor_display_source (DataSourceEditor *editor, DataSource *source);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/data-manager/data-source-manager.c b/tools/browser/data-manager/data-source-manager.c
index ebabcc1..0986773 100644
--- a/tools/browser/data-manager/data-source-manager.c
+++ b/tools/browser/data-manager/data-source-manager.c
@@ -33,11 +33,12 @@
/* signals */
enum {
- CHANGED,
+ LIST_CHANGED,
+ SOURCE_CHANGED,
LAST_SIGNAL
};
-gint data_source_manager_signals [LAST_SIGNAL] = { 0 };
+gint data_source_manager_signals [LAST_SIGNAL] = { 0, 0 };
/*
* Main static functions
@@ -53,6 +54,7 @@ struct _DataSourceManagerPrivate {
BrowserConnection *bcnc;
GSList *sources_list;
GdaSet *params; /* execution params */
+ gboolean emit_changes;
};
GType
@@ -90,13 +92,23 @@ data_source_manager_class_init (DataSourceManagerClass *klass)
parent_class = g_type_class_peek_parent (klass);
/* signals */
- data_source_manager_signals [CHANGED] =
- g_signal_new ("changed",
+ data_source_manager_signals [LIST_CHANGED] =
+ g_signal_new ("list-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (DataSourceManagerClass, changed),
+ G_STRUCT_OFFSET (DataSourceManagerClass, list_changed),
NULL, NULL,
_dm_marshal_VOID__VOID, G_TYPE_NONE, 0);
+ data_source_manager_signals [SOURCE_CHANGED] =
+ g_signal_new ("source-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (DataSourceManagerClass, source_changed),
+ NULL, NULL,
+ _dm_marshal_VOID__OBJECT, G_TYPE_NONE, 1, DATA_SOURCE_TYPE);
+
+ klass->list_changed = NULL;
+ klass->source_changed = NULL;
object_class->dispose = data_source_manager_dispose;
}
@@ -105,6 +117,13 @@ static void
data_source_manager_init (DataSourceManager *mgr)
{
mgr->priv = g_new0 (DataSourceManagerPrivate, 1);
+ mgr->priv->emit_changes = TRUE;
+}
+
+static void
+source_changed_cb (DataSource *source, DataSourceManager *mgr)
+{
+ g_signal_emit (mgr, data_source_manager_signals[SOURCE_CHANGED], 0, source);
}
static void
@@ -121,7 +140,13 @@ data_source_manager_dispose (GObject *object)
g_object_unref (mgr->priv->params);
if (mgr->priv->sources_list) {
- g_slist_foreach (mgr->priv->sources_list, (GFunc) g_object_unref, NULL);
+ GSList *list;
+ for (list = mgr->priv->sources_list; list; list = list->next) {
+ g_signal_handlers_disconnect_by_func (list->data,
+ G_CALLBACK (source_changed_cb), mgr);
+ g_object_unref ((GObject*) list->data);
+
+ }
g_slist_free (mgr->priv->sources_list);
mgr->priv->sources_list = NULL;
}
@@ -265,43 +290,50 @@ data_source_manager_add_source (DataSourceManager *mgr, DataSource *source)
}
}
}
- g_signal_emit (mgr, data_source_manager_signals[CHANGED], 0);
+ if (mgr->priv->emit_changes)
+ g_signal_emit (mgr, data_source_manager_signals[LIST_CHANGED], 0);
+
+ g_signal_connect (source, "changed",
+ G_CALLBACK (source_changed_cb), mgr);
#ifdef DEBUG_SOURCES_SORT
g_print ("Sources in manager:\n");
-#endif
GSList *list;
gint i;
for (i = 0, list = mgr->priv->sources_list; list; list = list->next, i++) {
DataSource *source = DATA_SOURCE (list->data);
-#ifdef DEBUG_SOURCES_SORT
g_print ("\t %d ... %s\n", i,
data_source_get_title (source));
-#endif
}
-#ifdef DEBUG_SOURCES_SORT
g_print ("\n");
#endif
}
/**
- * data_source_manager_remove_all
- * @mgr:
+ * data_source_manager_replace_all
+ * @mgr: a #DataSourceManager object
+ * @sources_list: a list of #DataSource objects, or %NULL
+ *
+ * Replaces all the data sources by the ones in @sources_list.
*/
void
-data_source_manager_remove_all (DataSourceManager *mgr)
+data_source_manager_replace_all (DataSourceManager *mgr, const GSList *sources_list)
{
+ GSList *list;
g_return_if_fail (IS_DATA_SOURCE_MANAGER (mgr));
- if (mgr->priv->sources_list) {
- GSList *list;
- list = mgr->priv->sources_list;
- mgr->priv->sources_list = NULL;
- g_signal_emit (mgr, data_source_manager_signals[CHANGED], 0);
+ mgr->priv->emit_changes = FALSE;
- g_slist_foreach (list, (GFunc) g_object_unref, NULL);
- g_slist_free (list);
- }
+ /* remove any existing data source */
+ for (; mgr->priv->sources_list; )
+ data_source_manager_remove_source (mgr,
+ DATA_SOURCE (mgr->priv->sources_list->data));
+
+ for (list = sources_list; list; list = list->next)
+ data_source_manager_add_source (mgr, DATA_SOURCE (list->data));
+
+ mgr->priv->emit_changes = TRUE;
+ g_signal_emit (mgr, data_source_manager_signals[LIST_CHANGED], 0);
}
/**
@@ -316,8 +348,11 @@ data_source_manager_remove_source (DataSourceManager *mgr, DataSource *source)
g_return_if_fail (IS_DATA_SOURCE (source));
g_return_if_fail (g_slist_find (mgr->priv->sources_list, source));
+ g_signal_handlers_disconnect_by_func (source,
+ G_CALLBACK (source_changed_cb), mgr);
mgr->priv->sources_list = g_slist_remove (mgr->priv->sources_list, source);
- g_signal_emit (mgr, data_source_manager_signals[CHANGED], 0);
+ if (mgr->priv->emit_changes)
+ g_signal_emit (mgr, data_source_manager_signals[LIST_CHANGED], 0);
g_object_unref (source);
}
@@ -537,3 +572,14 @@ data_source_manager_get_browser_cnc (DataSourceManager *mgr)
g_return_val_if_fail (IS_DATA_SOURCE_MANAGER (mgr), NULL);
return mgr->priv->bcnc;
}
+
+/**
+ * data_source_manager_get_sources
+ * @mgr:
+ */
+const GSList *
+data_source_manager_get_sources (DataSourceManager *mgr)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE_MANAGER (mgr), NULL);
+ return mgr->priv->sources_list;
+}
diff --git a/tools/browser/data-manager/data-source-manager.h b/tools/browser/data-manager/data-source-manager.h
index c5d320c..02bd50d 100644
--- a/tools/browser/data-manager/data-source-manager.h
+++ b/tools/browser/data-manager/data-source-manager.h
@@ -48,7 +48,8 @@ struct _DataSourceManagerClass
GObjectClass parent_class;
/* signals */
- void (*changed) (DataSourceManager *mgr);
+ void (*list_changed) (DataSourceManager *mgr);
+ void (*source_changed) (DataSourceManager *mgr, DataSource *source);
};
GType data_source_manager_get_type (void) G_GNUC_CONST;
@@ -56,7 +57,7 @@ GType data_source_manager_get_type (void) G_GNUC_CONST;
DataSourceManager *data_source_manager_new (BrowserConnection *bcnc);
void data_source_manager_add_source (DataSourceManager *mgr, DataSource *source);
void data_source_manager_remove_source (DataSourceManager *mgr, DataSource *source);
-void data_source_manager_remove_all (DataSourceManager *mgr);
+void data_source_manager_replace_all (DataSourceManager *mgr, const GSList *sources_list);
GdaSet *data_source_manager_get_params (DataSourceManager *mgr);
BrowserConnection *data_source_manager_get_browser_cnc (DataSourceManager *mgr);
@@ -64,6 +65,8 @@ BrowserConnection *data_source_manager_get_browser_cnc (DataSourceManager *mgr
GArray *data_source_manager_get_sources_array (DataSourceManager *mgr, GError **error);
void data_source_manager_destroy_sources_array (GArray *array);
+const GSList *data_source_manager_get_sources (DataSourceManager *mgr);
+
G_END_DECLS
diff --git a/tools/browser/data-manager/data-source.c b/tools/browser/data-manager/data-source.c
index 74cfdfe..b53efaf 100644
--- a/tools/browser/data-manager/data-source.c
+++ b/tools/browser/data-manager/data-source.c
@@ -32,12 +32,13 @@
/* signals */
enum {
+ CHANGED,
EXEC_STARTED,
EXEC_FINISHED,
LAST_SIGNAL
};
-gint data_source_signals [LAST_SIGNAL] = {0, 0};
+gint data_source_signals [LAST_SIGNAL] = {0, 0, 0};
/*
* Main static functions
@@ -46,22 +47,33 @@ static void data_source_class_init (DataSourceClass *klass);
static void data_source_init (DataSource *source);
static void data_source_dispose (GObject *object);
+
+static void compute_stmt_and_params (DataSource *source);
+static void compute_import_params (DataSource *source);
+
+
/* 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 *impl_title;
gchar *id;
+ DataSourceType source_type;
+
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;
gboolean executing;
gboolean exec_again;
+ gchar *tablename;
+ GdaSqlBuilder *builder;
+ GSList *dependencies; /* list of strings of table name or ID */
+
GdaStatement *stmt;
GdaSet *ext_params; /* "free" parameters */
GdaSet *params; /* all the params used when executing @stmt */
@@ -107,6 +119,13 @@ data_source_class_init (DataSourceClass *klass)
parent_class = g_type_class_peek_parent (klass);
/* signals */
+ data_source_signals [CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (DataSourceClass, changed),
+ NULL, NULL,
+ _dm_marshal_VOID__VOID, G_TYPE_NONE, 0);
data_source_signals [EXEC_STARTED] =
g_signal_new ("execution-started",
G_TYPE_FROM_CLASS (object_class),
@@ -121,6 +140,7 @@ data_source_class_init (DataSourceClass *klass)
G_STRUCT_OFFSET (DataSourceClass, execution_finished),
NULL, NULL,
_dm_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+ klass->changed = NULL;
klass->execution_started = NULL;
klass->execution_finished = NULL;
@@ -132,6 +152,7 @@ data_source_init (DataSource *source)
{
source->priv = g_new0 (DataSourcePrivate, 1);
source->priv->bcnc = NULL;
+ source->priv->source_type = DATA_SOURCE_UNKNOWN;
source->priv->need_rerun = FALSE;
source->priv->exec_id = 0;
source->priv->executing = FALSE;
@@ -155,6 +176,61 @@ ext_params_changed_cb (GdaSet *params, GdaHolder *holder, DataSource *source)
}
static void
+data_source_reset (DataSource *source)
+{
+ source->priv->source_type = DATA_SOURCE_UNKNOWN;
+ g_clear_error (& source->priv->init_error);
+
+ if (source->priv->builder) {
+ g_object_unref (source->priv->builder);
+ source->priv->builder = NULL;
+ }
+ if (source->priv->stmt) {
+ g_object_unref (source->priv->stmt);
+ source->priv->stmt = NULL;
+ }
+ 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);
+ source->priv->params = NULL;
+ }
+ if (source->priv->ext_params) {
+ g_signal_handlers_disconnect_by_func (source->priv->ext_params,
+ G_CALLBACK (ext_params_changed_cb),
+ source);
+ g_object_unref (source->priv->ext_params);
+ source->priv->ext_params = NULL;
+ }
+
+ if (source->priv->tablename) {
+ g_free (source->priv->tablename);
+ source->priv->tablename = NULL;
+ }
+
+ if (source->priv->dependencies) {
+ g_slist_foreach (source->priv->dependencies, (GFunc) g_free, NULL);
+ g_slist_free (source->priv->dependencies);
+ source->priv->dependencies = NULL;
+ }
+
+ if (source->priv->model) {
+ g_object_unref (source->priv->model);
+ source->priv->model = NULL;
+ }
+
+ if (source->priv->export_names) {
+ g_array_free (source->priv->export_names, TRUE);
+ source->priv->export_names = NULL;
+ }
+
+ if (source->priv->export_columns) {
+ g_hash_table_destroy (source->priv->export_columns);
+ source->priv->export_columns = NULL;
+ }
+}
+
+static void
data_source_dispose (GObject *object)
{
DataSource *source;
@@ -166,33 +242,10 @@ data_source_dispose (GObject *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);
- }
- if (source->priv->ext_params) {
- g_signal_handlers_disconnect_by_func (source->priv->ext_params,
- G_CALLBACK (ext_params_changed_cb),
- source);
- g_object_unref (source->priv->ext_params);
- }
-
+ data_source_reset (source);
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->impl_title);
g_free (source->priv);
source->priv = NULL;
@@ -208,6 +261,28 @@ static gboolean init_from_table_node (DataSource *source, xmlNodePtr node, GErro
/**
* data_source_new
* @bcnc: a #BrowserConnection
+ * @type: the new data source's requested type
+ *
+ * Returns: a new #DataSource object
+ */
+DataSource *
+data_source_new (BrowserConnection *bcnc, DataSourceType type)
+{
+ DataSource *source;
+
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+
+ source = DATA_SOURCE (g_object_new (DATA_SOURCE_TYPE, NULL));
+ source->priv->bcnc = g_object_ref (bcnc);
+ source->priv->source_type = type;
+ source->priv->id = g_strdup ("NewSource");
+
+ return source;
+}
+
+/**
+ * data_source_new_from_xml_node
+ * @bcnc: a #BrowserConnection
* @node:
* @error:
*
@@ -260,97 +335,14 @@ data_source_new_from_xml_node (BrowserConnection *bcnc, xmlNodePtr node, GError
static void
init_from_query (DataSource *source, xmlNodePtr node)
{
- GdaSqlParser *parser;
- const gchar *remain;
xmlChar *contents;
#ifdef DEBUG_SOURCE
g_print ("%s(%s [%s])\n", __FUNCTION__, source->priv->id, source->priv->title);
#endif
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+1);
- g_array_append_val (source->priv->export_names, tmp);
- g_hash_table_insert (source->priv->export_columns, tmp,
- GINT_TO_POINTER (i + 1));
-#ifdef DEBUG_SOURCE
- g_print ("\tEXPORT [%s]\n", tmp);
-#endif
-
- 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));
-#ifdef DEBUG_SOURCE
- g_print ("\tEXPORT [%s]\n", tmp);
-#endif
- }
- }
- }
- }
- 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);
-#ifdef DEBUG_SOURCE
- g_print ("\tIMPORT [%s]\n", gda_holder_get_id (GDA_HOLDER (list->data)));
-#endif
- }
-
- g_signal_connect (source->priv->params, "holder-changed",
- G_CALLBACK (params_changed_cb), source);
- }
- }
-
-#ifdef DEBUG_SOURCE
- g_print ("\n");
-#endif
+ data_source_set_query (source, (gchar*) contents, &source->priv->init_error);
}
static GdaMetaTable *
@@ -404,6 +396,7 @@ static gboolean
init_from_table_node (DataSource *source, xmlNodePtr node, GError **error)
{
xmlChar *tname;
+ gboolean retval;
#ifdef DEBUG_SOURCE
g_print ("%s(%s [%s])\n", __FUNCTION__, source->priv->id, source->priv->title);
@@ -415,79 +408,8 @@ init_from_table_node (DataSource *source, xmlNodePtr node, GError **error)
_("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;
- }
- gda_sql_builder_select_set_limit (b,
- gda_sql_builder_add_expr (b, NULL,
- G_TYPE_INT, DEFAULT_DATA_SELECT_LIMIT),
- 0);
-
- 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);
- if (mcol->pkey) {
- /* ORDER BY */
- gda_sql_builder_select_order_by (b,
- gda_sql_builder_add_id (b,
- mcol->column_name),
- FALSE, 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));
-#ifdef DEBUG_SOURCE
- g_print ("\tEXPORT [%s]\n", tmp);
-#endif
-
- 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));
-#ifdef DEBUG_SOURCE
- g_print ("\tEXPORT [%s]\n", tmp);
-#endif
- }
+ retval = data_source_set_table (source, (gchar*) tname, error);
xmlFree (tname);
/* linking */
@@ -495,82 +417,11 @@ init_from_table_node (DataSource *source, xmlNodePtr node, GError **error)
for (subnode = node->children; subnode; subnode = subnode->next) {
if (!strcmp ((gchar*)subnode->name, "depend")) {
xmlChar *fk_table, *id;
- GdaMetaTable *mlinked;
fk_table = xmlGetProp (subnode, BAD_CAST "foreign_key_table");
- mlinked = get_meta_table (source, (gchar*) fk_table, error);
- if (!mlinked) {
- xmlFree (fk_table);
- 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*) fk_table);
- xmlFree (fk_table);
- 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*) fk_table);
- xmlFree (fk_table);
- if (id) xmlFree (id);
- g_object_unref (b);
- return FALSE;
- }
- else if (fk->cols_nb == 1) {
- gchar *tmp;
- GdaMetaTableColumn *col;
- const GdaSqlBuilderId id1 = gda_sql_builder_add_id (b, fk->fk_names_array [0]);
- tmp = g_strdup_printf ("%s %s", id ? (gchar*) id : (gchar*) fk_table,
- fk->ref_pk_names_array [0]);
-
- col = GDA_META_TABLE_COLUMN (g_slist_nth_data (mlinked->columns,
- fk->ref_pk_cols_array [0] - 1));
- g_assert (col);
- const GdaSqlBuilderId id2 = gda_sql_builder_add_param (b, tmp, col->gtype, FALSE);
- g_free (tmp);
- const GdaSqlBuilderId id_cond = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_EQ, id1, id2, 0);
- gda_sql_builder_set_where (b, id_cond);
- }
- else {
- gchar *tmp;
- gint i;
- GdaMetaTableColumn *col;
- GdaSqlBuilderId andid;
- GdaSqlBuilderId *op_ids;
- op_ids = g_new (GdaSqlBuilderId, fk->cols_nb);
-
- for (i = 0; i < fk->cols_nb; i++) {
- const GdaSqlBuilderId id1 = gda_sql_builder_add_id (b, fk->fk_names_array [i]);
- tmp = g_strdup_printf ("%s %s", id ? (gchar*) id : (gchar*) fk_table,
- fk->ref_pk_names_array [i]);
-
- col = GDA_META_TABLE_COLUMN (g_slist_nth_data (mlinked->columns,
- fk->ref_pk_cols_array [i] - 1));
- g_assert (col);
- const GdaSqlBuilderId id2 = gda_sql_builder_add_param (b, tmp, col->gtype, FALSE);
- g_free (tmp);
- op_ids [i] = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_EQ, id1, id2, 0);
- }
- andid = gda_sql_builder_add_cond_v (b, GDA_SQL_OPERATOR_TYPE_AND, op_ids, fk->cols_nb);
- g_free (op_ids);
- gda_sql_builder_set_where (b, andid);
- }
-
+ data_source_add_dependendency (source, (gchar *) fk_table, (gchar*) id, error);
xmlFree (fk_table);
if (id)
xmlFree (id);
@@ -578,31 +429,108 @@ init_from_table_node (DataSource *source, xmlNodePtr node, GError **error)
}
}
- source->priv->stmt = gda_sql_builder_get_statement (b, error);
+ return retval;
+}
- /* 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);
-#ifdef DEBUG_SOURCE
- g_print ("\tIMPORT [%s]\n", gda_holder_get_id (GDA_HOLDER (list->data)));
-#endif
- }
+/**
+ * data_source_add_dependendency
+ * @source: a #DataSource
+ * @table: the name of the referenced table
+ * @id: the ID of the referenced data source, or %NULL if its ID is the same as the table name
+ *
+ * Adds a dependency on the @table table, only for DATA_SOURCE_TABLE sources
+ */
+gboolean
+data_source_add_dependendency (DataSource *source, const gchar *table,
+ const char *id, GError **error)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), FALSE);
+ g_return_val_if_fail (table && *table, FALSE);
+ g_return_val_if_fail (source->priv->source_type == DATA_SOURCE_TABLE, FALSE);
+ g_return_val_if_fail (source->priv->builder, FALSE);
- g_signal_connect (source->priv->params, "holder-changed",
- G_CALLBACK (params_changed_cb), source);
+ if (g_slist_find (source->priv->dependencies, id ? id : table))
+ return TRUE;
+
+ GdaMetaTable *mtable, *mlinked;
+ mtable = get_meta_table (source, source->priv->tablename, error);
+ if (!mtable)
+ return FALSE;
+
+ mlinked = get_meta_table (source, table, error);
+ if (!mlinked)
+ return FALSE;
+
+ /* find foreign key to linked table */
+ GdaMetaTableForeignKey *fk = NULL;
+ GSList *list;
+ 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\""), table);
+ 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"),
+ table);
+ return FALSE;
+ }
+ else if (fk->cols_nb == 1) {
+ gchar *tmp;
+ GdaMetaTableColumn *col;
+ const GdaSqlBuilderId id1 = gda_sql_builder_add_id (source->priv->builder,
+ fk->fk_names_array [0]);
+ tmp = g_strdup_printf ("%s %s", id ? id : table, fk->ref_pk_names_array [0]);
+
+ col = GDA_META_TABLE_COLUMN (g_slist_nth_data (mlinked->columns,
+ fk->ref_pk_cols_array [0] - 1));
+ g_assert (col);
+ const GdaSqlBuilderId id2 = gda_sql_builder_add_param (source->priv->builder, tmp,
+ col->gtype, FALSE);
+ g_free (tmp);
+ const GdaSqlBuilderId id_cond = gda_sql_builder_add_cond (source->priv->builder,
+ GDA_SQL_OPERATOR_TYPE_EQ,
+ id1, id2, 0);
+ gda_sql_builder_set_where (source->priv->builder, id_cond);
+ }
+ else {
+ gchar *tmp;
+ gint i;
+ GdaMetaTableColumn *col;
+ GdaSqlBuilderId andid;
+ GdaSqlBuilderId *op_ids;
+ op_ids = g_new (GdaSqlBuilderId, fk->cols_nb);
+
+ for (i = 0; i < fk->cols_nb; i++) {
+ const GdaSqlBuilderId id1 = gda_sql_builder_add_id (source->priv->builder,
+ fk->fk_names_array [i]);
+ tmp = g_strdup_printf ("%s %s", id ? id : table, fk->ref_pk_names_array [i]);
+
+ col = GDA_META_TABLE_COLUMN (g_slist_nth_data (mlinked->columns,
+ fk->ref_pk_cols_array [i] - 1));
+ g_assert (col);
+ const GdaSqlBuilderId id2 = gda_sql_builder_add_param (source->priv->builder,
+ tmp, col->gtype, FALSE);
+ g_free (tmp);
+ op_ids [i] = gda_sql_builder_add_cond (source->priv->builder, GDA_SQL_OPERATOR_TYPE_EQ,
+ id1, id2, 0);
+ }
+ andid = gda_sql_builder_add_cond_v (source->priv->builder, GDA_SQL_OPERATOR_TYPE_AND,
+ op_ids, fk->cols_nb);
+ g_free (op_ids);
+ gda_sql_builder_set_where (source->priv->builder, andid);
}
- /*g_print ("SQL [%s]\n", gda_statement_to_sql (source->priv->stmt, NULL, NULL));*/
- g_object_unref (b);
+ source->priv->dependencies = g_slist_append (source->priv->dependencies, g_strdup (id ? id : table));
-#ifdef DEBUG_SOURCE
- g_print ("\n");
-#endif
- return source->priv->stmt ? TRUE : FALSE;
+ compute_stmt_and_params (source);
+ return TRUE;
}
@@ -612,8 +540,54 @@ init_from_table_node (DataSource *source, xmlNodePtr node, GError **error)
xmlNodePtr
data_source_to_xml_node (DataSource *source)
{
- TO_IMPLEMENT;
- return NULL;
+ xmlNodePtr node = NULL;
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+ switch (source->priv->source_type) {
+ case DATA_SOURCE_TABLE:
+ node = xmlNewNode (NULL, BAD_CAST "table");
+ if (source->priv->id && g_strcmp0 (source->priv->id, source->priv->tablename))
+ xmlSetProp (node, BAD_CAST "id", BAD_CAST source->priv->id);
+ if (source->priv->title && g_strcmp0 (source->priv->title, source->priv->tablename))
+ xmlSetProp (node, BAD_CAST "title", BAD_CAST source->priv->title);
+ xmlSetProp (node, BAD_CAST "name",
+ BAD_CAST (source->priv->tablename ? source->priv->tablename : ""));
+
+ if (source->priv->dependencies) {
+ GSList *list;
+ for (list = source->priv->dependencies; list; list = list->next) {
+ xmlNodePtr depnode;
+ depnode = xmlNewChild (node, NULL, BAD_CAST "depend", NULL);
+ xmlSetProp (depnode, BAD_CAST "foreign_key_table",
+ BAD_CAST (list->data));
+ }
+ }
+ break;
+ case DATA_SOURCE_SELECT: {
+ node = xmlNewNode (NULL, BAD_CAST "query");
+ if (source->priv->id)
+ xmlSetProp (node, BAD_CAST "id", BAD_CAST source->priv->id);
+ if (source->priv->title)
+ xmlSetProp (node, BAD_CAST "title", BAD_CAST source->priv->title);
+
+ if (source->priv->stmt) {
+ gchar *sql;
+ sql = gda_statement_to_sql_extended (source->priv->stmt, NULL, NULL,
+ GDA_STATEMENT_SQL_PRETTY |
+ GDA_STATEMENT_SQL_PARAMS_SHORT, NULL, NULL);
+ if (sql) {
+ xmlNodeSetContent (node, BAD_CAST sql);
+ g_free (sql);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (node) {
+ }
+ return node;
}
static gboolean
@@ -856,7 +830,7 @@ data_source_create_grid (DataSource *source)
GtkWidget *fg;
GdauiRawGrid *grid;
- fg = (GdauiRawGrid*) ui_formgrid_new (source->priv->model, 0);
+ fg = ui_formgrid_new (source->priv->model, 0);
grid = ui_formgrid_get_grid_widget (UI_FORMGRID (fg));
GList *columns, *list;
@@ -899,7 +873,61 @@ data_source_create_grid (DataSource *source)
}
/**
+ * data_source_set_id
+ * @source: a #DataSource
+ * @id: the new source's ID
+ *
+ * @source MUST NOT be executed when calling this method.
+ */
+void
+data_source_set_id (DataSource *source, const gchar * id)
+{
+ g_return_if_fail (IS_DATA_SOURCE (source));
+ g_return_if_fail (! data_source_execution_going_on (source));
+
+ g_free (source->priv->id);
+ if (id)
+ source->priv->id = g_strdup (id);
+ g_signal_emit (source, data_source_signals [CHANGED], 0);
+}
+
+
+/**
+ * data_source_get_id
+ * @source: a #DataSource
+ *
+ * Returns: the ID, or %NULL if no ID has been defined
+ */
+const gchar *
+data_source_get_id (DataSource *source)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+
+ return source->priv->id;
+}
+
+/**
+ * data_source_set_title
+ * @source: a #DataSource
+ * @title: the new source's TITLE
+ *
+ * @source MUST NOT be executed when calling this method.
+ */
+void
+data_source_set_title (DataSource *source, const gchar * title)
+{
+ g_return_if_fail (IS_DATA_SOURCE (source));
+ g_return_if_fail (! data_source_execution_going_on (source));
+
+ g_free (source->priv->title);
+ if (title)
+ source->priv->title = g_strdup (title);
+ g_signal_emit (source, data_source_signals [CHANGED], 0);
+}
+
+/**
* data_source_get_title
+ * @source: a #DataSource
*/
const gchar *
data_source_get_title (DataSource *source)
@@ -908,6 +936,8 @@ data_source_get_title (DataSource *source)
if (source->priv->title)
return source->priv->title;
+ else if (source->priv->impl_title)
+ return source->priv->impl_title;
else if (source->priv->id)
return source->priv->id;
else
@@ -915,6 +945,262 @@ data_source_get_title (DataSource *source)
}
/**
+ * data_source_set_table
+ *
+ * @source MUST NOT be executed when calling this method.
+ */
+gboolean
+data_source_set_table (DataSource *source, const gchar *table, GError **error)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), FALSE);
+ g_return_val_if_fail (! data_source_execution_going_on (source), FALSE);
+
+ data_source_reset (source);
+ if (!table)
+ return FALSE;
+
+ /* locate table */
+ GdaMetaTable *mtable;
+ mtable = get_meta_table (source, table, error);
+ if (!mtable)
+ return FALSE;
+
+ source->priv->source_type = DATA_SOURCE_TABLE;
+ source->priv->tablename = g_strdup (table);
+
+ g_free (source->priv->impl_title);
+ source->priv->impl_title = g_strdup_printf (_("Contents of '%s'"), table);
+
+ g_free (source->priv->id);
+ source->priv->id = g_strdup ((gchar*) table);
+
+ /* build statement */
+ GSList *list;
+ GdaSqlBuilder *b;
+ gint i;
+
+ b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
+ source->priv->builder = b;
+ if (! gda_sql_builder_select_add_target (b, table, NULL)) {
+ g_set_error (error, 0, 0,
+ _("Could not build SELECT statement"));
+ return FALSE;
+ }
+ gda_sql_builder_select_set_limit (b,
+ gda_sql_builder_add_expr (b, NULL,
+ G_TYPE_INT, DEFAULT_DATA_SELECT_LIMIT),
+ 0);
+
+ 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);
+
+ if (mcol->pkey) {
+ /* ORDER BY */
+ gda_sql_builder_select_order_by (b,
+ gda_sql_builder_add_id (b,
+ mcol->column_name),
+ FALSE, 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", table, 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));
+#ifdef DEBUG_SOURCE
+ g_print ("\tEXPORT [%s]\n", tmp);
+#endif
+
+ if (source->priv->id)
+ tmp = g_strdup_printf ("%s %d", source->priv->id, i + 1);
+ else
+ tmp = g_strdup_printf ("%s %d", table, 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));
+#ifdef DEBUG_SOURCE
+ g_print ("\tEXPORT [%s]\n", tmp);
+#endif
+ }
+
+ /* compute statement & parameters */
+ compute_stmt_and_params (source);
+ /*g_print ("SQL [%s]\n", gda_statement_to_sql (source->priv->stmt, NULL, NULL));*/
+
+#ifdef DEBUG_SOURCE
+ g_print ("\n");
+#endif
+
+ g_signal_emit (source, data_source_signals [CHANGED], 0);
+ return source->priv->stmt ? TRUE : FALSE;
+}
+
+/**
+ * data_source_set_query
+ *
+ * @source MUST NOT be executed when calling this method.
+ */
+void
+data_source_set_query (DataSource *source, const gchar *sql, GError **warning)
+{
+ g_return_if_fail (IS_DATA_SOURCE (source));
+ g_return_if_fail (! data_source_execution_going_on (source));
+
+ data_source_reset (source);
+
+ source->priv->source_type = DATA_SOURCE_SELECT;
+ if (!sql) {
+ g_signal_emit (source, data_source_signals [CHANGED], 0);
+ return;
+ }
+
+ GdaSqlParser *parser;
+ const gchar *remain;
+ parser = browser_connection_create_parser (source->priv->bcnc);
+ source->priv->stmt = gda_sql_parser_parse_string (parser, sql,
+ &remain, warning);
+ g_object_unref (parser);
+ if (!source->priv->stmt) {
+ g_signal_emit (source, data_source_signals [CHANGED], 0);
+ return;
+ }
+
+ if (remain)
+ g_set_error (warning, 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+1);
+ g_array_append_val (source->priv->export_names, tmp);
+ g_hash_table_insert (source->priv->export_columns, tmp,
+ GINT_TO_POINTER (i + 1));
+#ifdef DEBUG_SOURCE
+ g_print ("\tEXPORT [%s]\n", tmp);
+#endif
+
+ 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));
+#ifdef DEBUG_SOURCE
+ g_print ("\tEXPORT [%s]\n", tmp);
+#endif
+ }
+ }
+ }
+ }
+ gda_sql_statement_free (sqlst);
+
+ /* compute parameters */
+ source->priv->need_rerun = FALSE;
+ compute_import_params (source);
+
+#ifdef DEBUG_SOURCE
+ g_print ("\n");
+#endif
+
+ g_signal_emit (source, data_source_signals [CHANGED], 0);
+}
+
+static void
+compute_stmt_and_params (DataSource *source)
+{
+ g_assert (source->priv->builder);
+ if (source->priv->stmt)
+ g_object_unref (source->priv->stmt);
+ source->priv->stmt = gda_sql_builder_get_statement (source->priv->builder, NULL);
+ compute_import_params (source);
+}
+
+static void
+compute_import_params (DataSource *source)
+{
+ 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);
+ source->priv->params = NULL;
+ }
+ g_clear_error (& source->priv->init_error);
+
+ 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);
+#ifdef DEBUG_SOURCE
+ g_print ("\tIMPORT [%s]\n", gda_holder_get_id (GDA_HOLDER (list->data)));
+#endif
+ }
+
+ g_signal_connect (source->priv->params, "holder-changed",
+ G_CALLBACK (params_changed_cb), source);
+ }
+}
+
+/**
+ * data_source_get_table
+ * @source: a #DataSource
+ *
+ * Returns: the name of the table used by @source, if its type is %DATA_SOURCE_TABLE
+ */
+const gchar *
+data_source_get_table (DataSource *source)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), NULL);
+ return source->priv->tablename;
+}
+
+/**
+ * data_source_get_source_type
+ */
+DataSourceType
+data_source_get_source_type (DataSource *source)
+{
+ g_return_val_if_fail (IS_DATA_SOURCE (source), DATA_SOURCE_UNKNOWN);
+ return source->priv->source_type;
+}
+
+/**
* data_source_should_rerun
*
* The SELECT statement will be re-executed the next time
diff --git a/tools/browser/data-manager/data-source.h b/tools/browser/data-manager/data-source.h
index b7dd4c9..5968931 100644
--- a/tools/browser/data-manager/data-source.h
+++ b/tools/browser/data-manager/data-source.h
@@ -36,6 +36,12 @@ typedef struct _DataSource DataSource;
typedef struct _DataSourceClass DataSourceClass;
typedef struct _DataSourcePrivate DataSourcePrivate;
+typedef enum {
+ DATA_SOURCE_UNKNOWN,
+ DATA_SOURCE_TABLE,
+ DATA_SOURCE_SELECT,
+} DataSourceType;
+
/* struct for the object's data */
struct _DataSource
{
@@ -49,15 +55,34 @@ struct _DataSourceClass
GObjectClass parent_class;
/* signals */
+ void (*changed) (DataSource *source);
void (*execution_started) (DataSource *source);
void (*execution_finished) (DataSource *source, GError *error);
};
GType data_source_get_type (void) G_GNUC_CONST;
+DataSourceType data_source_get_source_type (DataSource *source);
+void data_source_set_id (DataSource *source, const gchar *id);
+const gchar *data_source_get_id (DataSource *source);
+void data_source_set_title (DataSource *source, const gchar *title);
+const gchar *data_source_get_title (DataSource *source);
+
+/* Data source as table API */
+gboolean data_source_set_table (DataSource *source, const gchar *table, GError **error);
+const gchar *data_source_get_table (DataSource *source);
+gboolean data_source_add_dependendency (DataSource *source, const gchar *table,
+ const char *id, GError **error);
+
+/* Data source as SQL query API */
+void data_source_set_query (DataSource *source, const gchar *sql, GError **warning);
+
+/* other API */
+DataSource *data_source_new (BrowserConnection *bcnc, DataSourceType type);
DataSource *data_source_new_from_xml_node (BrowserConnection *bcnc, xmlNodePtr node, GError **error);
void data_source_set_params (DataSource *source, GdaSet *params);
xmlNodePtr data_source_to_xml_node (DataSource *source);
+
GdaStatement *data_source_get_statement (DataSource *source);
GdaSet *data_source_get_import (DataSource *source);
@@ -67,7 +92,6 @@ GHashTable *data_source_get_export_columns (DataSource *source);
void data_source_execute (DataSource *source, GError **error);
gboolean data_source_execution_going_on (DataSource *source);
GtkWidget *data_source_create_grid (DataSource *source);
-const gchar *data_source_get_title (DataSource *source);
/*
DataSource *data_source_new_from_table (BrowserConnection *bcnc,
diff --git a/tools/browser/data-manager/marshal.list b/tools/browser/data-manager/marshal.list
index 9ab3792..d2dbeee 100644
--- a/tools/browser/data-manager/marshal.list
+++ b/tools/browser/data-manager/marshal.list
@@ -25,3 +25,4 @@
VOID:VOID
VOID:POINTER
VOID:INT,ENUM,STRING
+VOID:OBJECT
diff --git a/tools/browser/data-manager/ui-spec-editor.c b/tools/browser/data-manager/ui-spec-editor.c
index 2e43b09..8272428 100644
--- a/tools/browser/data-manager/ui-spec-editor.c
+++ b/tools/browser/data-manager/ui-spec-editor.c
@@ -26,22 +26,20 @@
#include "data-source.h"
#include <libgda/libgda.h>
#include "../support.h"
+#include "data-source-editor.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
+enum
+{
+ COLUMN_DATA_SOURCE,
+ NUM_COLUMNS
+};
struct _UiSpecEditorPrivate {
DataSourceManager *mgr;
-
+ GtkListStore *sources_model;
+ GtkWidget *sources_tree;
+ DataSourceEditor *propsedit;
+
/* warnings */
GtkWidget *info;
};
@@ -65,6 +63,73 @@ ui_spec_editor_class_init (UiSpecEditorClass *klass)
object_class->dispose = ui_spec_editor_dispose;
}
+static void
+cell_text_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ DataSource *source;
+ gtk_tree_model_get (tree_model, iter, COLUMN_DATA_SOURCE, &source, -1);
+ g_assert (source);
+
+ GString *mark;
+ const gchar *id, *str;
+ mark = g_string_new ("");
+ /* FIXME: add source ID */
+ id = NULL;
+
+ str = data_source_get_id (source);
+ if (str)
+ g_string_append (mark, str);
+ else
+ g_string_append_c (mark, '-');
+ str = data_source_get_title (source);
+ if (str) {
+ if (!id || strcmp ((gchar*) id, (gchar*) str)) {
+ gchar *tmp;
+ tmp = g_markup_escape_text ((gchar*) str, -1);
+ g_string_append_printf (mark, "\n<small><i>%s</i></small>", tmp);
+ g_free (tmp);
+ }
+ }
+
+ g_object_set (cell, "markup", mark->str, NULL);
+ g_string_free (mark, TRUE);
+}
+
+static void
+cell_pixbuf_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ DataSource *source;
+ gtk_tree_model_get (tree_model, iter, COLUMN_DATA_SOURCE, &source, -1);
+ g_assert (source);
+
+ DataSourceType stype;
+ stype = data_source_get_source_type (source);
+ switch (stype) {
+ case DATA_SOURCE_TABLE:
+ g_object_set (cell, "pixbuf", browser_get_pixbuf_icon (BROWSER_ICON_TABLE), NULL);
+ break;
+ case DATA_SOURCE_SELECT:
+ g_object_set (cell, "pixbuf", browser_get_pixbuf_icon (BROWSER_ICON_QUERY), NULL);
+ break;
+ default:
+ g_object_set (cell, "pixbuf", NULL, NULL);
+ break;
+ }
+}
+
+static void
+data_source_selection_changed_cb (GtkTreeSelection *sel, UiSpecEditor *uied)
+{
+ GtkTreeIter iter;
+ if (gtk_tree_selection_get_selected (sel, NULL, &iter)) {
+ DataSource *source;
+ gtk_tree_model_get (GTK_TREE_MODEL (uied->priv->sources_model), &iter,
+ COLUMN_DATA_SOURCE, &source, -1);
+ data_source_editor_display_source (uied->priv->propsedit, source);
+ }
+}
static void
ui_spec_editor_init (UiSpecEditor *sped, UiSpecEditorClass *klass)
@@ -73,6 +138,84 @@ ui_spec_editor_init (UiSpecEditor *sped, UiSpecEditorClass *klass)
/* allocate private structure */
sped->priv = g_new0 (UiSpecEditorPrivate, 1);
+
+ GtkWidget *hpaned;
+ hpaned = gtk_hpaned_new ();
+ gtk_box_pack_start (GTK_BOX (sped), hpaned, TRUE, TRUE, 0);
+
+ GtkWidget *vbox;
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_paned_add1 (GTK_PANED (hpaned), vbox);
+
+ GtkWidget *label;
+ gchar *str;
+ label = gtk_label_new ("");
+ str = g_strdup_printf ("<b>%s</b>", _("Data sources:"));
+ 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);
+
+ /* data sources model & view */
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ sped->priv = g_new0 (UiSpecEditorPrivate, 1);
+ sped->priv->sources_model = gtk_list_store_new (NUM_COLUMNS,
+ G_TYPE_POINTER);
+
+ sped->priv->sources_tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (sped->priv->sources_model));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (sped->priv->sources_tree), FALSE);
+ gtk_widget_set_size_request (sped->priv->sources_tree, 120, -1);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_set_cell_data_func (column, renderer,
+ (GtkTreeCellDataFunc) cell_pixbuf_data_func,
+ NULL, NULL);
+
+ 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_text_data_func,
+ NULL, NULL);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (sped->priv->sources_tree), column);
+
+ GtkTreeSelection *sel;
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (sped->priv->sources_tree));
+ g_signal_connect (sel, "changed",
+ G_CALLBACK (data_source_selection_changed_cb), sped);
+
+ /* data sources tree */
+ GtkWidget *sw;
+ 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);
+ gtk_container_add (GTK_CONTAINER (sw), sped->priv->sources_tree);
+ gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_paned_add2 (GTK_PANED (hpaned), vbox);
+
+ label = gtk_label_new ("");
+ str = g_strdup_printf ("<b>%s</b>", _("Selected data source'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);
+
+ GtkWidget *pe;
+ pe = data_source_editor_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), pe, TRUE, TRUE, 0);
+ sped->priv->propsedit = DATA_SOURCE_EDITOR (pe);
+
+ /* warning, not shown */
+ sped->priv->info = NULL;
+
+ gtk_widget_show_all (hpaned);
}
GType
@@ -111,6 +254,77 @@ ui_spec_editor_dispose (GObject *object)
parent_class->dispose (object);
}
+static void
+mgr_changed_cb (DataSourceManager *mgr, UiSpecEditor *sped)
+{
+ const GSList *list;
+
+ /* keep selected source, if any */
+ GtkTreeIter iter;
+ GtkTreeSelection *sel;
+ DataSource *current_source = NULL;
+ GtkTreePath *current_path = NULL;
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (sped->priv->sources_tree));
+ if (gtk_tree_selection_get_selected (sel, NULL, &iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (sped->priv->sources_model),
+ &iter, COLUMN_DATA_SOURCE, ¤t_source, -1);
+ current_path = gtk_tree_model_get_path (GTK_TREE_MODEL (sped->priv->sources_model),
+ &iter);
+ }
+
+ /* reset sources list */
+ gtk_list_store_clear (sped->priv->sources_model);
+ for (list = data_source_manager_get_sources (mgr); list; list = list->next) {
+ DataSource *source = DATA_SOURCE (list->data);
+
+ gtk_list_store_append (sped->priv->sources_model, &iter);
+ gtk_list_store_set (sped->priv->sources_model, &iter,
+ COLUMN_DATA_SOURCE, source,
+ -1);
+ }
+
+ /* reset selected source */
+ data_source_editor_display_source (sped->priv->propsedit, current_source);
+ if (current_path) {
+ gtk_tree_selection_select_path (sel, current_path);
+ gtk_tree_path_free (current_path);
+ }
+}
+
+static void
+mgr_source_changed_cb (DataSourceManager *mgr, DataSource *source, UiSpecEditor *sped)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *tree_model = GTK_TREE_MODEL (sped->priv->sources_model);
+ DataSource *msource;
+
+ if (gtk_tree_model_get_iter_first (tree_model, &iter)) {
+ gtk_tree_model_get (tree_model, &iter, COLUMN_DATA_SOURCE, &msource, -1);
+ if (source == msource) {
+ GtkTreePath *path;
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_model_row_changed (tree_model, path, &iter);
+ gtk_tree_path_free (path);
+ return;
+ }
+
+ gint pos;
+ for (pos = 1; gtk_tree_model_iter_next (tree_model, &iter); pos++) {
+ gtk_tree_model_get (tree_model, &iter, COLUMN_DATA_SOURCE, &msource, -1);
+ if (source == msource) {
+ GtkTreePath *path;
+ path = gtk_tree_path_new_from_indices (pos, -1);
+ gtk_tree_model_row_changed (tree_model, path, &iter);
+ gtk_tree_path_free (path);
+ return;
+ }
+ }
+ }
+
+ g_assert_not_reached ();
+}
+
/**
* ui_spec_editor_new
@@ -121,19 +335,53 @@ GtkWidget *
ui_spec_editor_new (DataSourceManager *mgr)
{
UiSpecEditor *sped;
- GtkWidget *label;
g_return_val_if_fail (IS_DATA_SOURCE_MANAGER (mgr), NULL);
sped = g_object_new (UI_SPEC_EDITOR_TYPE, NULL);
sped->priv->mgr = g_object_ref (mgr);
-
- label = gtk_label_new ("TODO");
- gtk_box_pack_start (GTK_BOX (sped), label, TRUE, TRUE, 0);
- gtk_widget_show (label);
+ g_signal_connect (mgr, "list-changed",
+ G_CALLBACK (mgr_changed_cb), sped);
+ g_signal_connect (mgr, "source-changed",
+ G_CALLBACK (mgr_source_changed_cb), sped);
+ mgr_changed_cb (mgr, sped);
/* warning */
sped->priv->info = NULL;
return (GtkWidget*) sped;
}
+
+/**
+ * ui_spec_editor_select_source
+ * @editor: a #UiSpecEditor widget
+ * @source: a #DataSource
+ *
+ * Selects and displays @source's propserties
+ */
+void
+ui_spec_editor_select_source (UiSpecEditor *editor, DataSource *source)
+{
+ GtkTreeSelection *sel;
+ GtkTreeIter iter;
+ GtkTreeModel *tree_model = GTK_TREE_MODEL (editor->priv->sources_model);
+ DataSource *msource;
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (editor->priv->sources_tree));
+ if (gtk_tree_model_get_iter_first (tree_model, &iter)) {
+ gtk_tree_model_get (tree_model, &iter, COLUMN_DATA_SOURCE, &msource, -1);
+ if (source == msource) {
+ gtk_tree_selection_select_iter (sel, &iter);
+ return;
+ }
+
+ gint pos;
+ for (pos = 1; gtk_tree_model_iter_next (tree_model, &iter); pos++) {
+ gtk_tree_model_get (tree_model, &iter, COLUMN_DATA_SOURCE, &msource, -1);
+ if (source == msource) {
+ gtk_tree_selection_select_iter (sel, &iter);
+ return;
+ }
+ }
+ }
+}
diff --git a/tools/browser/data-manager/ui-spec-editor.h b/tools/browser/data-manager/ui-spec-editor.h
index 0c4bc37..4fd6bc1 100644
--- a/tools/browser/data-manager/ui-spec-editor.h
+++ b/tools/browser/data-manager/ui-spec-editor.h
@@ -49,8 +49,9 @@ struct _UiSpecEditorClass {
GtkVBoxClass parent_class;
};
-GType ui_spec_editor_get_type (void) G_GNUC_CONST;
-GtkWidget *ui_spec_editor_new (DataSourceManager *mgr);
+GType ui_spec_editor_get_type (void) G_GNUC_CONST;
+GtkWidget *ui_spec_editor_new (DataSourceManager *mgr);
+void ui_spec_editor_select_source (UiSpecEditor *editor, DataSource *source);
G_END_DECLS
diff --git a/tools/browser/data-manager/xml-spec-editor.c b/tools/browser/data-manager/xml-spec-editor.c
index 0dff0e0..47898a0 100644
--- a/tools/browser/data-manager/xml-spec-editor.c
+++ b/tools/browser/data-manager/xml-spec-editor.c
@@ -59,6 +59,9 @@ static void xml_spec_editor_init (XmlSpecEditor *sped, XmlSpecEditorClass
static void xml_spec_editor_dispose (GObject *object);
static void xml_spec_editor_grab_focus (GtkWidget *widget);
+static void source_list_changed_cb (DataSourceManager *mgr, XmlSpecEditor *sped);
+static void data_source_changed_cb (DataSourceManager *mgr, DataSource *source, XmlSpecEditor *sped);
+
static GObjectClass *parent_class = NULL;
/*
@@ -120,8 +123,14 @@ xml_spec_editor_dispose (GObject *object)
if (sped->priv) {
if (sped->priv->signal_editor_changed_id)
g_source_remove (sped->priv->signal_editor_changed_id);
- if (sped->priv->mgr)
+ if (sped->priv->mgr) {
+ g_signal_handlers_disconnect_by_func (sped->priv->mgr,
+ G_CALLBACK (source_list_changed_cb), sped);
+ g_signal_handlers_disconnect_by_func (sped->priv->mgr,
+ G_CALLBACK (data_source_changed_cb), sped);
+
g_object_unref (sped->priv->mgr);
+ }
g_free (sped->priv);
sped->priv = NULL;
@@ -132,8 +141,9 @@ xml_spec_editor_dispose (GObject *object)
static gboolean
signal_editor_changed (XmlSpecEditor *sped)
{
- /* modify the DataSourceManager */
- data_source_manager_remove_all (sped->priv->mgr);
+ GSList *newlist = NULL;
+ g_signal_handlers_block_by_func (sped->priv->mgr,
+ G_CALLBACK (source_list_changed_cb), sped);
/* create new DataSource objects */
GError *lerror = NULL;
@@ -173,11 +183,11 @@ signal_editor_changed (XmlSpecEditor *sped)
if (strcmp ((gchar*) node->name, "data")) {
g_set_error (&lerror, 0, 0,
_("Expecting <%s> root node"), "data");
+ xmlFreeDoc (doc);
goto out;
}
BrowserConnection *bcnc;
-
bcnc = data_source_manager_get_browser_cnc (sped->priv->mgr);
for (node = node->children; node; node = node->next) {
if (!strcmp ((gchar*) node->name, "table") ||
@@ -185,18 +195,26 @@ signal_editor_changed (XmlSpecEditor *sped)
DataSource *source;
source = data_source_new_from_xml_node (bcnc, node, &lerror);
if (!source) {
- data_source_manager_remove_all (sped->priv->mgr);
- TO_IMPLEMENT;
+ if (newlist) {
+ g_slist_foreach (newlist, (GFunc) g_object_unref, NULL);
+ g_slist_free (newlist);
+ newlist = NULL;
+ }
+ xmlFreeDoc (doc);
goto out;
}
-
- data_source_manager_add_source (sped->priv->mgr, source);
- g_object_unref (source);
+ else
+ newlist = g_slist_prepend (newlist, source);
}
}
xmlFreeDoc (doc);
out:
+ newlist = g_slist_reverse (newlist);
+ data_source_manager_replace_all (sped->priv->mgr, newlist);
+ if (newlist)
+ g_slist_free (newlist);
+
if (lerror) {
if (! sped->priv->info) {
#if GTK_CHECK_VERSION (2,18,0)
@@ -226,6 +244,10 @@ signal_editor_changed (XmlSpecEditor *sped)
/* remove timeout */
sped->priv->signal_editor_changed_id = 0;
+
+ g_signal_handlers_unblock_by_func (sped->priv->mgr,
+ G_CALLBACK (source_list_changed_cb), sped);
+
return FALSE;
}
@@ -237,6 +259,41 @@ editor_changed_cb (GtkTextBuffer *buffer, XmlSpecEditor *sped)
sped->priv->signal_editor_changed_id = g_timeout_add_seconds (1, (GSourceFunc) signal_editor_changed, sped);
}
+static void
+source_list_changed_cb (DataSourceManager *mgr, XmlSpecEditor *sped)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ doc = xmlNewDoc (BAD_CAST "1.0");
+ root = xmlNewNode (NULL, BAD_CAST "data");
+ xmlDocSetRootElement (doc, root);
+
+ const GSList *list;
+ for (list = data_source_manager_get_sources (sped->priv->mgr); list; list = list->next) {
+ xmlNodePtr node;
+ node = data_source_to_xml_node (DATA_SOURCE (list->data));
+ xmlAddChild (root, node);
+ }
+
+ xmlChar *mem;
+ int size;
+ xmlDocDumpFormatMemory (doc, &mem, &size, 1);
+ xmlFreeDoc (doc);
+
+ g_signal_handlers_block_by_func (sped->priv->buffer,
+ G_CALLBACK (editor_changed_cb), sped);
+ gtk_text_buffer_set_text (sped->priv->buffer, (gchar*) mem, -1);
+ g_signal_handlers_unblock_by_func (sped->priv->buffer,
+ G_CALLBACK (editor_changed_cb), sped);
+ xmlFree (mem);
+}
+
+static void
+data_source_changed_cb (DataSourceManager *mgr, DataSource *source, XmlSpecEditor *sped)
+{
+ source_list_changed_cb (mgr, sped);
+}
+
/**
* xml_spec_editor_new
*
@@ -253,6 +310,10 @@ xml_spec_editor_new (DataSourceManager *mgr)
sped = g_object_new (XML_SPEC_EDITOR_TYPE, NULL);
sped->priv->mgr = g_object_ref (mgr);
+ g_signal_connect (mgr, "list-changed",
+ G_CALLBACK (source_list_changed_cb), sped);
+ g_signal_connect (mgr, "source-changed",
+ G_CALLBACK (data_source_changed_cb), sped);
/* XML editor */
label = gtk_label_new ("");
diff --git a/tools/browser/doc/gda-browser-sections.txt b/tools/browser/doc/gda-browser-sections.txt
index 08817ad..3904917 100644
--- a/tools/browser/doc/gda-browser-sections.txt
+++ b/tools/browser/doc/gda-browser-sections.txt
@@ -10,6 +10,7 @@ browser_window_pop_status
browser_window_customize_perspective_ui
browser_window_change_perspective
browser_window_is_fullscreen
+browser_window_set_fullscreen
<SUBSECTION Standard>
BROWSER_WINDOW
BROWSER_IS_WINDOW
diff --git a/tools/browser/doc/tmpl/browser-window.sgml b/tools/browser/doc/tmpl/browser-window.sgml
index 0881a1f..d62f097 100644
--- a/tools/browser/doc/tmpl/browser-window.sgml
+++ b/tools/browser/doc/tmpl/browser-window.sgml
@@ -111,3 +111,12 @@ Top level browser window
@Returns:
+<!-- ##### FUNCTION browser_window_set_fullscreen ##### -->
+<para>
+
+</para>
+
+ bwin:
+ fullscreen:
+
+
diff --git a/tools/browser/support.c b/tools/browser/support.c
index 3cdc874..a4b70c5 100644
--- a/tools/browser/support.c
+++ b/tools/browser/support.c
@@ -313,6 +313,8 @@ browser_show_help (GtkWindow *parent, const gchar *topic)
g_error_free (error);
}
+ else
+ browser_show_notice (parent, "show-help", _("Help is being loaded, please wait..."));
g_free (uri);
}
@@ -568,6 +570,7 @@ browser_make_small_button (gboolean is_toggle, const gchar *label, const gchar *
if (label) {
GtkWidget *wid;
wid = gtk_label_new (label);
+ gtk_misc_set_alignment (GTK_MISC (wid), 0., -1);
if (hbox)
gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 5);
else
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]