[libgda] Improved again the UI when dealing with binary data



commit 2127bbad14c7036f809a48deea554cca554b3e4b
Author: Vivien Malerba <malerba gnome-db org>
Date:   Sat Sep 12 10:14:25 2009 +0200

    Improved again the UI when dealing with binary data
    
    now display the data's size and type (if GIO is available)

 libgda-ui/data-entries/common-bin.c                |  185 +++++++++---
 libgda-ui/data-entries/common-bin.h                |   13 +-
 .../data-entries/gdaui-data-cell-renderer-bin.c    |   48 +++-
 libgda-ui/data-entries/gdaui-entry-bin.c           |   47 ++-
 libgda-ui/internal/Makefile.am                     |    2 +
 libgda-ui/internal/popup-container.c               |  313 +++++++++++++++++++
 libgda-ui/internal/popup-container.h               |   57 ++++
 tools/browser/common/popup-container.c             |  319 +-------------------
 tools/browser/common/popup-container.h             |   58 +----
 9 files changed, 603 insertions(+), 439 deletions(-)
---
diff --git a/libgda-ui/data-entries/common-bin.c b/libgda-ui/data-entries/common-bin.c
index 8be009a..69a3004 100644
--- a/libgda-ui/data-entries/common-bin.c
+++ b/libgda-ui/data-entries/common-bin.c
@@ -19,6 +19,7 @@
 
 #include <libgda/gda-value.h>
 #include "common-bin.h"
+#include "../internal/popup-container.h"
 #include <string.h>
 #include <gtk/gtk.h>
 #include <glib/gi18n-lib.h>
