[libgda] GdaBrowser: reworked tables index
- From: Vivien Malerba <vivien src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [libgda] GdaBrowser: reworked tables index
- Date: Sun, 23 Aug 2009 20:19:36 +0000 (UTC)
commit d6451b7664656cd29a33a139751562f70827f683
Author: Vivien Malerba <malerba gnome-db org>
Date: Sun Aug 16 15:16:57 2009 +0200
GdaBrowser: reworked tables index
* "cloud" view
* search features
tools/browser/Makefile.am | 4 +-
tools/browser/popup-container.c | 260 ++++++++++++
tools/browser/popup-container.h | 56 +++
tools/browser/schema-browser/objects-index.c | 584 ++++++++++++++++++--------
4 files changed, 722 insertions(+), 182 deletions(-)
---
diff --git a/tools/browser/Makefile.am b/tools/browser/Makefile.am
index d4ea7eb..71e26de 100644
--- a/tools/browser/Makefile.am
+++ b/tools/browser/Makefile.am
@@ -55,7 +55,9 @@ gda_browser_4_0_SOURCES=\
browser-connections-list.h \
main.c \
mgr-favorites.h \
- mgr-favorites.c
+ mgr-favorites.c \
+ popup-container.h \
+ popup-container.c
$(OBJECTS): marshal.c marshal.h
diff --git a/tools/browser/popup-container.c b/tools/browser/popup-container.c
new file mode 100644
index 0000000..50025e8
--- /dev/null
+++ b/tools/browser/popup-container.c
@@ -0,0 +1,260 @@
+/*
+ * 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 <string.h>
+#include <gtk/gtk.h>
+#include "popup-container.h"
+#include <gdk/gdkkeysyms.h>
+
+struct _PopupContainerPrivate {
+ PopupContainerPositionFunc position_func;
+};
+
+static void popup_container_class_init (PopupContainerClass *klass);
+static void popup_container_init (PopupContainer *container,
+ PopupContainerClass *klass);
+static void popup_container_dispose (GObject *object);
+static void popup_container_show (GtkWidget *widget);
+
+static GObjectClass *parent_class = NULL;
+
+/*
+ * PopupContainer class implementation
+ */
+
+static void
+popup_container_class_init (PopupContainerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = popup_container_dispose;
+ widget_class->show = popup_container_show;
+}
+
+static gboolean
+delete_popup (GtkWidget *widget, PopupContainer *container)
+{
+ gtk_widget_hide (GTK_WIDGET (container));
+ gtk_grab_remove (GTK_WIDGET (container));
+ return TRUE;
+}
+
+static gboolean
+key_press_popup (GtkWidget *widget, GdkEventKey *event, PopupContainer *container)
+{
+ if (event->keyval != GDK_Escape)
+ return FALSE;
+
+ g_signal_stop_emission_by_name (widget, "key_press_event");
+ gtk_widget_hide (GTK_WIDGET (container));
+ gtk_grab_remove (GTK_WIDGET (container));
+ return TRUE;
+}
+
+static gboolean
+button_press_popup (GtkWidget *widget, GdkEventButton *event, PopupContainer *container)
+{
+ GtkWidget *child;
+
+ child = gtk_get_event_widget ((GdkEvent *) event);
+
+ /* We don't ask for button press events on the grab widget, so
+ * if an event is reported directly to the grab widget, it must
+ * be on a window outside the application (and thus we remove
+ * the popup window). Otherwise, we check if the widget is a child
+ * of the grab widget, and only remove the popup window if it
+ * is not.
+ */
+ if (child != widget) {
+ while (child) {
+ if (child == widget)
+ return FALSE;
+ child = child->parent;
+ }
+ }
+ gtk_widget_hide (GTK_WIDGET (container));
+ gtk_grab_remove (GTK_WIDGET (container));
+ return TRUE;
+}
+
+static void
+popup_container_init (PopupContainer *container, PopupContainerClass *klass)
+{
+ container->priv = g_new0 (PopupContainerPrivate, 1);
+ container->priv->position_func = NULL;
+
+ gtk_widget_set_events (GTK_WIDGET (container),
+ gtk_widget_get_events (GTK_WIDGET (container)) | GDK_KEY_PRESS_MASK);
+ gtk_window_set_resizable (GTK_WINDOW (container), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (container), 5);
+ g_signal_connect (G_OBJECT (container), "delete_event",
+ G_CALLBACK (delete_popup), container);
+ g_signal_connect (G_OBJECT (container), "key_press_event",
+ G_CALLBACK (key_press_popup), container);
+ g_signal_connect (G_OBJECT (container), "button_press_event",
+ G_CALLBACK (button_press_popup), container);
+
+}
+
+/* FIXME:
+ * - implement the show() virtual method with popup_grab_on_window()...
+ * - implement the position_popup()
+ */
+
+static void
+popup_container_dispose (GObject *object)
+{
+ PopupContainer *container = (PopupContainer *) object;
+
+ /* free memory */
+ if (container->priv) {
+ g_free (container->priv);
+ container->priv = NULL;
+ }
+
+ parent_class->dispose (object);
+}
+
+static void
+default_position_func (PopupContainer *container, gint *out_x, gint *out_y)
+{
+ gdk_display_get_pointer (gdk_display_get_default (), NULL,
+ out_x, out_y, NULL);
+}
+
+static gboolean
+popup_grab_on_window (GdkWindow *window, guint32 activate_time)
+{
+ if ((gdk_pointer_grab (window, TRUE,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK,
+ NULL, NULL, activate_time) == 0)) {
+ if (gdk_keyboard_grab (window, TRUE,
+ activate_time) == 0)
+ return TRUE;
+ else {
+ gdk_pointer_ungrab (activate_time);
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+popup_container_show (GtkWidget *widget)
+{
+ PopupContainer *container = (PopupContainer *) widget;
+ gint x, y;
+
+ GTK_WIDGET_CLASS (parent_class)->show (widget);
+ if (container->priv->position_func)
+ container->priv->position_func (container, &x, &y);
+ else
+ default_position_func (container, &x, &y);
+ gtk_window_move (GTK_WINDOW (widget), x + 1, y + 1);
+ gtk_window_move (GTK_WINDOW (widget), x, y);
+
+ gtk_grab_add (widget);
+
+ GdkScreen *screen;
+ gint swidth, sheight;
+ gint root_x, root_y;
+ gint wwidth, wheight;
+ gboolean do_move = FALSE;
+ screen = gtk_window_get_screen (GTK_WINDOW (widget));
+ if (screen) {
+ swidth = gdk_screen_get_width (screen);
+ sheight = gdk_screen_get_height (screen);
+ }
+ else {
+ swidth = gdk_screen_width ();
+ sheight = gdk_screen_height ();
+ }
+ gtk_window_get_position (GTK_WINDOW (widget), &root_x, &root_y);
+ gtk_window_get_size (GTK_WINDOW (widget), &wwidth, &wheight);
+ if (root_x + wwidth > swidth) {
+ do_move = TRUE;
+ root_x = swidth - wwidth;
+ }
+ else if (root_x < 0) {
+ do_move = TRUE;
+ root_x = 0;
+ }
+ if (root_y + wheight > sheight) {
+ do_move = TRUE;
+ root_y = sheight - wheight;
+ }
+ else if (root_y < 0) {
+ do_move = TRUE;
+ root_y = 0;
+ }
+ if (do_move)
+ gtk_window_move (GTK_WINDOW (widget), root_x, root_y);
+
+ popup_grab_on_window (widget->window,
+ gtk_get_current_event_time ());
+}
+
+GType
+popup_container_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (PopupContainerClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) popup_container_class_init,
+ NULL,
+ NULL,
+ sizeof (PopupContainer),
+ 0,
+ (GInstanceInitFunc) popup_container_init
+ };
+ type = g_type_register_static (GTK_TYPE_WINDOW, "PopupContainer",
+ &info, 0);
+ }
+ return type;
+}
+
+/**
+ * popup_container_new
+ *
+ *
+ *
+ * Returns:
+ */
+GtkWidget *
+popup_container_new (PopupContainerPositionFunc pos_func)
+{
+ PopupContainer *container;
+
+ container = POPUP_CONTAINER (g_object_new (POPUP_CONTAINER_TYPE, "type", GTK_WINDOW_POPUP,
+ NULL));
+
+ container->priv->position_func = pos_func;
+ return (GtkWidget*) container;
+}
diff --git a/tools/browser/popup-container.h b/tools/browser/popup-container.h
new file mode 100644
index 0000000..ba917fc
--- /dev/null
+++ b/tools/browser/popup-container.h
@@ -0,0 +1,56 @@
+/*
+ * 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 __POPUP_CONTAINER_H__
+#define __POPUP_CONTAINER_H__
+
+#include <gtk/gtkwindow.h>
+
+G_BEGIN_DECLS
+
+#define POPUP_CONTAINER_TYPE (popup_container_get_type())
+#define POPUP_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, POPUP_CONTAINER_TYPE, PopupContainer))
+#define POPUP_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, POPUP_CONTAINER_TYPE, PopupContainerClass))
+#define IS_POPUP_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, POPUP_CONTAINER_TYPE))
+#define IS_POPUP_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POPUP_CONTAINER_TYPE))
+
+typedef struct _PopupContainer PopupContainer;
+typedef struct _PopupContainerClass PopupContainerClass;
+typedef struct _PopupContainerPrivate PopupContainerPrivate;
+
+typedef void (*PopupContainerPositionFunc) (PopupContainer *cont, gint *out_x, gint *out_y);
+
+struct _PopupContainer {
+ GtkWindow parent;
+ PopupContainerPrivate *priv;
+};
+
+struct _PopupContainerClass {
+ GtkWindowClass parent_class;
+};
+
+GType popup_container_get_type (void) G_GNUC_CONST;
+GtkWidget *popup_container_new (PopupContainerPositionFunc pos_func);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/schema-browser/objects-index.c b/tools/browser/schema-browser/objects-index.c
index 0b9f342..05e6ca0 100644
--- a/tools/browser/schema-browser/objects-index.c
+++ b/tools/browser/schema-browser/objects-index.c
@@ -30,10 +30,16 @@
#include "../support.h"
#include "../cc-gray-bar.h"
#include "marshal.h"
+#include <gdk/gdkkeysyms.h>
+#include "../popup-container.h"
struct _ObjectsIndexPrivate {
BrowserConnection *bcnc;
- GtkWidget *main;
+ GtkTextBuffer *tbuffer;
+ GtkWidget *tview;
+ GtkWidget *popup_container;
+
+ gboolean hovering_over_link;
};
static void objects_index_class_init (ObjectsIndexClass *klass);
@@ -82,6 +88,16 @@ 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
@@ -91,11 +107,13 @@ objects_index_dispose (GObject *object)
/* free memory */
if (index->priv) {
+ gtk_widget_destroy (index->priv->popup_container);
if (index->priv->bcnc) {
g_signal_handlers_disconnect_by_func (index->priv->bcnc,
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;
}
@@ -128,25 +146,40 @@ objects_index_get_type (void)
typedef struct {
gchar *schema;
- GtkWidget *container;
- GtkWidget *objects;
- gint left;
- gint top;
- gint nrows;
+ GtkTextMark *mark;
} SchemaData;
static void add_to_schema_data (ObjectsIndex *index, SchemaData *sd, GdaMetaDbObject *dbo);
static void
update_display (ObjectsIndex *index)
{
-#define NCOLS 4
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);
- if (index->priv->main) {
- gtk_widget_destroy (index->priv->main);
- index->priv->main = NULL;
- }
GdaMetaStruct *mstruct;
GSList *dbo_list, *list;
@@ -155,7 +188,7 @@ update_display (ObjectsIndex *index)
/* not yet ready */
return;
}
- dbo_list = gda_meta_struct_get_all_db_objects (mstruct);
+ 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;
@@ -173,56 +206,24 @@ update_display (ObjectsIndex *index)
break;
}
}
- if (is_default && !default_sd) {
- GtkWidget *label;
-
- default_sd = g_new0 (SchemaData, 1);
- default_sd->schema = NULL;
- default_sd->objects = gtk_table_new (2, NCOLS, FALSE);
- default_sd->container = default_sd->objects;
-
- /*
- str = g_strdup_printf ("<b>%s:</b>", _("Tables"));
- label = gtk_label_new ("");
- gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
- gtk_label_set_markup (GTK_LABEL (label), str);
- g_free (str);
- gtk_table_attach (GTK_TABLE (default_sd->objects), label, 0, NCOLS, 0, 1,
- GTK_EXPAND | GTK_FILL, 0, 0, 0);
- gtk_table_set_row_spacing (GTK_TABLE (default_sd->objects), 0, 5);
- */
-
- default_sd->left = 0;
- default_sd->top = 1;
- default_sd->nrows = 1;
- }
if (!sd) {
- GtkWidget *hbox, *label, *icon;
-
sd = g_new0 (SchemaData, 1);
sd->schema = g_strdup (dbo->obj_schema);
- sd->left = 0;
- sd->top = 0;
- sd->nrows = 1;
-
- sd->objects = gtk_table_new (2, NCOLS, FALSE);
+ sd->mark = gtk_text_mark_new (NULL, TRUE);
- str = g_strdup_printf (_("Tables in schema <b>'%s'</b>"), sd->schema);
- label = gtk_label_new ("");
- gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
- gtk_label_set_markup (GTK_LABEL (label), str);
+ 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);
- icon = gtk_image_new_from_pixbuf (browser_get_pixbuf_icon (BROWSER_ICON_SCHEMA));
- hbox = gtk_hbox_new (FALSE, 0);
- gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 5);
- gtk_widget_show_all (hbox);
-
- sd->container = gtk_expander_new ("");
- gtk_expander_set_label_widget (GTK_EXPANDER (sd->container), hbox);
+ gtk_text_buffer_add_mark (tbuffer, sd->mark, &end);
- gtk_container_add (GTK_CONTAINER (sd->container), sd->objects);
schemas = g_slist_append (schemas, sd);
}
@@ -235,30 +236,14 @@ update_display (ObjectsIndex *index)
if (default_sd)
schemas = g_slist_prepend (schemas, default_sd);
- GtkWidget *sw, *vbox;
- sw = gtk_scrolled_window_new (NULL, NULL);
- index->priv->main = sw;
- 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);
+ /* get rid of the SchemaData structures */
for (list = schemas; list; list = list->next) {
sd = (SchemaData*) list->data;
- if (sd->nrows == 1) {
- /* add some padding */
- gint i;
- for (i = sd->left; i < NCOLS; i++)
- add_to_schema_data (index, sd, NULL);
- }
-
- gtk_box_pack_start (GTK_BOX (vbox), sd->container, FALSE, FALSE, 5);
g_free (sd->schema);
+ g_object_unref (sd->mark);
g_free (sd);
}
- gtk_widget_show_all (sw);
}
static gchar *
@@ -283,131 +268,120 @@ double_underscores (const gchar *str)
return out;
}
-static void objects_button_clicked_cb (GtkWidget *button, ObjectsIndex *index);
-static void source_drag_data_get_cb (GtkWidget *widget, GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info, guint time, ObjectsIndex *index);
-
static void
add_to_schema_data (ObjectsIndex *index, SchemaData *sd, GdaMetaDbObject *dbo)
{
- GtkWidget *wid, *icon;
-
- wid = gtk_button_new ();
- gtk_button_set_relief (GTK_BUTTON (wid), GTK_RELIEF_NONE);
- gtk_button_set_focus_on_click (GTK_BUTTON (wid), FALSE);
- if (dbo) {
- icon = gtk_image_new_from_pixbuf (browser_get_pixbuf_icon (BROWSER_ICON_TABLE));
- gtk_button_set_alignment (GTK_BUTTON (wid), 0., -1);
- gtk_button_set_image (GTK_BUTTON (wid), icon);
-
- gchar *str;
- str = double_underscores (dbo->obj_name);
- gtk_button_set_label (GTK_BUTTON (wid), str);
- g_free (str);
-
- g_object_set_data_full (G_OBJECT (wid), "dbo_obj_schema", g_strdup (dbo->obj_schema), g_free);
- g_object_set_data_full (G_OBJECT (wid), "dbo_obj_name", g_strdup (dbo->obj_name), g_free);
- g_object_set_data_full (G_OBJECT (wid), "dbo_obj_short_name", g_strdup (dbo->obj_short_name), g_free);
- g_signal_connect (wid, "clicked",
- G_CALLBACK (objects_button_clicked_cb), index);
-
- /* setup DnD */
- gtk_drag_source_set (wid, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
- dbo_table, G_N_ELEMENTS (dbo_table), GDK_ACTION_COPY);
- gtk_drag_source_set_icon_pixbuf (wid, browser_get_pixbuf_icon (BROWSER_ICON_TABLE));
- g_signal_connect (wid, "drag-data-get",
- G_CALLBACK (source_drag_data_get_cb), index);
- }
- else {
- gtk_button_set_label (GTK_BUTTON (wid), " ");
- gtk_widget_set_sensitive (wid, FALSE);
- }
+ GtkTextTag *tag;
+ GtkTextIter iter;
+ gdouble scale = 1.0;
- gtk_button_set_use_underline (GTK_BUTTON (wid), FALSE);
- if (! sd->schema && dbo) {
- gchar *str;
- str = g_strdup_printf (_("Objects in the '%s' schema"), dbo->obj_schema);
- gtk_widget_set_tooltip_text (wid, str);
- g_free (str);
- }
- gtk_table_attach (GTK_TABLE (sd->objects), wid, sd->left, sd->left + 1, sd->top, sd->top +1,
- GTK_EXPAND | GTK_FILL, 0, 5, 0);
- sd->left ++;
- if (sd->left >= NCOLS) {
- sd->left = 0;
- sd->top ++;
- sd->nrows ++;
+ 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 void popup_position (PopupContainer *container, gint *out_x, gint *out_y);
+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
-objects_button_clicked_cb (GtkWidget *button, ObjectsIndex *index)
+popup_position (PopupContainer *container, gint *out_x, gint *out_y)
{
- const gchar *schema;
- const gchar *objects_name, *short_name;
- gchar *str, *tmp1, *tmp2, *tmp3;
+ GtkWidget *button;
+ button = g_object_get_data (G_OBJECT (container), "button");
- schema = g_object_get_data (G_OBJECT (button), "dbo_obj_schema");
- objects_name = g_object_get_data (G_OBJECT (button), "dbo_obj_name");
- short_name = g_object_get_data (G_OBJECT (button), "dbo_obj_short_name");
-
- 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);
+ gint x, y;
+ gint bwidth, bheight;
+ GtkRequisition req;
+
+ gtk_widget_size_request (button, &req);
+
+ gdk_window_get_origin (button->window, &x, &y);
+
+ x += button->allocation.x;
+ y += button->allocation.y;
+ bwidth = button->allocation.width;
+ bheight = button->allocation.height;
+
+ x += bwidth - req.width;
+ y += bheight;
+
+ if (x < 0)
+ x = 0;
+
+ if (y < 0)
+ y = 0;
+
+ *out_x = x;
+ *out_y = y;
}
static void
-source_drag_data_get_cb (GtkWidget *widget, GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info, guint time, ObjectsIndex *index)
+text_tag_table_foreach_cb (GtkTextTag *tag, const gchar *find)
{
- const gchar *schema;
- const gchar *objects_name;
- const gchar *objects_short_name;
-
- schema = g_object_get_data (G_OBJECT (widget), "dbo_obj_schema");
- objects_name = g_object_get_data (G_OBJECT (widget), "dbo_obj_name");
- objects_short_name = g_object_get_data (G_OBJECT (widget), "dbo_obj_short_name");
-
- switch (info) {
- case TARGET_KEY_VALUE: {
- GString *string;
- gchar *tmp;
- string = g_string_new ("OBJ_TYPE=table");
- tmp = gda_rfc1738_encode (schema);
- g_string_append_printf (string, ";OBJ_SCHEMA=%s", tmp);
- g_free (tmp);
- tmp = gda_rfc1738_encode (objects_name);
- g_string_append_printf (string, ";OBJ_NAME=%s", tmp);
- g_free (tmp);
- tmp = gda_rfc1738_encode (objects_short_name);
- g_string_append_printf (string, ";OBJ_SHORT_NAME=%s", tmp);
- g_free (tmp);
- gtk_selection_data_set (selection_data, selection_data->target, 8, string->str, strlen (string->str));
- g_string_free (string, TRUE);
- break;
- }
- default:
- case TARGET_PLAIN: {
- gchar *str;
- str = g_strdup_printf ("%s.%s", schema, objects_name);
- gtk_selection_data_set_text (selection_data, str, -1);
- g_free (str);
- break;
+ 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);
}
- case TARGET_ROOTWIN:
- TO_IMPLEMENT; /* dropping on the Root Window => create a file */
- break;
+ 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);
+}
+
/**
* objects_index_new
*
@@ -428,15 +402,70 @@ objects_index_new (BrowserConnection *bcnc)
G_CALLBACK (meta_changed_cb), index);
/* header */
+ GtkWidget *hbox, *wid;
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (index), hbox, FALSE, FALSE, 0);
+
GtkWidget *label;
gchar *str;
str = g_strdup_printf ("<b>%s</b>", _("Tables' index"));
label = cc_gray_bar_new (str);
g_free (str);
- gtk_box_pack_start (GTK_BOX (index), label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
+ wid = gtk_button_new ();
+ label = gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_BUTTON);
+ gtk_container_add (GTK_CONTAINER (wid), label);
+ gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 0);
+ g_object_set (G_OBJECT (wid), "label", NULL, NULL);
+
+ GtkWidget *popup;
+ popup = popup_container_new (popup_position);
+ index->priv->popup_container = popup;
+ g_signal_connect_swapped (wid, "clicked",
+ 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);
return (GtkWidget*) index;
@@ -447,3 +476,196 @@ meta_changed_cb (BrowserConnection *bcnc, GdaMetaStruct *mstruct, ObjectsIndex *
{
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;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]