[libgda] GdaBrowser: improved usage of cloud widget
- From: Vivien Malerba <vivien src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [libgda] GdaBrowser: improved usage of cloud widget
- Date: Sun, 23 Aug 2009 20:19:56 +0000 (UTC)
commit 93b70571e61e58be72aa3a4fe397cd0b9e8b80d1
Author: Vivien Malerba <malerba gnome-db org>
Date: Tue Aug 18 16:03:58 2009 +0200
GdaBrowser: improved usage of cloud widget
* created a new common/libcommon.la static library to store
common objects
* the objects cloud widget is now used to add tables in diagrams
configure.in | 1 +
tools/browser/Makefile.am | 20 +-
tools/browser/canvas/Makefile.am | 1 -
tools/browser/canvas/browser-canvas-db-relations.c | 171 +++---
tools/browser/common/Makefile.am | 30 +
tools/browser/common/marshal.list | 25 +
tools/browser/common/objects-cloud.c | 633 ++++++++++++++++++++
tools/browser/common/objects-cloud.h | 69 +++
tools/browser/{ => common}/popup-container.c | 16 +-
tools/browser/{ => common}/popup-container.h | 0
tools/browser/schema-browser/objects-index.c | 473 +--------------
tools/browser/schema-browser/relations-diagram.c | 2 +-
12 files changed, 899 insertions(+), 542 deletions(-)
---
diff --git a/configure.in b/configure.in
index 95cc9f4..c014879 100644
--- a/configure.in
+++ b/configure.in
@@ -1725,6 +1725,7 @@ control-center/Makefile
tools/Makefile
tools/gda-sql-4.0.1:tools/gda-sql.1.in
tools/browser/Makefile
+tools/browser/common/Makefile
tools/browser/schema-browser/Makefile
tools/browser/dummy-perspective/Makefile
tools/browser/canvas/Makefile
diff --git a/tools/browser/Makefile.am b/tools/browser/Makefile.am
index 71e26de..92b314c 100644
--- a/tools/browser/Makefile.am
+++ b/tools/browser/Makefile.am
@@ -1,7 +1,7 @@
bin_PROGRAMS=gda-browser-4.0
noinst_PROGRAMS = favorites-test
-SUBDIRS = schema-browser dummy-perspective
+SUBDIRS = common schema-browser dummy-perspective
if HAVE_GOOCANVAS
SUBDIRS+=canvas
noinst_PROGRAMS+=canvas-example
@@ -55,9 +55,7 @@ gda_browser_4_0_SOURCES=\
browser-connections-list.h \
main.c \
mgr-favorites.h \
- mgr-favorites.c \
- popup-container.h \
- popup-container.c
+ mgr-favorites.c
$(OBJECTS): marshal.c marshal.h
@@ -68,6 +66,10 @@ else
EXTRALDFLAGS=
endif
+if HAVE_GOOCANVAS
+CANVAS_LDADD=$(top_builddir)/tools/browser/canvas/libcanvas.la
+endif
+
.rc.o:
$(WINDRES) $^ -o $@
@@ -78,14 +80,12 @@ gda_browser_4_0_LDFLAGS = $(EXTRALDFLAGS)
gda_browser_4_0_LDADD=\
$(top_builddir)/tools/browser/schema-browser/libperspective.la \
$(top_builddir)/tools/browser/dummy-perspective/libperspective.la \
+ $(CANVAS_LDADD) \
+ $(top_builddir)/tools/browser/common/libcommon.la \
$(top_builddir)/libgda/libgda-4.0.la \
$(top_builddir)/libgda-ui/libgda-ui-4.0.la \
$(LIBGDA_LIBS) $(GTK_LIBS)
-if HAVE_GOOCANVAS
-gda_browser_4_0_LDADD+= \
- $(top_builddir)/tools/browser/canvas/libcanvas.la
-endif
favorites_test_SOURCES=\
browser-favorites.c \
@@ -115,8 +115,8 @@ canvas_example_CFLAGS = -DCANVAS_EXAMPLE
canvas_example_LDFLAGS = \
$(top_builddir)/libgda/libgda-4.0.la \
$(top_builddir)/libgda-ui/libgda-ui-4.0.la \
- canvas/libcanvas.la
-
+ $(top_builddir)/tools/browser/canvas/libcanvas.la \
+ $(top_builddir)/tools/browser/common/libcommon.la
# icons
iconsdir=$(datadir)/pixmaps
diff --git a/tools/browser/canvas/Makefile.am b/tools/browser/canvas/Makefile.am
index 94c5251..59a2b6f 100644
--- a/tools/browser/canvas/Makefile.am
+++ b/tools/browser/canvas/Makefile.am
@@ -32,7 +32,6 @@ libcanvas_la_SOURCES = \
browser-canvas-utility.c \
browser-canvas-utility.h
-
libcanvas_la_LDFLAGS = \
$(GOOCANVAS_LIBS) \
$(GRAPHVIZ_LIBS)
diff --git a/tools/browser/canvas/browser-canvas-db-relations.c b/tools/browser/canvas/browser-canvas-db-relations.c
index 7894854..947cd23 100644
--- a/tools/browser/canvas/browser-canvas-db-relations.c
+++ b/tools/browser/canvas/browser-canvas-db-relations.c
@@ -1,6 +1,6 @@
/* browser-canvas-db-relations.c
*
- * Copyright (C) 2002 - 2007 Vivien Malerba
+ * Copyright (C) 2002 - 2009 Vivien Malerba
* Copyright (C) 2002 Fernando Martins
*
* This program is free software; you can redistribute it and/or
@@ -27,6 +27,8 @@
#include "browser-canvas-table.h"
#include "browser-canvas-column.h"
#include "browser-canvas-fkey.h"
+#include "../common/objects-cloud.h"
+#include "../common/popup-container.h"
static void browser_canvas_db_relations_class_init (BrowserCanvasDbRelationsClass *class);
static void browser_canvas_db_relations_init (BrowserCanvasDbRelations *canvas);
@@ -62,6 +64,9 @@ struct _BrowserCanvasDbRelationsPrivate
GdaMetaStruct *mstruct;
GooCanvasItem *level_separator; /* all tables items will be above this item and FK lines below */
+
+ GtkWidget *popup_container;
+ ObjectsCloud *cloud;
};
GType
@@ -135,6 +140,8 @@ browser_canvas_db_relations_dispose (GObject *object)
g_hash_table_destroy (canvas->priv->hash_tables);
g_hash_table_destroy (canvas->priv->hash_fkeys);
+ gtk_widget_destroy (canvas->priv->popup_container);
+
g_free (canvas->priv);
canvas->priv = NULL;
}
@@ -161,6 +168,8 @@ browser_canvas_db_relations_set_property (GObject *object,
canvas->priv->mstruct = g_value_get_object (value);
if (canvas->priv->mstruct)
g_object_ref (canvas->priv->mstruct);
+ if (canvas->priv->cloud)
+ objects_cloud_set_meta_struct (canvas->priv->cloud, canvas->priv->mstruct);
break;
}
}
@@ -184,6 +193,70 @@ browser_canvas_db_relations_get_property (GObject *object,
}
}
+static void
+popup_position (PopupContainer *container, gint *out_x, gint *out_y)
+{
+ GtkWidget *canvas;
+ canvas = g_object_get_data (G_OBJECT (container), "__canvas");
+
+ gint x, y;
+ GtkRequisition req;
+
+ gtk_widget_size_request (canvas, &req);
+
+ gdk_window_get_origin (canvas->window, &x, &y);
+
+ x += canvas->allocation.x;
+ y += canvas->allocation.y;
+
+ if (x < 0)
+ x = 0;
+
+ if (y < 0)
+ y = 0;
+ *out_x = x;
+ *out_y = y;
+}
+
+static void
+cloud_object_selected_cb (ObjectsCloud *ocloud, ObjectsCloudObjType sel_type,
+ const gchar *sel_contents, BrowserCanvasDbRelations *dbrel)
+{
+ g_print ("-> %s\n", sel_contents);
+
+ GdaMetaTable *mtable;
+ GValue *table_schema;
+ GValue *table_name;
+ GdaQuarkList *ql;
+
+ ql = gda_quark_list_new_from_string (sel_contents);
+ g_value_set_string ((table_schema = gda_value_new (G_TYPE_STRING)),
+ gda_quark_list_find (ql, "OBJ_SCHEMA"));
+ g_value_set_string ((table_name = gda_value_new (G_TYPE_STRING)),
+ gda_quark_list_find (ql, "OBJ_NAME"));
+ gda_quark_list_free (ql);
+
+ g_print ("Add %s.%s\n",
+ g_value_get_string (table_schema), g_value_get_string (table_name));
+ mtable = (GdaMetaTable*) gda_meta_struct_complement (dbrel->priv->mstruct, GDA_META_DB_TABLE,
+ NULL, table_schema, table_name, NULL);
+ if (mtable) {
+ BrowserCanvasTable *ctable;
+ GooCanvasBounds bounds;
+ gdouble x, y;
+
+ x = BROWSER_CANVAS (dbrel)->xmouse;
+ y = BROWSER_CANVAS (dbrel)->ymouse;
+ //goo_canvas_convert_from_pixels (BROWSER_CANVAS (dbrel)->priv->goocanvas, &x, &y);
+ ctable = browser_canvas_db_relations_add_table (dbrel, NULL, table_schema, table_name);
+ goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (ctable), &bounds);
+ browser_canvas_item_translate (BROWSER_CANVAS_ITEM (ctable),
+ x - bounds.x1, y - bounds.y1);
+ }
+ else
+ g_print ("Unknown...\n");
+}
+
/**
* browser_canvas_db_relations_new
* @mstruct: a #GdaMetaStruct object, or %NULL
@@ -199,17 +272,36 @@ GtkWidget *
browser_canvas_db_relations_new (GdaMetaStruct *mstruct)
{
BrowserCanvas *canvas;
+ BrowserCanvasDbRelations *dbrels;
GooCanvasItem *item;
+ GtkWidget *vbox, *cloud, *find;
g_return_val_if_fail (!mstruct || GDA_IS_META_STRUCT (mstruct), NULL);
canvas = BROWSER_CANVAS (g_object_new (TYPE_BROWSER_CANVAS_DB_RELATIONS, "meta-struct", mstruct, NULL));
+ dbrels = BROWSER_CANVAS_DB_RELATIONS (canvas);
item = goo_canvas_group_new (goo_canvas_get_root_item (canvas->priv->goocanvas), NULL);
- BROWSER_CANVAS_DB_RELATIONS (canvas)->priv->level_separator = item;
+ dbrels->priv->level_separator = item;
- return GTK_WIDGET (canvas);
-}
+ dbrels->priv->popup_container = popup_container_new_with_func (popup_position);
+ g_object_set_data (G_OBJECT (dbrels->priv->popup_container), "__canvas", canvas);
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (dbrels->priv->popup_container), vbox);
+ cloud = objects_cloud_new (mstruct, OBJECTS_CLOUD_TYPE_TABLE);
+ dbrels->priv->cloud = OBJECTS_CLOUD (cloud);
+ gtk_widget_set_size_request (GTK_WIDGET (cloud), 200, 300);
+ g_signal_connect (cloud, "selected",
+ G_CALLBACK (cloud_object_selected_cb), dbrels);
+ gtk_box_pack_start (GTK_BOX (vbox), cloud, TRUE, TRUE, 0);
+
+ find = objects_cloud_create_filter (OBJECTS_CLOUD (cloud));
+ gtk_box_pack_start (GTK_BOX (vbox), find, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (vbox);
+
+ return GTK_WIDGET (canvas);
+}
static void
clean_canvas_items (BrowserCanvas *canvas)
@@ -391,8 +483,7 @@ static void popup_add_table_cb (GtkMenuItem *mitem, BrowserCanvasDbRelations *ca
static GtkWidget *
build_context_menu (BrowserCanvas *canvas)
{
- GtkWidget *menu, *mitem, *submenu, *submitem;
- GSList *dbolist, *list;
+ GtkWidget *menu, *submitem;
BrowserCanvasDbRelations *dbrel = BROWSER_CANVAS_DB_RELATIONS (canvas);
if (!dbrel->priv->mstruct)
@@ -402,44 +493,7 @@ build_context_menu (BrowserCanvas *canvas)
submitem = gtk_menu_item_new_with_label (_("Add table"));
gtk_widget_show (submitem);
gtk_menu_append (menu, submitem);
- submenu = NULL;
-
- /* build list of tables */
- dbolist = gda_meta_struct_get_all_db_objects (dbrel->priv->mstruct);
- for (list = dbolist; list; list = list->next) {
- GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (list->data);
- GdaMetaTable *mtable;
-
- if (dbo->obj_type != GDA_META_DB_TABLE)
- continue;
-
- mtable = GDA_META_TABLE (dbo);
- if (mtable && g_hash_table_lookup (dbrel->priv->hash_tables, mtable))
- continue; /* skip that table as it is already present in the canvas */
-
- if (!submenu) {
- submenu = gtk_menu_new ();
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (submitem), submenu);
- gtk_widget_show (submenu);
- }
-
- mitem = gtk_menu_item_new_with_label (dbo->obj_name);
- gtk_widget_show (mitem);
- gtk_menu_append (submenu, mitem);
-
- GValue *tcatalog, *tschema, *tname;
- g_value_set_string ((tcatalog = gda_value_new (G_TYPE_STRING)), dbo->obj_catalog);
- g_value_set_string ((tschema = gda_value_new (G_TYPE_STRING)), dbo->obj_schema);
- g_value_set_string ((tname = gda_value_new (G_TYPE_STRING)), dbo->obj_name);
- g_object_set_data_full (G_OBJECT (mitem), "tcat", tcatalog, (GDestroyNotify) gda_value_free);
- g_object_set_data_full (G_OBJECT (mitem), "tschema", tschema, (GDestroyNotify) gda_value_free);
- g_object_set_data_full (G_OBJECT (mitem), "tname", tname, (GDestroyNotify) gda_value_free);
- g_signal_connect (G_OBJECT (mitem), "activate", G_CALLBACK (popup_add_table_cb), canvas);
- }
- g_slist_free (dbolist);
-
- /* sub menu is incensitive if there are no more tables left to add */
- gtk_widget_set_sensitive (submitem, submenu ? TRUE : FALSE);
+ g_signal_connect (G_OBJECT (submitem), "activate", G_CALLBACK (popup_add_table_cb), canvas);
return menu;
}
@@ -447,34 +501,7 @@ build_context_menu (BrowserCanvas *canvas)
static void
popup_add_table_cb (GtkMenuItem *mitem, BrowserCanvasDbRelations *dbrel)
{
- GdaMetaTable *mtable;
- GValue *table_catalog;
- GValue *table_schema;
- GValue *table_name;
-
- table_catalog = g_object_get_data (G_OBJECT (mitem), "tcat");
- table_schema = g_object_get_data (G_OBJECT (mitem), "tschema");
- table_name = g_object_get_data (G_OBJECT (mitem), "tname");
-
- /*g_print ("Add %s.%s.%s\n", g_value_get_string (table_catalog),
- g_value_get_string (table_schema), g_value_get_string (table_name));*/
- mtable = (GdaMetaTable*) gda_meta_struct_complement (dbrel->priv->mstruct, GDA_META_DB_TABLE,
- table_catalog, table_schema, table_name, NULL);
- if (mtable) {
- BrowserCanvasTable *ctable;
- GooCanvasBounds bounds;
- gdouble x, y;
-
- x = BROWSER_CANVAS (dbrel)->xmouse;
- y = BROWSER_CANVAS (dbrel)->ymouse;
- //goo_canvas_convert_from_pixels (BROWSER_CANVAS (dbrel)->priv->goocanvas, &x, &y);
- ctable = browser_canvas_db_relations_add_table (dbrel, table_catalog, table_schema, table_name);
- goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (ctable), &bounds);
- browser_canvas_item_translate (BROWSER_CANVAS_ITEM (ctable),
- x - bounds.x1, y - bounds.y1);
- }
- else
- g_print ("Unknown...\n");
+ gtk_widget_show (dbrel->priv->popup_container);
}
/**
diff --git a/tools/browser/common/Makefile.am b/tools/browser/common/Makefile.am
new file mode 100644
index 0000000..3996a3b
--- /dev/null
+++ b/tools/browser/common/Makefile.am
@@ -0,0 +1,30 @@
+noinst_LTLIBRARIES = libcommon.la
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libgda \
+ $(LIBGDA_CFLAGS) \
+ $(GTK_CFLAGS)
+
+marshal.h: marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=_common_marshal > $@
+marshal.c: marshal.list $(GLIB_GENMARSHAL) marshal.h
+ $(GLIB_GENMARSHAL) $< --body --prefix=_common_marshal > $@
+
+libcommon_la_SOURCES = \
+ marshal.c \
+ marshal.h \
+ objects-cloud.c \
+ objects-cloud.h \
+ popup-container.c \
+ popup-container.h
+
+$(OBJECTS): marshal.c marshal.h
+
+EXTRA_DIST = \
+ marshal.list
+
+CLEANFILES = \
+ marshal.h \
+ marshal.c
diff --git a/tools/browser/common/marshal.list b/tools/browser/common/marshal.list
new file mode 100644
index 0000000..c4ac747
--- /dev/null
+++ b/tools/browser/common/marshal.list
@@ -0,0 +1,25 @@
+# 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:ENUM,STRING
+VOID:INT,ENUM,STRING
diff --git a/tools/browser/common/objects-cloud.c b/tools/browser/common/objects-cloud.c
new file mode 100644
index 0000000..04b4f24
--- /dev/null
+++ b/tools/browser/common/objects-cloud.c
@@ -0,0 +1,633 @@
+/*
+ * Copyright (C) 2009 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 "objects-cloud.h"
+#include <libgda-ui/gdaui-tree-store.h>
+#include "../dnd.h"
+#include "../support.h"
+#include "../cc-gray-bar.h"
+#include "marshal.h"
+#include <gdk/gdkkeysyms.h>
+#include "popup-container.h"
+
+struct _ObjectsCloudPrivate {
+ gboolean show_schemas;
+ ObjectsCloudObjType type;
+ GdaMetaStruct *mstruct;
+ GtkTextBuffer *tbuffer;
+ GtkWidget *tview;
+
+ gboolean hovering_over_link;
+};
+
+static void objects_cloud_class_init (ObjectsCloudClass *klass);
+static void objects_cloud_init (ObjectsCloud *cloud,
+ ObjectsCloudClass *klass);
+static void objects_cloud_dispose (GObject *object);
+
+enum {
+ SELECTED,
+ LAST_SIGNAL
+};
+
+static guint objects_cloud_signals[LAST_SIGNAL] = { 0 };
+static GObjectClass *parent_class = NULL;
+
+
+/*
+ * ObjectsCloud class implementation
+ */
+
+static void
+objects_cloud_class_init (ObjectsCloudClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ /* signals */
+ objects_cloud_signals [SELECTED] =
+ g_signal_new ("selected",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (ObjectsCloudClass, selected),
+ NULL, NULL,
+ _common_marshal_VOID__ENUM_STRING, G_TYPE_NONE,
+ 2, G_TYPE_UINT, G_TYPE_STRING);
+ klass->selected = NULL;
+
+ object_class->dispose = objects_cloud_dispose;
+}
+
+
+static void
+objects_cloud_init (ObjectsCloud *cloud, ObjectsCloudClass *klass)
+{
+ cloud->priv = g_new0 (ObjectsCloudPrivate, 1);
+ cloud->priv->show_schemas = FALSE;
+ cloud->priv->tbuffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_create_tag (cloud->priv->tbuffer, "section",
+ "weight", PANGO_WEIGHT_BOLD,
+ "foreground", "blue", NULL);
+ gtk_text_buffer_create_tag (cloud->priv->tbuffer, "size0",
+ "scale", PANGO_SCALE_MEDIUM, NULL);
+ gtk_text_buffer_create_tag (cloud->priv->tbuffer, "size1",
+ "scale", PANGO_SCALE_LARGE, NULL);
+ gtk_text_buffer_create_tag (cloud->priv->tbuffer, "size2",
+ "scale", PANGO_SCALE_LARGE, NULL);
+}
+
+static void
+objects_cloud_dispose (GObject *object)
+{
+ ObjectsCloud *cloud = (ObjectsCloud *) object;
+
+ /* free memory */
+ if (cloud->priv) {
+ if (cloud->priv->mstruct)
+ g_object_unref (cloud->priv->mstruct);
+ g_object_unref (cloud->priv->tbuffer);
+ g_free (cloud->priv);
+ cloud->priv = NULL;
+ }
+
+ parent_class->dispose (object);
+}
+
+GType
+objects_cloud_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (ObjectsCloudClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) objects_cloud_class_init,
+ NULL,
+ NULL,
+ sizeof (ObjectsCloud),
+ 0,
+ (GInstanceInitFunc) objects_cloud_init
+ };
+ type = g_type_register_static (GTK_TYPE_VBOX, "ObjectsCloud",
+ &info, 0);
+ }
+ return type;
+}
+
+typedef struct {
+ gchar *schema;
+ GtkTextMark *mark;
+} SchemaData;
+static void add_to_schema_data (ObjectsCloud *cloud, SchemaData *sd, GdaMetaDbObject *dbo);
+static void
+update_display (ObjectsCloud *cloud)
+{
+ gchar *str;
+ GSList *schemas = NULL; /* holds pointers to @SchemaData structures */
+ SchemaData *default_sd = NULL, *sd;
+
+ GtkTextBuffer *tbuffer;
+ GtkTextIter start, end;
+
+ /* clean all */
+ tbuffer = cloud->priv->tbuffer;
+ gtk_text_buffer_get_start_iter (tbuffer, &start);
+ gtk_text_buffer_get_end_iter (tbuffer, &end);
+ gtk_text_buffer_delete (tbuffer, &start, &end);
+
+ default_sd = g_new0 (SchemaData, 1);
+ default_sd->schema = NULL;
+ default_sd->mark = gtk_text_mark_new (NULL, TRUE);
+ gtk_text_buffer_get_end_iter (tbuffer, &end);
+
+ gtk_text_buffer_get_end_iter (tbuffer, &end);
+ if (cloud->priv->show_schemas) {
+ gtk_text_buffer_insert_pixbuf (tbuffer, &end,
+ browser_get_pixbuf_icon (BROWSER_ICON_TABLE));
+ gtk_text_buffer_insert (tbuffer, &end, " ", 1);
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, &end,
+ _("Tables:"), -1, "section", NULL);
+ gtk_text_buffer_insert (tbuffer, &end, "\n\n", 2);
+ }
+ gtk_text_buffer_add_mark (tbuffer, default_sd->mark, &end);
+
+
+ GdaMetaStruct *mstruct;
+ GSList *dbo_list, *list;
+ mstruct = cloud->priv->mstruct;
+ if (!mstruct) {
+ /* nothing to display */
+ return;
+ }
+ dbo_list = g_slist_reverse (gda_meta_struct_get_all_db_objects (mstruct));
+ for (list = dbo_list; list; list = list->next) {
+ GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (list->data);
+ GSList *list;
+ gboolean is_default;
+
+ if (dbo->obj_type != GDA_META_DB_TABLE)
+ continue;
+ g_assert (dbo->obj_schema);
+
+ is_default = strcmp (dbo->obj_short_name, dbo->obj_full_name) ? TRUE : FALSE;
+ sd = NULL;
+ if (cloud->priv->show_schemas) {
+ for (list = schemas; list; list = list->next) {
+ if (!strcmp (((SchemaData *) list->data)->schema, dbo->obj_schema)) {
+ sd = (SchemaData *) list->data;
+ break;
+ }
+ }
+ if (!sd) {
+ sd = g_new0 (SchemaData, 1);
+ sd->schema = g_strdup (dbo->obj_schema);
+ sd->mark = gtk_text_mark_new (NULL, TRUE);
+
+ gtk_text_buffer_get_end_iter (tbuffer, &end);
+ gtk_text_buffer_insert (tbuffer, &end, "\n\n", 2);
+ gtk_text_buffer_insert_pixbuf (tbuffer, &end,
+ browser_get_pixbuf_icon (BROWSER_ICON_TABLE));
+ gtk_text_buffer_insert (tbuffer, &end, " ", 1);
+ str = g_strdup_printf (_("Tables in schema '%s':"), sd->schema);
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, &end,
+ str, -1, "section", NULL);
+ g_free (str);
+ gtk_text_buffer_insert (tbuffer, &end, "\n\n", 2);
+
+ gtk_text_buffer_add_mark (tbuffer, sd->mark, &end);
+
+ schemas = g_slist_append (schemas, sd);
+ }
+
+ add_to_schema_data (cloud, sd, dbo);
+ }
+ if (is_default)
+ add_to_schema_data (cloud, default_sd, dbo);
+ }
+ g_slist_free (dbo_list);
+
+ if (default_sd)
+ schemas = g_slist_prepend (schemas, default_sd);
+
+ /* get rid of the SchemaData structures */
+ for (list = schemas; list; list = list->next) {
+ sd = (SchemaData*) list->data;
+
+ g_free (sd->schema);
+ g_object_unref (sd->mark);
+ g_free (sd);
+ }
+}
+
+static void
+add_to_schema_data (ObjectsCloud *cloud, SchemaData *sd, GdaMetaDbObject *dbo)
+{
+ GtkTextTag *tag;
+ GtkTextIter iter;
+ gdouble scale = 1.0;
+
+ if (dbo->obj_type == GDA_META_DB_TABLE) {
+ scale = 1.0 + g_slist_length (dbo->depend_list) / 5.;
+ }
+
+ gtk_text_buffer_get_iter_at_mark (cloud->priv->tbuffer, &iter, sd->mark);
+ tag = gtk_text_buffer_create_tag (cloud->priv->tbuffer, NULL,
+ "foreground", "#6161F2",
+ //"underline", PANGO_UNDERLINE_SINGLE,
+ "scale", scale,
+ NULL);
+ g_object_set_data_full (G_OBJECT (tag), "dbo_obj_schema", g_strdup (dbo->obj_schema), g_free);
+ g_object_set_data_full (G_OBJECT (tag), "dbo_obj_name", g_strdup (dbo->obj_name), g_free);
+ g_object_set_data_full (G_OBJECT (tag), "dbo_obj_short_name", g_strdup (dbo->obj_short_name), g_free);
+
+ gtk_text_buffer_insert_with_tags (cloud->priv->tbuffer, &iter, dbo->obj_name, -1,
+ tag, NULL);
+ gtk_text_buffer_insert (cloud->priv->tbuffer, &iter, " ", -1);
+}
+
+static gboolean key_press_event (GtkWidget *text_view, GdkEventKey *event, ObjectsCloud *cloud);
+static gboolean event_after (GtkWidget *text_view, GdkEvent *ev, ObjectsCloud *cloud);
+static gboolean motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ObjectsCloud *cloud);
+static gboolean visibility_notify_event (GtkWidget *text_view, GdkEventVisibility *event, ObjectsCloud *cloud);
+
+static void
+text_tag_table_foreach_cb (GtkTextTag *tag, const gchar *find)
+{
+ const gchar *name;
+
+ name = g_object_get_data (G_OBJECT (tag), "dbo_obj_name");
+
+ if (!name)
+ return;
+
+ if (!*find) {
+ g_object_set (tag, "foreground", "#6161F2", NULL);
+ }
+ else {
+ gchar *ptr;
+ gchar *lcname, *lcfind;
+ lcname = g_utf8_strdown (name, -1);
+ lcfind = g_utf8_strdown (find, -1);
+
+ ptr = strstr (lcname, lcfind);
+ if (!ptr) {
+ /* string not present in name */
+ g_object_set (tag, "foreground", "#DBDBDB", NULL);
+ }
+ else if ((ptr == lcname) ||
+ ((*name == '"') && (ptr == lcname+1))) {
+ /* string present as start of name */
+ g_object_set (tag, "foreground", "#6161F2", NULL);
+ }
+ else {
+ /* string present in name but not at the start */
+ g_object_set (tag, "foreground", "#A0A0A0", NULL);
+ }
+
+ g_free (lcname);
+ g_free (lcfind);
+ }
+}
+
+void
+objects_cloud_filter (ObjectsCloud *cloud, const gchar *filter)
+{
+ g_return_if_fail (IS_OBJECTS_CLOUD (cloud));
+
+ GtkTextTagTable *tags_table = gtk_text_buffer_get_tag_table (cloud->priv->tbuffer);
+
+ gtk_text_tag_table_foreach (tags_table, (GtkTextTagTableForeach) text_tag_table_foreach_cb,
+ (gpointer) filter);
+}
+
+/**
+ * objects_cloud_new
+ *
+ *
+ *
+ * Returns:
+ */
+GtkWidget *
+objects_cloud_new (GdaMetaStruct *mstruct, ObjectsCloudObjType type)
+{
+ ObjectsCloud *cloud;
+
+ g_return_val_if_fail (!mstruct || GDA_IS_META_STRUCT (mstruct), NULL);
+ cloud = OBJECTS_CLOUD (g_object_new (OBJECTS_CLOUD_TYPE, NULL));
+
+ if (mstruct)
+ cloud->priv->mstruct = g_object_ref (mstruct);
+ cloud->priv->type = type;
+
+ /* text contents */
+ GtkWidget *sw, *vbox;
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_box_pack_start (GTK_BOX (cloud), sw, TRUE, TRUE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), vbox);
+
+ cloud->priv->tview = gtk_text_view_new_with_buffer (cloud->priv->tbuffer);
+ gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (cloud->priv->tview), GTK_WRAP_WORD);
+ gtk_text_view_set_editable (GTK_TEXT_VIEW (cloud->priv->tview), FALSE);
+ gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (cloud->priv->tview), FALSE);
+ gtk_box_pack_start (GTK_BOX (vbox), cloud->priv->tview, TRUE, TRUE, 0);
+ gtk_widget_show_all (sw);
+
+ g_signal_connect (cloud->priv->tview, "key-press-event",
+ G_CALLBACK (key_press_event), cloud);
+ g_signal_connect (cloud->priv->tview, "event-after",
+ G_CALLBACK (event_after), cloud);
+ g_signal_connect (cloud->priv->tview, "motion-notify-event",
+ G_CALLBACK (motion_notify_event), cloud);
+ g_signal_connect (cloud->priv->tview, "visibility-notify-event",
+ G_CALLBACK (visibility_notify_event), cloud);
+
+ /* initial update */
+ update_display (cloud);
+
+ return (GtkWidget*) cloud;
+}
+
+/**
+ * objects_cloud_set_meta_struct
+ *
+ */
+void
+objects_cloud_set_meta_struct (ObjectsCloud *cloud, GdaMetaStruct *mstruct)
+{
+ g_return_if_fail (IS_OBJECTS_CLOUD (cloud));
+ g_return_if_fail (!mstruct || GDA_IS_META_STRUCT (mstruct));
+
+ if (cloud->priv->mstruct) {
+ g_object_unref (cloud->priv->mstruct);
+ cloud->priv->mstruct = NULL;
+ }
+ if (mstruct)
+ cloud->priv->mstruct = g_object_ref (mstruct);
+ update_display (cloud);
+}
+
+/**
+ * objects_cloud_show_schemas
+ */
+void
+objects_cloud_show_schemas (ObjectsCloud *cloud, gboolean show_schemas)
+{
+ g_return_if_fail (IS_OBJECTS_CLOUD (cloud));
+
+ cloud->priv->show_schemas = show_schemas;
+ update_display (cloud);
+}
+
+static void
+find_entry_changed_cb (GtkWidget *entry, ObjectsCloud *cloud)
+{
+ gchar *find = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+ objects_cloud_filter (cloud, find);
+ g_free (find);
+}
+
+/**
+ * objects_cloud_create_filter
+ */
+GtkWidget *
+objects_cloud_create_filter (ObjectsCloud *cloud)
+{
+ GtkWidget *hbox, *label, *wid;
+ g_return_val_if_fail (IS_OBJECTS_CLOUD (cloud), NULL);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+
+ label = gtk_label_new (_("Find:"));
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ wid = gtk_entry_new ();
+ g_signal_connect (wid, "changed",
+ G_CALLBACK (find_entry_changed_cb), cloud);
+ gtk_box_pack_start (GTK_BOX (hbox), wid, TRUE, TRUE, 0);
+ gtk_widget_show_all (hbox);
+ gtk_widget_hide (hbox);
+
+ return hbox;
+}
+
+static GdkCursor *hand_cursor = NULL;
+static GdkCursor *regular_cursor = NULL;
+
+/* Looks at all tags covering the position (x, y) in the text view,
+ * and if one of them is a link, change the cursor to the "hands" cursor
+ * typically used by web browsers.
+ */
+static void
+set_cursor_if_appropriate (GtkTextView *text_view, gint x, gint y, ObjectsCloud *cloud)
+{
+ GSList *tags = NULL, *tagp = NULL;
+ GtkTextIter iter;
+ gboolean hovering = FALSE;
+
+ gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
+
+ tags = gtk_text_iter_get_tags (&iter);
+ for (tagp = tags; tagp != NULL; tagp = tagp->next) {
+ GtkTextTag *tag = tagp->data;
+ gchar *table_name;
+
+ table_name = g_object_get_data (G_OBJECT (tag), "dbo_obj_name");
+ if (table_name) {
+ hovering = TRUE;
+ break;
+ }
+ }
+
+ if (hovering != cloud->priv->hovering_over_link) {
+ cloud->priv->hovering_over_link = hovering;
+
+ if (cloud->priv->hovering_over_link) {
+ if (! hand_cursor)
+ hand_cursor = gdk_cursor_new (GDK_HAND2);
+ gdk_window_set_cursor (gtk_text_view_get_window (text_view,
+ GTK_TEXT_WINDOW_TEXT),
+ hand_cursor);
+ }
+ else {
+ if (!regular_cursor)
+ regular_cursor = gdk_cursor_new (GDK_XTERM);
+ gdk_window_set_cursor (gtk_text_view_get_window (text_view,
+ GTK_TEXT_WINDOW_TEXT),
+ regular_cursor);
+ }
+ }
+
+ if (tags)
+ g_slist_free (tags);
+}
+
+/*
+ * Also update the cursor image if the window becomes visible
+ * (e.g. when a window covering it got iconified).
+ */
+static gboolean
+visibility_notify_event (GtkWidget *text_view, GdkEventVisibility *event, ObjectsCloud *cloud)
+{
+ gint wx, wy, bx, by;
+
+ gdk_window_get_pointer (text_view->window, &wx, &wy, NULL);
+
+ gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
+ GTK_TEXT_WINDOW_WIDGET,
+ wx, wy, &bx, &by);
+
+ set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), bx, by, cloud);
+
+ return FALSE;
+}
+
+/*
+ * Update the cursor image if the pointer moved.
+ */
+static gboolean
+motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ObjectsCloud *cloud)
+{
+ gint x, y;
+
+ gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
+ GTK_TEXT_WINDOW_WIDGET,
+ event->x, event->y, &x, &y);
+
+ set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y, cloud);
+
+ gdk_window_get_pointer (text_view->window, NULL, NULL, NULL);
+ return FALSE;
+}
+
+
+/* Looks at all tags covering the position of iter in the text view,
+ * and if one of them is a link, follow it by showing the page identified
+ * by the data attached to it.
+ */
+static void
+follow_if_link (GtkWidget *text_view, GtkTextIter *iter, ObjectsCloud *cloud)
+{
+ GSList *tags = NULL, *tagp = NULL;
+
+ tags = gtk_text_iter_get_tags (iter);
+ for (tagp = tags; tagp; tagp = tagp->next) {
+ GtkTextTag *tag = tagp->data;
+ const gchar *schema;
+
+ schema = g_object_get_data (G_OBJECT (tag), "dbo_obj_schema");
+ if (schema) {
+ const gchar *objects_name, *short_name;
+
+ objects_name = g_object_get_data (G_OBJECT (tag), "dbo_obj_name");
+ short_name = g_object_get_data (G_OBJECT (tag), "dbo_obj_short_name");
+
+ if (objects_name && short_name) {
+ gchar *str, *tmp1, *tmp2, *tmp3;
+ tmp1 = gda_rfc1738_encode (schema);
+ tmp2 = gda_rfc1738_encode (objects_name);
+ tmp3 = gda_rfc1738_encode (short_name);
+ str = g_strdup_printf ("OBJ_TYPE=table;OBJ_SCHEMA=%s;OBJ_NAME=%s;OBJ_SHORT_NAME=%s",
+ tmp1, tmp2, tmp3);
+ g_free (tmp1);
+ g_free (tmp2);
+ g_free (tmp3);
+ g_signal_emit (cloud, objects_cloud_signals [SELECTED], 0,
+ cloud->priv->type, str);
+ g_free (str);
+ }
+ }
+ }
+
+ if (tags)
+ g_slist_free (tags);
+}
+
+/*
+ * Links can also be activated by clicking.
+ */
+static gboolean
+event_after (GtkWidget *text_view, GdkEvent *ev, ObjectsCloud *cloud)
+{
+ GtkTextIter start, end, iter;
+ GtkTextBuffer *buffer;
+ GdkEventButton *event;
+ gint x, y;
+
+ if (ev->type != GDK_BUTTON_RELEASE)
+ return FALSE;
+
+ event = (GdkEventButton *)ev;
+
+ if (event->button != 1)
+ return FALSE;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+
+ /* we shouldn't follow a link if the user has selected something */
+ gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+ if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
+ return FALSE;
+
+ gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
+ GTK_TEXT_WINDOW_WIDGET,
+ event->x, event->y, &x, &y);
+
+ gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
+
+ follow_if_link (text_view, &iter, cloud);
+
+ return FALSE;
+}
+
+/*
+ * Links can be activated by pressing Enter.
+ */
+static gboolean
+key_press_event (GtkWidget *text_view, GdkEventKey *event, ObjectsCloud *cloud)
+{
+ GtkTextIter iter;
+ GtkTextBuffer *buffer;
+
+ switch (event->keyval) {
+ case GDK_Return:
+ case GDK_KP_Enter:
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter,
+ gtk_text_buffer_get_insert (buffer));
+ follow_if_link (text_view, &iter, cloud);
+ break;
+
+ default:
+ break;
+ }
+ return FALSE;
+}
diff --git a/tools/browser/common/objects-cloud.h b/tools/browser/common/objects-cloud.h
new file mode 100644
index 0000000..e92a853
--- /dev/null
+++ b/tools/browser/common/objects-cloud.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 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 __OBJECTS_CLOUD_H__
+#define __OBJECTS_CLOUD_H__
+
+#include <gtk/gtkvbox.h>
+#include "../browser-connection.h"
+
+G_BEGIN_DECLS
+
+#define OBJECTS_CLOUD_TYPE (objects_cloud_get_type())
+#define OBJECTS_CLOUD(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, OBJECTS_CLOUD_TYPE, ObjectsCloud))
+#define OBJECTS_CLOUD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, OBJECTS_CLOUD_TYPE, ObjectsCloudClass))
+#define IS_OBJECTS_CLOUD(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, OBJECTS_CLOUD_TYPE))
+#define IS_OBJECTS_CLOUD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OBJECTS_CLOUD_TYPE))
+
+typedef struct _ObjectsCloud ObjectsCloud;
+typedef struct _ObjectsCloudClass ObjectsCloudClass;
+typedef struct _ObjectsCloudPrivate ObjectsCloudPrivate;
+
+typedef enum {
+ OBJECTS_CLOUD_TYPE_TABLE,
+ OBJECTS_CLOUD_TYPE_VIEW,
+} ObjectsCloudObjType;
+
+struct _ObjectsCloud {
+ GtkVBox parent;
+ ObjectsCloudPrivate *priv;
+};
+
+struct _ObjectsCloudClass {
+ GtkVBoxClass parent_class;
+
+ /* signals */
+ void (*selected) (ObjectsCloud *sel, ObjectsCloudObjType sel_type,
+ const gchar *sel_contents);
+};
+
+GType objects_cloud_get_type (void) G_GNUC_CONST;
+
+GtkWidget *objects_cloud_new (GdaMetaStruct *mstruct, ObjectsCloudObjType type);
+void objects_cloud_set_meta_struct (ObjectsCloud *cloud, GdaMetaStruct *mstruct);
+void objects_cloud_show_schemas (ObjectsCloud *cloud, gboolean show_schemas);
+void objects_cloud_filter (ObjectsCloud *cloud, const gchar *filter);
+GtkWidget *objects_cloud_create_filter (ObjectsCloud *cloud);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/popup-container.c b/tools/browser/common/popup-container.c
similarity index 95%
rename from tools/browser/popup-container.c
rename to tools/browser/common/popup-container.c
index cda8573..e259f32 100644
--- a/tools/browser/popup-container.c
+++ b/tools/browser/common/popup-container.c
@@ -252,21 +252,21 @@ popup_container_get_type (void)
static void
popup_position (PopupContainer *container, gint *out_x, gint *out_y)
{
- GtkWidget *button;
- button = g_object_get_data (G_OBJECT (container), "__poswidget");
+ GtkWidget *poswidget;
+ poswidget = g_object_get_data (G_OBJECT (container), "__poswidget");
gint x, y;
gint bwidth, bheight;
GtkRequisition req;
- gtk_widget_size_request (button, &req);
+ gtk_widget_size_request (poswidget, &req);
- gdk_window_get_origin (button->window, &x, &y);
+ gdk_window_get_origin (poswidget->window, &x, &y);
- x += button->allocation.x;
- y += button->allocation.y;
- bwidth = button->allocation.width;
- bheight = button->allocation.height;
+ x += poswidget->allocation.x;
+ y += poswidget->allocation.y;
+ bwidth = poswidget->allocation.width;
+ bheight = poswidget->allocation.height;
x += bwidth - req.width;
y += bheight;
diff --git a/tools/browser/popup-container.h b/tools/browser/common/popup-container.h
similarity index 100%
rename from tools/browser/popup-container.h
rename to tools/browser/common/popup-container.h
diff --git a/tools/browser/schema-browser/objects-index.c b/tools/browser/schema-browser/objects-index.c
index 772f44c..9f8c58e 100644
--- a/tools/browser/schema-browser/objects-index.c
+++ b/tools/browser/schema-browser/objects-index.c
@@ -31,15 +31,13 @@
#include "../cc-gray-bar.h"
#include "marshal.h"
#include <gdk/gdkkeysyms.h>
-#include "../popup-container.h"
+#include "../common/popup-container.h"
+#include "../common/objects-cloud.h"
struct _ObjectsIndexPrivate {
BrowserConnection *bcnc;
- GtkTextBuffer *tbuffer;
- GtkWidget *tview;
+ ObjectsCloud *cloud;
GtkWidget *popup_container;
-
- gboolean hovering_over_link;
};
static void objects_index_class_init (ObjectsIndexClass *klass);
@@ -88,16 +86,6 @@ static void
objects_index_init (ObjectsIndex *index, ObjectsIndexClass *klass)
{
index->priv = g_new0 (ObjectsIndexPrivate, 1);
- index->priv->tbuffer = gtk_text_buffer_new (NULL);
- gtk_text_buffer_create_tag (index->priv->tbuffer, "section",
- "weight", PANGO_WEIGHT_BOLD,
- "foreground", "blue", NULL);
- gtk_text_buffer_create_tag (index->priv->tbuffer, "size0",
- "scale", PANGO_SCALE_MEDIUM, NULL);
- gtk_text_buffer_create_tag (index->priv->tbuffer, "size1",
- "scale", PANGO_SCALE_LARGE, NULL);
- gtk_text_buffer_create_tag (index->priv->tbuffer, "size2",
- "scale", PANGO_SCALE_LARGE, NULL);
}
static void
@@ -113,7 +101,6 @@ objects_index_dispose (GObject *object)
G_CALLBACK (meta_changed_cb), index);
g_object_unref (index->priv->bcnc);
}
- g_object_unref (index->priv->tbuffer);
g_free (index->priv);
index->priv = NULL;
}
@@ -144,209 +131,13 @@ objects_index_get_type (void)
return type;
}
-typedef struct {
- gchar *schema;
- GtkTextMark *mark;
-} SchemaData;
-static void add_to_schema_data (ObjectsIndex *index, SchemaData *sd, GdaMetaDbObject *dbo);
static void
-update_display (ObjectsIndex *index)
+cloud_object_selected_cb (ObjectsCloud *sel, ObjectsCloudObjType sel_type,
+ const gchar *sel_contents, ObjectsIndex *index)
{
- gchar *str;
- GSList *schemas = NULL; /* holds pointers to @SchemaData structures */
- SchemaData *default_sd = NULL, *sd;
-
- GtkTextBuffer *tbuffer;
- GtkTextIter start, end;
-
- /* clean all */
- tbuffer = index->priv->tbuffer;
- gtk_text_buffer_get_start_iter (tbuffer, &start);
- gtk_text_buffer_get_end_iter (tbuffer, &end);
- gtk_text_buffer_delete (tbuffer, &start, &end);
-
- default_sd = g_new0 (SchemaData, 1);
- default_sd->schema = NULL;
- default_sd->mark = gtk_text_mark_new (NULL, TRUE);
- gtk_text_buffer_get_end_iter (tbuffer, &end);
-
- gtk_text_buffer_get_end_iter (tbuffer, &end);
- gtk_text_buffer_insert_pixbuf (tbuffer, &end,
- browser_get_pixbuf_icon (BROWSER_ICON_TABLE));
- gtk_text_buffer_insert (tbuffer, &end, " ", 1);
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, &end,
- _("Default tables:"), -1, "section", NULL);
- gtk_text_buffer_insert (tbuffer, &end, "\n\n", 2);
-
- gtk_text_buffer_add_mark (tbuffer, default_sd->mark, &end);
-
-
- GdaMetaStruct *mstruct;
- GSList *dbo_list, *list;
- mstruct = browser_connection_get_meta_struct (index->priv->bcnc);
- if (!mstruct) {
- /* not yet ready */
- return;
- }
- dbo_list = g_slist_reverse (gda_meta_struct_get_all_db_objects (mstruct));
- for (list = dbo_list; list; list = list->next) {
- GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (list->data);
- GSList *list;
- gboolean is_default;
-
- if (dbo->obj_type != GDA_META_DB_TABLE)
- continue;
- g_assert (dbo->obj_schema);
-
- is_default = strcmp (dbo->obj_short_name, dbo->obj_full_name) ? TRUE : FALSE;
- sd = NULL;
- for (list = schemas; list; list = list->next) {
- if (!strcmp (((SchemaData *) list->data)->schema, dbo->obj_schema)) {
- sd = (SchemaData *) list->data;
- break;
- }
- }
- if (!sd) {
- sd = g_new0 (SchemaData, 1);
- sd->schema = g_strdup (dbo->obj_schema);
- sd->mark = gtk_text_mark_new (NULL, TRUE);
-
- gtk_text_buffer_get_end_iter (tbuffer, &end);
- gtk_text_buffer_insert (tbuffer, &end, "\n\n", 2);
- gtk_text_buffer_insert_pixbuf (tbuffer, &end,
- browser_get_pixbuf_icon (BROWSER_ICON_TABLE));
- gtk_text_buffer_insert (tbuffer, &end, " ", 1);
- str = g_strdup_printf (_("Tables in schema '%s':"), sd->schema);
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, &end,
- str, -1, "section", NULL);
- g_free (str);
- gtk_text_buffer_insert (tbuffer, &end, "\n\n", 2);
-
- gtk_text_buffer_add_mark (tbuffer, sd->mark, &end);
-
- schemas = g_slist_append (schemas, sd);
- }
-
- add_to_schema_data (index, sd, dbo);
- if (is_default)
- add_to_schema_data (index, default_sd, dbo);
- }
- g_slist_free (dbo_list);
-
- if (default_sd)
- schemas = g_slist_prepend (schemas, default_sd);
-
- /* get rid of the SchemaData structures */
- for (list = schemas; list; list = list->next) {
- sd = (SchemaData*) list->data;
-
- g_free (sd->schema);
- g_object_unref (sd->mark);
- g_free (sd);
- }
-}
-
-static gchar *
-double_underscores (const gchar *str)
-{
- gchar *out, *outptr;
- gint len;
- if (!str)
- return NULL;
-
- len = strlen (str);
- out = g_malloc (sizeof (gchar) * (len * 2 +1));
- for (outptr = out; *str; str++, outptr++) {
- if (*str == '_') {
- *outptr = '_';
- outptr++;
- }
- *outptr = *str;
- }
- *outptr = 0;
-
- return out;
-}
-
-static void
-add_to_schema_data (ObjectsIndex *index, SchemaData *sd, GdaMetaDbObject *dbo)
-{
- GtkTextTag *tag;
- GtkTextIter iter;
- gdouble scale = 1.0;
-
- if (dbo->obj_type == GDA_META_DB_TABLE) {
- scale = 1.0 + g_slist_length (dbo->depend_list) / 5.;
- }
-
- gtk_text_buffer_get_iter_at_mark (index->priv->tbuffer, &iter, sd->mark);
- tag = gtk_text_buffer_create_tag (index->priv->tbuffer, NULL,
- "foreground", "#6161F2",
- //"underline", PANGO_UNDERLINE_SINGLE,
- "scale", scale,
- NULL);
- g_object_set_data_full (G_OBJECT (tag), "dbo_obj_schema", g_strdup (dbo->obj_schema), g_free);
- g_object_set_data_full (G_OBJECT (tag), "dbo_obj_name", g_strdup (dbo->obj_name), g_free);
- g_object_set_data_full (G_OBJECT (tag), "dbo_obj_short_name", g_strdup (dbo->obj_short_name), g_free);
-
- gtk_text_buffer_insert_with_tags (index->priv->tbuffer, &iter, dbo->obj_name, -1,
- tag, NULL);
- gtk_text_buffer_insert (index->priv->tbuffer, &iter, " ", -1);
-}
-
-static gboolean key_press_event (GtkWidget *text_view, GdkEventKey *event, ObjectsIndex *index);
-static gboolean event_after (GtkWidget *text_view, GdkEvent *ev, ObjectsIndex *index);
-static gboolean motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ObjectsIndex *index);
-static gboolean visibility_notify_event (GtkWidget *text_view, GdkEventVisibility *event, ObjectsIndex *index);
-
-static void
-text_tag_table_foreach_cb (GtkTextTag *tag, const gchar *find)
-{
- const gchar *name;
-
- name = g_object_get_data (G_OBJECT (tag), "dbo_obj_name");
-
- if (!name)
- return;
-
- if (!*find) {
- g_object_set (tag, "foreground", "#6161F2", NULL);
- }
- else {
- gchar *ptr;
- gchar *lcname, *lcfind;
- lcname = g_utf8_strdown (name, -1);
- lcfind = g_utf8_strdown (find, -1);
-
- ptr = strstr (lcname, lcfind);
- if (!ptr) {
- /* string not present in name */
- g_object_set (tag, "foreground", "#DBDBDB", NULL);
- }
- else if ((ptr == lcname) ||
- ((*name == '"') && (ptr == lcname+1))) {
- /* string present as start of name */
- g_object_set (tag, "foreground", "#6161F2", NULL);
- }
- else {
- /* string present in name but not at the start */
- g_object_set (tag, "foreground", "#A0A0A0", NULL);
- }
-
- g_free (lcname);
- g_free (lcfind);
- }
-}
-
-static void
-find_entry_changed_cb (GtkWidget *entry, ObjectsIndex *index)
-{
- gchar *find = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
- GtkTextTagTable *tags_table = gtk_text_buffer_get_tag_table (index->priv->tbuffer);
-
- gtk_text_tag_table_foreach (tags_table, (GtkTextTagTableForeach) text_tag_table_foreach_cb,
- find);
- g_free (find);
+ /* FIXME: adjust with sel->priv->type */
+ g_signal_emit (index, objects_index_signals [SELECTION_CHANGED], 0,
+ BROWSER_FAVORITES_TABLES, sel_contents);
}
/**
@@ -382,6 +173,17 @@ objects_index_new (BrowserConnection *bcnc)
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
+ /* cloud */
+ GdaMetaStruct *mstruct;
+ GtkWidget *cloud;
+ mstruct = browser_connection_get_meta_struct (index->priv->bcnc);
+ cloud = objects_cloud_new (mstruct, OBJECTS_CLOUD_TYPE_TABLE);
+ gtk_box_pack_start (GTK_BOX (index), cloud, TRUE, TRUE, 0);
+ index->priv->cloud = cloud;
+ g_signal_connect (cloud, "selected",
+ G_CALLBACK (cloud_object_selected_cb), index);
+
+ /* find button */
wid = gtk_button_new ();
label = gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (wid), label);
@@ -395,45 +197,9 @@ objects_index_new (BrowserConnection *bcnc)
G_CALLBACK (gtk_widget_show), popup);
g_object_set_data (G_OBJECT (popup), "button", wid);
- hbox = gtk_hbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (popup), hbox);
-
- label = gtk_label_new (_("Find:"));
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- wid = gtk_entry_new ();
- g_signal_connect (wid, "changed",
- G_CALLBACK (find_entry_changed_cb), index);
- gtk_box_pack_start (GTK_BOX (hbox), wid, TRUE, TRUE, 0);
- gtk_widget_show_all (hbox);
-
- /* text contents */
- GtkWidget *sw, *vbox;
- sw = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
- gtk_box_pack_start (GTK_BOX (index), sw, TRUE, TRUE, 0);
-
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), vbox);
-
- index->priv->tview = gtk_text_view_new_with_buffer (index->priv->tbuffer);
- gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (index->priv->tview), GTK_WRAP_WORD);
- gtk_text_view_set_editable (GTK_TEXT_VIEW (index->priv->tview), FALSE);
- //gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (index->priv->tview), FALSE);
- gtk_box_pack_start (GTK_BOX (vbox), index->priv->tview, TRUE, TRUE, 0);
- gtk_widget_show_all (sw);
-
- g_signal_connect (index->priv->tview, "key-press-event",
- G_CALLBACK (key_press_event), index);
- g_signal_connect (index->priv->tview, "event-after",
- G_CALLBACK (event_after), index);
- g_signal_connect (index->priv->tview, "motion-notify-event",
- G_CALLBACK (motion_notify_event), index);
- g_signal_connect (index->priv->tview, "visibility-notify-event",
- G_CALLBACK (visibility_notify_event), index);
-
- /* initial update */
- update_display (index);
+ wid = objects_cloud_create_filter (cloud);
+ gtk_container_add (GTK_CONTAINER (popup), wid);
+ gtk_widget_show (wid);
return (GtkWidget*) index;
}
@@ -441,198 +207,5 @@ objects_index_new (BrowserConnection *bcnc)
static void
meta_changed_cb (BrowserConnection *bcnc, GdaMetaStruct *mstruct, ObjectsIndex *index)
{
- update_display (index);
-}
-
-static GdkCursor *hand_cursor = NULL;
-static GdkCursor *regular_cursor = NULL;
-
-/* Looks at all tags covering the position (x, y) in the text view,
- * and if one of them is a link, change the cursor to the "hands" cursor
- * typically used by web browsers.
- */
-static void
-set_cursor_if_appropriate (GtkTextView *text_view, gint x, gint y, ObjectsIndex *index)
-{
- GSList *tags = NULL, *tagp = NULL;
- GtkTextIter iter;
- gboolean hovering = FALSE;
-
- gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
-
- tags = gtk_text_iter_get_tags (&iter);
- for (tagp = tags; tagp != NULL; tagp = tagp->next) {
- GtkTextTag *tag = tagp->data;
- gchar *table_name;
-
- table_name = g_object_get_data (G_OBJECT (tag), "dbo_obj_name");
- if (table_name) {
- hovering = TRUE;
- break;
- }
- }
-
- if (hovering != index->priv->hovering_over_link) {
- index->priv->hovering_over_link = hovering;
-
- if (index->priv->hovering_over_link) {
- if (! hand_cursor)
- hand_cursor = gdk_cursor_new (GDK_HAND2);
- gdk_window_set_cursor (gtk_text_view_get_window (text_view,
- GTK_TEXT_WINDOW_TEXT),
- hand_cursor);
- }
- else {
- if (!regular_cursor)
- regular_cursor = gdk_cursor_new (GDK_XTERM);
- gdk_window_set_cursor (gtk_text_view_get_window (text_view,
- GTK_TEXT_WINDOW_TEXT),
- regular_cursor);
- }
- }
-
- if (tags)
- g_slist_free (tags);
-}
-
-/*
- * Also update the cursor image if the window becomes visible
- * (e.g. when a window covering it got iconified).
- */
-static gboolean
-visibility_notify_event (GtkWidget *text_view, GdkEventVisibility *event, ObjectsIndex *index)
-{
- gint wx, wy, bx, by;
-
- gdk_window_get_pointer (text_view->window, &wx, &wy, NULL);
-
- gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
- GTK_TEXT_WINDOW_WIDGET,
- wx, wy, &bx, &by);
-
- set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), bx, by, index);
-
- return FALSE;
-}
-
-/*
- * Update the cursor image if the pointer moved.
- */
-static gboolean
-motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ObjectsIndex *index)
-{
- gint x, y;
-
- gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
- GTK_TEXT_WINDOW_WIDGET,
- event->x, event->y, &x, &y);
-
- set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y, index);
-
- gdk_window_get_pointer (text_view->window, NULL, NULL, NULL);
- return FALSE;
-}
-
-
-/* Looks at all tags covering the position of iter in the text view,
- * and if one of them is a link, follow it by showing the page identified
- * by the data attached to it.
- */
-static void
-follow_if_link (GtkWidget *text_view, GtkTextIter *iter, ObjectsIndex *index)
-{
- GSList *tags = NULL, *tagp = NULL;
-
- tags = gtk_text_iter_get_tags (iter);
- for (tagp = tags; tagp; tagp = tagp->next) {
- GtkTextTag *tag = tagp->data;
- const gchar *schema;
-
- schema = g_object_get_data (G_OBJECT (tag), "dbo_obj_schema");
- if (schema) {
- const gchar *objects_name, *short_name;
-
- objects_name = g_object_get_data (G_OBJECT (tag), "dbo_obj_name");
- short_name = g_object_get_data (G_OBJECT (tag), "dbo_obj_short_name");
-
- if (objects_name && short_name) {
- gchar *str, *tmp1, *tmp2, *tmp3;
- tmp1 = gda_rfc1738_encode (schema);
- tmp2 = gda_rfc1738_encode (objects_name);
- tmp3 = gda_rfc1738_encode (short_name);
- str = g_strdup_printf ("OBJ_TYPE=table;OBJ_SCHEMA=%s;OBJ_NAME=%s;OBJ_SHORT_NAME=%s",
- tmp1, tmp2, tmp3);
- g_free (tmp1);
- g_free (tmp2);
- g_free (tmp3);
- g_signal_emit (index, objects_index_signals [SELECTION_CHANGED], 0,
- BROWSER_FAVORITES_TABLES, str);
- g_free (str);
- }
- }
- }
-
- if (tags)
- g_slist_free (tags);
-}
-
-/*
- * Links can also be activated by clicking.
- */
-static gboolean
-event_after (GtkWidget *text_view, GdkEvent *ev, ObjectsIndex *index)
-{
- GtkTextIter start, end, iter;
- GtkTextBuffer *buffer;
- GdkEventButton *event;
- gint x, y;
-
- if (ev->type != GDK_BUTTON_RELEASE)
- return FALSE;
-
- event = (GdkEventButton *)ev;
-
- if (event->button != 1)
- return FALSE;
-
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
-
- /* we shouldn't follow a link if the user has selected something */
- gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
- if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
- return FALSE;
-
- gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
- GTK_TEXT_WINDOW_WIDGET,
- event->x, event->y, &x, &y);
-
- gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
-
- follow_if_link (text_view, &iter, index);
-
- return FALSE;
-}
-
-/*
- * Links can be activated by pressing Enter.
- */
-static gboolean
-key_press_event (GtkWidget *text_view, GdkEventKey *event, ObjectsIndex *index)
-{
- GtkTextIter iter;
- GtkTextBuffer *buffer;
-
- switch (event->keyval) {
- case GDK_Return:
- case GDK_KP_Enter:
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
- gtk_text_buffer_get_iter_at_mark (buffer, &iter,
- gtk_text_buffer_get_insert (buffer));
- follow_if_link (text_view, &iter, index);
- break;
-
- default:
- break;
- }
- return FALSE;
+ objects_cloud_set_meta_struct (index->priv->cloud, mstruct);
}
diff --git a/tools/browser/schema-browser/relations-diagram.c b/tools/browser/schema-browser/relations-diagram.c
index 9e2facd..da2533c 100644
--- a/tools/browser/schema-browser/relations-diagram.c
+++ b/tools/browser/schema-browser/relations-diagram.c
@@ -28,7 +28,7 @@
#include "../cc-gray-bar.h"
#include "../canvas/browser-canvas-db-relations.h"
#include <gdk/gdkkeysyms.h>
-#include "../popup-container.h"
+#include "../common/popup-container.h"
struct _RelationsDiagramPrivate {
BrowserConnection *bcnc;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]