@@ -33,6 +34,7 @@ file_load_cb (GtkWidget *button, BinMenu *menu)
 {
 	GtkWidget *dlg;
 
+	gtk_widget_hide (menu->popup);
         dlg = gtk_file_chooser_dialog_new (_("Select file to load"),
                                            GTK_WINDOW (gtk_widget_get_toplevel (button)),
                                            GTK_FILE_CHOOSER_ACTION_OPEN,
@@ -62,23 +64,6 @@ file_load_cb (GtkWidget *button, BinMenu *menu)
 				gda_value_take_binary (nvalue, bin);
 
 				menu->loaded_value_cb (menu->loaded_value_cb_data, nvalue);
-
-#ifdef HAVE_GIO
-				/* Open with... using GIO */
-				gchar *tmp;
-				tmp = g_content_type_guess (NULL, bin->data, (gsize) bin->binary_length, NULL);
-				g_print ("Content type: %s\n", tmp);
-
-				GList *list;
-				list = g_app_info_get_all_for_type (tmp);
-				for (; list; list = list->next) {
-					GAppInfo *ai;
-					ai = (GAppInfo*) list->data;
-					g_print ("\t open with %s (%s)\n", g_app_info_get_name (ai),
-						 g_app_info_get_executable (ai));
-				}
-				g_free (tmp);
-#endif
 			}
 			else {
 				GtkWidget *msg;
@@ -113,6 +98,7 @@ file_save_cb (GtkWidget *button, BinMenu *menu)
 {
 	GtkWidget *dlg;
 
+	gtk_widget_hide (menu->popup);
         dlg = gtk_file_chooser_dialog_new (_("Select a file to save data to"),
                                            GTK_WINDOW (gtk_widget_get_toplevel (button)),
                                            GTK_FILE_CHOOSER_ACTION_SAVE,
@@ -175,34 +161,70 @@ file_save_cb (GtkWidget *button, BinMenu *menu)
 }
 
 void
-common_bin_create_menu (BinMenu *binmenu, GtkWidget *attach_to, GType entry_type,
+common_bin_create_menu (BinMenu *binmenu, PopupContainerPositionFunc pos_func, GType entry_type,
 			BinCallback loaded_value_cb, gpointer loaded_value_cb_data)
 {
-	GtkWidget *menu, *mitem;
+	GtkWidget *popup, *vbox, *hbox, *bbox, *button, *label;
+	gchar *str;
 
 	binmenu->entry_type = entry_type;
 	binmenu->loaded_value_cb = loaded_value_cb;
 	binmenu->loaded_value_cb_data = loaded_value_cb_data;
 	
-	menu = gtk_menu_new ();
-	g_signal_connect (menu, "deactivate", 
-			  G_CALLBACK (gtk_widget_hide), NULL);
-	binmenu->menu = menu;
+	popup = popup_container_new_with_func (pos_func);
+	binmenu->popup = popup;
 	
-	mitem = gtk_menu_item_new_with_mnemonic (_("_Load from file"));
-	gtk_container_add (GTK_CONTAINER (menu), mitem);
-	g_signal_connect (mitem, "activate",
+	vbox = gtk_vbox_new (FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (popup), vbox);
+
+	label = gtk_label_new ("");
+	str = g_strdup_printf ("<b>%s:</b>", _("Properties"));
+	gtk_label_set_markup (GTK_LABEL (label), str);
+	g_free (str);
+	gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+	gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+	hbox = gtk_hbox_new (FALSE, 0); /* HIG */
+        gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5);
+        gtk_widget_show (hbox);
+        label = gtk_label_new ("    ");
+        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+        gtk_widget_show (label);
+
+	label = gtk_label_new ("");
+	gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+	binmenu->props_label = label;
+
+	bbox = gtk_hbutton_box_new ();
+	gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+
+	button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
+	gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+	g_signal_connect (button, "clicked",
 			  G_CALLBACK (file_load_cb), binmenu);
-	binmenu->load_mitem = mitem;
+	binmenu->load_button = button;
 	
-	mitem = gtk_menu_item_new_with_mnemonic (_("_Save to file"));
-	gtk_container_add (GTK_CONTAINER (menu), mitem);
-	g_signal_connect (mitem, "activate",
+	button = gtk_button_new_from_stock (GTK_STOCK_SAVE_AS);
+	gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+	g_signal_connect (button, "clicked",
 			  G_CALLBACK (file_save_cb), binmenu);
-	binmenu->save_mitem = mitem;
-	
-	gtk_menu_attach_to_widget (GTK_MENU (menu), attach_to, NULL);
-	gtk_widget_show_all (menu);
+	binmenu->save_button = button;
+
+	gtk_widget_show_all (vbox);
+}
+
+static gchar *
+format_size (gulong size)
+{
+	if (size < 1024)
+		return g_strdup_printf (ngettext ("%lu Byte", "%lu Bytes", size), size);
+	else if (size < 1048576)
+		return g_strdup_printf ("%.1f Kio", (gfloat) (size / 1024));
+	else if (size < 1073741824)
+		return g_strdup_printf ("%.1f Mio", (gfloat) (size / 1048576));
+	else
+		return g_strdup_printf ("%.1f Gio", (gfloat) (size / 1073741824));
 }
 
 /* 
@@ -211,17 +233,100 @@ common_bin_create_menu (BinMenu *binmenu, GtkWidget *attach_to, GType entry_type
 void
 common_bin_adjust_menu (BinMenu *binmenu, gboolean editable, const GValue *value)
 {
-	if (!binmenu || !binmenu->menu)
+	gchar *size;
+	GString *string;
+#ifdef HAVE_GIO
+	gchar *ctype = NULL;
+#endif
+
+	if (!binmenu || !binmenu->popup)
 		return;
 
 	if (binmenu->tmpvalue) {
 		gda_value_free (binmenu->tmpvalue);
 		binmenu->tmpvalue = NULL;
 	}
-	if (value)
+	string = g_string_new ("");
+	if (value) {
 		binmenu->tmpvalue = gda_value_copy (value);
-	gtk_widget_set_sensitive (binmenu->load_mitem, editable);
-	gtk_widget_set_sensitive (binmenu->save_mitem, (value && !gda_value_is_null (value)) ? TRUE : FALSE);
+		if (G_VALUE_TYPE (value) == GDA_TYPE_NULL)
+			g_string_append_printf (string, "<i>%s</i>", _("No data"));
+		else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
+			const GdaBinary *bin;
+			bin = gda_value_get_binary (value);
+			size = format_size (bin->binary_length);
+			g_string_append_printf (string, "%s: %s", _("Data size"), size);
+			g_free (size);
+#ifdef HAVE_GIO
+			ctype = g_content_type_guess (NULL, bin->data, (gsize) bin->binary_length, NULL);
+#endif
+		}
+		else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
+			const GdaBlob *blob;
+			GdaBinary *bin;
+			blob = gda_value_get_blob (value);
+			bin = (GdaBinary *) blob;
+			if (blob->op) {
+				glong len;
+				len = gda_blob_op_get_length (blob->op);
+				if (len >= 0) {
+					size = format_size (len);
+					g_string_append_printf (string, "%s: %s", _("Data size"), size);
+					g_free (size);
+#ifdef HAVE_GIO
+					GdaBlob *b2;
+					glong read;
+					b2 = gda_blob_copy (blob);
+					read = gda_blob_op_read (b2->op, b2, 0, 1024);
+					bin = (GdaBinary *) b2;
+					ctype = g_content_type_guess (NULL, bin->data, (gsize) bin->binary_length, NULL);
+#endif
+				}
+				else
+					g_string_append_printf (string, "%s: %s", _("Data size"), _("Unknown"));
+			}
+			else {
+				size = format_size (bin->binary_length);
+				g_string_append_printf (string, "%s: %s", _("Data size"), size);
+				g_free (size);
+#ifdef HAVE_GIO
+				ctype = g_content_type_guess (NULL, bin->data, (gsize) bin->binary_length, NULL);
+#endif
+			}
+		}
+		else
+			g_assert_not_reached ();
+	}
+	else
+		g_string_append_printf (string, "<i>%s</i>", _("No data"));
+
+#ifdef HAVE_GIO
+	if (ctype) {
+		GList *list;
+		gchar *descr, *tmp;
+		descr = g_content_type_get_description (ctype);
+		tmp = g_markup_printf_escaped (descr);
+		g_free (descr);
+		g_string_append_printf (string, "\n%s: %s", _("Data type"), tmp);
+		g_free (tmp);
+
+		list = g_app_info_get_all_for_type (ctype);
+		for (; list; list = list->next) {
+			GAppInfo *ai;
+			ai = (GAppInfo*) list->data;
+			g_print ("\t open with %s (%s)\n", g_app_info_get_name (ai),
+				 g_app_info_get_executable (ai));
+		}
+		g_free (ctype);
+	}
+#endif
+
+
+	gtk_label_set_markup (GTK_LABEL (binmenu->props_label), string->str);
+	g_string_free (string, TRUE);
+
+	gtk_widget_set_sensitive (binmenu->load_button, editable);
+	gtk_widget_set_sensitive (binmenu->save_button, (value && !gda_value_is_null (value)) ? TRUE : FALSE);
 }
 
 /*
@@ -232,8 +337,8 @@ common_bin_reset (BinMenu *binmenu)
 {
 	if (binmenu->tmpvalue)
 		gda_value_free (binmenu->tmpvalue);
-	if (binmenu->menu)
-		gtk_widget_destroy (binmenu->menu);
+	if (binmenu->popup)
+		gtk_widget_destroy (binmenu->popup);
 
 	memset (binmenu, 0, sizeof (BinMenu));
 }
diff --git a/libgda-ui/data-entries/common-bin.h b/libgda-ui/data-entries/common-bin.h
index 0243876..2784bea 100644
--- a/libgda-ui/data-entries/common-bin.h
+++ b/libgda-ui/data-entries/common-bin.h
@@ -21,22 +21,25 @@
 #define __COMMON_BIN_H__
 
 #include <gtk/gtk.h>
+#include "../internal/popup-container.h"
 
 typedef void (*BinCallback) (gpointer, GValue *);
 typedef struct {
-        GtkWidget    *menu; /* popup menu */
-        GtkWidget    *load_mitem;
-        GtkWidget    *save_mitem;
+        GtkWidget    *popup; /* PopupContainer popup window */
+        GtkWidget    *load_button;
+        GtkWidget    *save_button;
+	GtkWidget    *props_label;
 
 	GType         entry_type;
-	const GValue *tmpvalue;
+	GValue       *tmpvalue;
 
 	BinCallback   loaded_value_cb;
 	gpointer      loaded_value_cb_data;
 } BinMenu;
 
 
-void         common_bin_create_menu (BinMenu *binmenu, GtkWidget *attach_to, GType entry_type, BinCallback loaded_value_cb, gpointer loaded_value_cb_data);
+void         common_bin_create_menu (BinMenu *binmenu, PopupContainerPositionFunc pos_func, GType entry_type,
+				     BinCallback loaded_value_cb, gpointer loaded_value_cb_data);
 void         common_bin_adjust_menu (BinMenu *binmenu, gboolean editable, const GValue *value);
 void         common_bin_reset (BinMenu *binmenu);
 
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c b/libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c
index a363baf..7120031 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c
@@ -381,6 +381,41 @@ bin_data_changed_cb (GdauiDataCellRendererBin *bincell, GValue *value)
         gda_value_free (value);
 }
 
+static void
+popup_position (PopupContainer *container, gint *out_x, gint *out_y)
+{
+	GtkWidget *poswidget;
+	GdkEvent *event;
+	GdkRectangle *rect;
+	gint x, y;
+
+	poswidget = g_object_get_data (G_OBJECT (container), "__poswidget");
+	event = g_object_get_data (G_OBJECT (container), "__event");
+	rect = g_object_get_data (G_OBJECT (container), "__rect");
+
+	if (event && (event->type == GDK_BUTTON_PRESS)) {
+		GdkEventButton *rev = (GdkEventButton*) event;
+		gdk_window_get_origin (rev->window, &x, &y);
+		x += (gint) rev->x;
+		y += (gint) rev->y;
+	}
+	else {
+		g_assert (rect);
+		gdk_window_get_origin (gtk_tree_view_get_bin_window (GTK_TREE_VIEW (poswidget)), &x, &y);
+		x += rect->x;
+		y += rect->y;
+	}
+
+	if (x < 0)
+                x = 0;
+
+        if (y < 0)
+                y = 0;
+
+	*out_x = x;
+	*out_y = y;
+}
+
 static gboolean
 gdaui_data_cell_renderer_bin_activate  (GtkCellRenderer            *cell,
 					GdkEvent                   *event,
@@ -396,12 +431,13 @@ gdaui_data_cell_renderer_bin_activate  (GtkCellRenderer            *cell,
 	GtkTreeIter iter;
 
         bincell = GDAUI_DATA_CELL_RENDERER_BIN (cell);
-	int event_time;
 	
 	g_object_set_data_full (G_OBJECT (bincell), "last_path", g_strdup (path), g_free);
-	if (!bincell->priv->menu.menu)
-		common_bin_create_menu (&(bincell->priv->menu), widget, bincell->priv->type,
+	if (!bincell->priv->menu.popup) {
+		common_bin_create_menu (&(bincell->priv->menu), popup_position, bincell->priv->type,
 					(BinCallback) bin_data_changed_cb, bincell);
+		g_object_set_data (G_OBJECT (bincell->priv->menu.popup), "__poswidget", widget);
+	}
 	
 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
 	tpath = gtk_tree_path_new_from_string (path);
@@ -415,9 +451,9 @@ gdaui_data_cell_renderer_bin_activate  (GtkCellRenderer            *cell,
 				    model_col, &value, -1);
 		common_bin_adjust_menu (&(bincell->priv->menu), bincell->priv->editable,
 					value);
-		event_time = gtk_get_current_event_time ();
-		gtk_menu_popup (GTK_MENU (bincell->priv->menu.menu), NULL, NULL, NULL, NULL,
-				0, event_time);
+		g_object_set_data (G_OBJECT (bincell->priv->menu.popup), "__event", event);
+		g_object_set_data (G_OBJECT (bincell->priv->menu.popup), "__rect", cell_area);
+		gtk_widget_show (bincell->priv->menu.popup);
 	}
 	gtk_tree_path_free (tpath);
 
diff --git a/libgda-ui/data-entries/gdaui-entry-bin.c b/libgda-ui/data-entries/gdaui-entry-bin.c
index 4ae2f9d..a5af886 100644
--- a/libgda-ui/data-entries/gdaui-entry-bin.c
+++ b/libgda-ui/data-entries/gdaui-entry-bin.c
@@ -184,10 +184,7 @@ gdaui_entry_bin_dispose (GObject   * object)
 			gda_value_free (gdaui_entry_bin->priv->current_data);
 			gdaui_entry_bin->priv->current_data = NULL;
 		}
-		if (gdaui_entry_bin->priv->menu.menu) {
-			gtk_widget_destroy (gdaui_entry_bin->priv->menu.menu);
-			gdaui_entry_bin->priv->menu.menu = NULL;
-		}
+		common_bin_reset (&(gdaui_entry_bin->priv->menu));
 
 		if (gdaui_entry_bin->priv->button_label) {
 			g_object_unref (gdaui_entry_bin->priv->button_label);
@@ -325,19 +322,44 @@ value_loaded_cb (GdauiEntryBin *dbin, GValue *new_value)
 }
 
 static void
+popup_position (PopupContainer *container, gint *out_x, gint *out_y)
+{
+	GtkWidget *poswidget;
+	poswidget = g_object_get_data (G_OBJECT (container), "__poswidget");
+
+	gint x, y;
+        GtkRequisition req;
+
+        gtk_widget_size_request (poswidget, &req);
+
+        gdk_window_get_origin (poswidget->window, &x, &y);
+
+        x += poswidget->allocation.x;
+        y += poswidget->allocation.y;
+        y += poswidget->allocation.height;
+
+        if (x < 0)
+                x = 0;
+
+        if (y < 0)
+                y = 0;
+
+	*out_x = x;
+	*out_y = y;
+}
+
+static void
 button_clicked_cb (GtkWidget *button, GdauiEntryBin *dbin)
 {
-	if (!dbin->priv->menu.menu)
-		common_bin_create_menu (&(dbin->priv->menu), button,
+	if (!dbin->priv->menu.popup) {
+		common_bin_create_menu (&(dbin->priv->menu), popup_position,
 					gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (dbin)),
 					(BinCallback) value_loaded_cb, dbin);
+		g_object_set_data (G_OBJECT (dbin->priv->menu.popup), "__poswidget", button);
+	}
 
 	common_bin_adjust_menu (&(dbin->priv->menu), dbin->priv->editable, dbin->priv->current_data);
-
-	int event_time;
-	event_time = gtk_get_current_event_time ();
-	gtk_menu_popup (GTK_MENU (dbin->priv->menu.menu), NULL, NULL, NULL, NULL,
-                        0, event_time);
+	gtk_widget_show (dbin->priv->menu.popup);
 }
 
 static void
@@ -369,8 +391,7 @@ set_editable (GdauiEntryWrapper *mgwrap, gboolean editable)
 	g_return_if_fail (dbin->priv);
 
 	dbin->priv->editable = editable;
-	if (dbin->priv->menu.load_mitem)
-		gtk_widget_set_sensitive (dbin->priv->menu.load_mitem, dbin->priv->editable);
+	common_bin_adjust_menu (&(dbin->priv->menu), editable, dbin->priv->current_data);
 }
 
 static void
diff --git a/libgda-ui/internal/Makefile.am b/libgda-ui/internal/Makefile.am
index e723a9e..dc58b46 100644
--- a/libgda-ui/internal/Makefile.am
+++ b/libgda-ui/internal/Makefile.am
@@ -16,5 +16,7 @@ libgda_ui_internal_la_SOURCES = \
 	gdaui-provider-auth-editor.h \
 	gdaui-provider-spec-editor.c \
 	gdaui-provider-spec-editor.h \
+	popup-container.h \
+	popup-container.c \
 	utility.h \
 	utility.c
diff --git a/libgda-ui/internal/popup-container.c b/libgda-ui/internal/popup-container.c
new file mode 100644
index 0000000..8726d09
--- /dev/null
+++ b/libgda-ui/internal/popup-container.c
@@ -0,0 +1,313 @@
+/*
+ * 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 void popup_container_hide   (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;
+	widget_class->hide = popup_container_hide;
+}
+
+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 ());
+}
+
+static void
+popup_container_hide (GtkWidget *widget)
+{
+	GTK_WIDGET_CLASS (parent_class)->hide (widget);
+	gtk_grab_remove (widget);
+}
+
+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;
+}
+
+static void
+popup_position (PopupContainer *container, gint *out_x, gint *out_y)
+{
+	GtkWidget *poswidget;
+	poswidget = g_object_get_data (G_OBJECT (container), "__poswidget");
+
+	gint x, y;
+        GtkRequisition req;
+
+        gtk_widget_size_request (poswidget, &req);
+
+        gdk_window_get_origin (poswidget->window, &x, &y);
+
+        x += poswidget->allocation.x;
+        y += poswidget->allocation.y;
+        y += poswidget->allocation.height;
+
+        if (x < 0)
+                x = 0;
+
+        if (y < 0)
+                y = 0;
+
+	*out_x = x;
+	*out_y = y;
+}
+
+/**
+ * popup_container_new_with_func
+ *
+ * Returns:
+ */
+GtkWidget *
+popup_container_new (GtkWidget *position_widget)
+{
+	PopupContainer *container;
+	g_return_val_if_fail (GTK_IS_WIDGET (position_widget), NULL);
+	
+	container = POPUP_CONTAINER (g_object_new (POPUP_CONTAINER_TYPE, "type", GTK_WINDOW_POPUP,
+						   NULL));
+	g_object_set_data (G_OBJECT (container), "__poswidget", position_widget);
+	container->priv->position_func = popup_position;
+	return (GtkWidget*) container;
+}
+
+
+/**
+ * popup_container_new_with_func
+ *
+ * Returns:
+ */
+GtkWidget *
+popup_container_new_with_func (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/libgda-ui/internal/popup-container.h b/libgda-ui/internal/popup-container.h
new file mode 100644
index 0000000..836225b
--- /dev/null
+++ b/libgda-ui/internal/popup-container.h
@@ -0,0 +1,57 @@
+/*
+ * 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 (GtkWidget *position_widget);
+GtkWidget             *popup_container_new_with_func (PopupContainerPositionFunc pos_func);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/browser/common/popup-container.c b/tools/browser/common/popup-container.c
deleted file mode 100644
index e259f32..354fef4
--- a/tools/browser/common/popup-container.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * 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 void popup_container_hide   (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;
-	widget_class->hide = popup_container_hide;
-}
-
-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 ());
-}
-
-static void
-popup_container_hide (GtkWidget *widget)
-{
-	GTK_WIDGET_CLASS (parent_class)->hide (widget);
-	gtk_grab_remove (widget);
-}
-
-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;
-}
-
-static void
-popup_position (PopupContainer *container, gint *out_x, gint *out_y)
-{
-	GtkWidget *poswidget;
-	poswidget = g_object_get_data (G_OBJECT (container), "__poswidget");
-
-	gint x, y;
-        gint bwidth, bheight;
-        GtkRequisition req;
-
-        gtk_widget_size_request (poswidget, &req);
-
-        gdk_window_get_origin (poswidget->window, &x, &y);
-
-        x += poswidget->allocation.x;
-        y += poswidget->allocation.y;
-        bwidth = poswidget->allocation.width;
-        bheight = poswidget->allocation.height;
-
-        x += bwidth - req.width;
-        y += bheight;
-
-        if (x < 0)
-                x = 0;
-
-        if (y < 0)
-                y = 0;
-
-	*out_x = x;
-	*out_y = y;
-}
-
-/**
- * popup_container_new_with_func
- *
- * Returns:
- */
-GtkWidget *
-popup_container_new (GtkWidget *position_widget)
-{
-	PopupContainer *container;
-	g_return_val_if_fail (GTK_IS_WIDGET (position_widget), NULL);
-	
-	container = POPUP_CONTAINER (g_object_new (POPUP_CONTAINER_TYPE, "type", GTK_WINDOW_POPUP,
-						   NULL));
-	g_object_set_data (G_OBJECT (container), "__poswidget", position_widget);
-	container->priv->position_func = popup_position;
-	return (GtkWidget*) container;
-}
-
-
-/**
- * popup_container_new_with_func
- *
- * Returns:
- */
-GtkWidget *
-popup_container_new_with_func (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/common/popup-container.c b/tools/browser/common/popup-container.c
new file mode 120000
index e259f32..354fef4
--- /dev/null
+++ b/tools/browser/common/popup-container.c
@@ -0,0 +1 @@
+../../../libgda-ui/internal/popup-container.c
\ No newline at end of file
diff --git a/tools/browser/common/popup-container.h b/tools/browser/common/popup-container.h
deleted file mode 100644
index 836225b..cfcd232
--- a/tools/browser/common/popup-container.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 (GtkWidget *position_widget);
-GtkWidget             *popup_container_new_with_func (PopupContainerPositionFunc pos_func);
-
-G_END_DECLS
-
-#endif
diff --git a/tools/browser/common/popup-container.h b/tools/browser/common/popup-container.h
new file mode 120000
index 836225b..cfcd232
--- /dev/null
+++ b/tools/browser/common/popup-container.h
@@ -0,0 +1 @@
+../../../libgda-ui/internal/popup-container.h
\ No newline at end of file



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]