[libgda] GdaBrowser: implemented graph saving and loading



commit de477574fb098ae0c9937946e03731a84b3726f0
Author: Vivien Malerba <malerba gnome-db org>
Date:   Mon Aug 10 15:46:09 2009 +0200

    GdaBrowser: implemented graph saving and loading
    
    and other minor changes

 tools/browser/browser-favorites.c                  |  109 +++++++++++-
 tools/browser/browser-favorites.h                  |    9 +-
 tools/browser/canvas/browser-canvas-item.h         |    4 +
 tools/browser/canvas/browser-canvas-table.c        |   32 ++++
 tools/browser/canvas/browser-canvas.c              |   36 ++++-
 tools/browser/canvas/browser-canvas.h              |    2 +
 tools/browser/mgr-favorites.c                      |   13 ++
 tools/browser/mgr-favorites.h                      |    2 +
 tools/browser/schema-browser/Makefile.am           |   16 ++
 tools/browser/schema-browser/favorite-selector.c   |   39 +++-
 tools/browser/schema-browser/favorite-selector.h   |    3 +-
 tools/browser/schema-browser/marshal.list          |   26 +++
 tools/browser/schema-browser/objects-index.c       |    7 +-
 tools/browser/schema-browser/objects-index.h       |    3 +-
 tools/browser/schema-browser/relations-diagram.c   |  146 ++++++++++++++-
 tools/browser/schema-browser/relations-diagram.h   |    7 +-
 .../schema-browser/schema-browser-perspective.c    |  197 +++++++++++++-------
 .../schema-browser/schema-browser-perspective.h    |    2 +
 tools/browser/support.c                            |    6 +-
 19 files changed, 556 insertions(+), 103 deletions(-)
---
diff --git a/tools/browser/browser-favorites.c b/tools/browser/browser-favorites.c
index 34c166e..1fccd6f 100644
--- a/tools/browser/browser-favorites.c
+++ b/tools/browser/browser-favorites.c
@@ -401,14 +401,16 @@ favorites_reorder (BrowserFavorites *bfav, gint order_key, gint id, gint new_pos
  *
  * Add a new favorite, or replace an existing one.
  * NOTE:
- *   - if @fav->id is NULL then it's either an update or an insert (depending if fav->contents exists)
+ *   - if @fav->id is < 0 then it's either an update or an insert (depending if fav->contents exists)
  *     and if it's not it is an UPDATE
  *   - @fav->type can't be 0
  *   - @fav->contents can't be %NULL
  *
+ * On success @fav->id contains the favorite's ID, otherwise it will contain -1.
+ *
  * if @order_key is negative, then no ordering is done and @pos is ignored.
  */
-gint
+gboolean
 browser_favorites_add (BrowserFavorites *bfav, guint session_id,
 		       BrowserFavoritesAttributes *fav,
 		       gint order_key, gint pos,
@@ -483,6 +485,9 @@ browser_favorites_add (BrowserFavorites *bfav, guint session_id,
 			goto err;
 		}
 		g_object_unref (stmt);
+
+		favid = find_favorite (bfav, session_id, fav->id, fav->contents, NULL);
+		fav->id = favid;
 	}
 	else {
 		/* update favorite's contents */
@@ -508,6 +513,18 @@ browser_favorites_add (BrowserFavorites *bfav, guint session_id,
 								 gda_sql_builder_ident (builder, 0, "id"),
 								 gda_sql_builder_param (builder, 0, "id", G_TYPE_INT, FALSE),
 								 0));
+		if (fav->id == favid) {
+			/* alter name and description only if fav->id was OK */
+			gda_sql_builder_add_field (builder,
+						   gda_sql_builder_ident (builder, 0, "name"),
+						   gda_sql_builder_param (builder, 0, "name", G_TYPE_STRING,
+									  TRUE));
+			gda_sql_builder_add_field (builder,
+						   gda_sql_builder_ident (builder, 0, "descr"),
+						   gda_sql_builder_param (builder, 0, "descr", G_TYPE_STRING,
+									  TRUE));
+		}
+
 		stmt = gda_sql_builder_get_statement (builder, error);
 		g_object_unref (G_OBJECT (builder));
 		if (!stmt)
@@ -517,6 +534,7 @@ browser_favorites_add (BrowserFavorites *bfav, guint session_id,
 			goto err;
 		}
 		g_object_unref (stmt);
+		fav->id = favid;
 	}
 
 	if (order_key >= 0) {
@@ -709,12 +727,13 @@ browser_favorites_list (BrowserFavorites *bfav, guint session_id, BrowserFavorit
 
 	gda_sql_builder_set_where (b,
 				   gda_sql_builder_cond_v (b, 0, GDA_SQL_OPERATOR_TYPE_AND, and_cond_ids, and_cond_size));
-
+#ifdef GDA_DEBUG_NO
 	{
 		GdaSqlStatement *sqlst;
 		sqlst = gda_sql_builder_get_sql_statement (b, TRUE);
 		g_print ("=>%s\n", gda_sql_statement_serialize (sqlst));
 	}
+#endif
 
 	stmt = gda_sql_builder_get_statement (b, error);
 	g_object_unref (G_OBJECT (b));
@@ -727,8 +746,10 @@ browser_favorites_list (BrowserFavorites *bfav, guint session_id, BrowserFavorit
 
 	model = gda_connection_statement_execute_select (bfav->priv->store_cnc, stmt, params, error);
 	g_object_unref (stmt);
-	if (!model)
+	if (!model) {
+		g_warning ("Malformed dictionary database, cannot get favorites list (this should happen only while in dev.).");
 		goto out;
+	}
 
 	gint nrows;
 	nrows = gda_data_model_get_n_rows (model);
@@ -872,3 +893,83 @@ browser_favorites_delete (BrowserFavorites *bfav, guint session_id,
 
 	return retval;
 }
+
+/**
+ * browser_favorites_get
+ *
+ * Get all the information about a favorite from its id: fills the @out_fav
+ * pointed structure.
+ */
+gboolean
+browser_favorites_get (BrowserFavorites *bfav, gint fav_id,
+		       BrowserFavoritesAttributes *out_fav, GError **error)
+{
+	GdaSqlBuilder *b;
+	GdaStatement *stmt;
+	GdaSet *params = NULL;
+	GdaDataModel *model;
+	gboolean retval = FALSE;
+
+	g_return_val_if_fail (BROWSER_IS_FAVORITES (bfav), FALSE);
+	g_return_val_if_fail (out_fav, FALSE);
+	g_return_val_if_fail (fav_id >= 0, FALSE);
+
+	memset (out_fav, 0, sizeof (BrowserFavoritesAttributes));
+
+	b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
+	gda_sql_builder_add_field (b,
+				   gda_sql_builder_ident (b, 0, "id"), 0);
+	gda_sql_builder_add_field (b,
+				   gda_sql_builder_ident (b, 0, "type"), 0);
+	gda_sql_builder_add_field (b,
+				   gda_sql_builder_ident (b, 0, "name"), 0);
+	gda_sql_builder_add_field (b,
+				   gda_sql_builder_ident (b, 0, "descr"), 0);
+	gda_sql_builder_add_field (b,
+				   gda_sql_builder_ident (b, 0, "contents"), 0);
+	gda_sql_builder_select_add_target (b, 0,
+					   gda_sql_builder_ident (b, 0, FAVORITES_TABLE_NAME),
+					   NULL);
+
+	gda_sql_builder_set_where (b,
+				   gda_sql_builder_cond (b, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+							 gda_sql_builder_ident (b, 0, "id"),
+						     gda_sql_builder_param (b, 0, "id", G_TYPE_INT, FALSE), 0));
+	stmt = gda_sql_builder_get_statement (b, error);
+	g_object_unref (G_OBJECT (b));
+	if (!stmt)
+		return FALSE;
+	params = gda_set_new_inline (1,
+				     "id", G_TYPE_INT, fav_id);
+	model = gda_connection_statement_execute_select (bfav->priv->store_cnc, stmt, params, error);
+	g_object_unref (stmt);
+	g_object_unref (params);
+
+	if (!model)
+		return FALSE;
+
+	gint nrows;
+	nrows = gda_data_model_get_n_rows (model);
+	if (nrows == 1) {
+		gint i;
+		const GValue *cvalues[5];
+		for (i = 0; i < 5; i++) {
+			cvalues [i] = gda_data_model_get_value_at (model, i, 0, error);
+			if (!cvalues [i])
+				goto out;
+		}
+
+		out_fav->id = g_value_get_int (cvalues [0]);
+		out_fav->type = favorite_string_to_type (g_value_get_string (cvalues [1]));
+		if (G_VALUE_TYPE (cvalues [2]) == G_TYPE_STRING)
+			out_fav->name = g_value_dup_string (cvalues [2]);
+		if (G_VALUE_TYPE (cvalues [3]) == G_TYPE_STRING)
+			out_fav->descr = g_value_dup_string (cvalues [3]);
+		out_fav->contents = g_value_dup_string (cvalues [4]);
+		retval = TRUE;
+	}
+	
+ out:
+	g_object_unref (G_OBJECT (model));
+	return retval;
+}
diff --git a/tools/browser/browser-favorites.h b/tools/browser/browser-favorites.h
index bd8e6ea..b4145c2 100644
--- a/tools/browser/browser-favorites.h
+++ b/tools/browser/browser-favorites.h
@@ -68,15 +68,18 @@ GType               browser_favorites_get_type               (void) G_GNUC_CONST
 
 BrowserFavorites   *browser_favorites_new                    (GdaMetaStore *store);
 
-gint                browser_favorites_add          (BrowserFavorites *bfav, guint session_id,
+gboolean            browser_favorites_add          (BrowserFavorites *bfav, guint session_id,
 						    BrowserFavoritesAttributes *fav,
 						    gint order_key, gint pos,
 						    GError **error);
-GSList             *browser_favorites_list         (BrowserFavorites *bcnc, guint session_id, 
+GSList             *browser_favorites_list         (BrowserFavorites *bfav, guint session_id, 
 						    BrowserFavoritesType type, gint order_key, GError **error);
-gboolean            browser_favorites_delete       (BrowserFavorites *bcnc, guint session_id,
+gboolean            browser_favorites_delete       (BrowserFavorites *bfav, guint session_id,
 						    BrowserFavoritesAttributes *fav, GError **error);
 void                browser_favorites_free_list    (GSList *fav_list);
+
+gboolean            browser_favorites_get          (BrowserFavorites *bfav, gint fav_id,
+						    BrowserFavoritesAttributes *out_fav, GError **error);
 G_END_DECLS
 
 #endif
diff --git a/tools/browser/canvas/browser-canvas-item.h b/tools/browser/canvas/browser-canvas-item.h
index 066ea5f..58555e5 100644
--- a/tools/browser/canvas/browser-canvas-item.h
+++ b/tools/browser/canvas/browser-canvas-item.h
@@ -23,6 +23,7 @@
 
 #include <goocanvas.h>
 #include "browser-canvas-decl.h"
+#include <libxml/tree.h>
 
 G_BEGIN_DECLS
 
@@ -54,6 +55,9 @@ struct _BrowserCanvasItemClass
 	void (*drag_data_get) (BrowserCanvasItem *citem, GdkDragContext *drag_context,
 			       GtkSelectionData *data, guint info, guint time);
 	void (*set_selected)  (BrowserCanvasItem *citem, gboolean selected);
+
+	/* serialization and de-serialization virtual methods (don't need to be implemented) */
+	xmlNodePtr (*serialize) (BrowserCanvasItem *citem);
 };
 
 GType              browser_canvas_item_get_type       (void) G_GNUC_CONST;
diff --git a/tools/browser/canvas/browser-canvas-table.c b/tools/browser/canvas/browser-canvas-table.c
index 342f225..b87917c 100644
--- a/tools/browser/canvas/browser-canvas-table.c
+++ b/tools/browser/canvas/browser-canvas-table.c
@@ -45,6 +45,8 @@ static void browser_canvas_table_drag_data_get (BrowserCanvasItem *citem, GdkDra
 						GtkSelectionData *data, guint info, guint time);
 static void browser_canvas_table_set_selected (BrowserCanvasItem *citem, gboolean selected);
 
+static xmlNodePtr browser_canvas_table_serialize (BrowserCanvasItem *citem);
+
 enum
 {
 	PROP_0,
@@ -104,6 +106,7 @@ browser_canvas_table_class_init (BrowserCanvasTableClass *class)
 	table_parent_class = g_type_class_peek_parent (class);
 	iclass->drag_data_get = browser_canvas_table_drag_data_get;
 	iclass->set_selected = browser_canvas_table_set_selected;
+	iclass->serialize = browser_canvas_table_serialize;
 
 	object_class->dispose = browser_canvas_table_dispose;
 	object_class->finalize = browser_canvas_table_finalize;
@@ -543,6 +546,35 @@ browser_canvas_table_set_selected (BrowserCanvasItem *citem, gboolean selected)
 		      "visibility", selected ? GOO_CANVAS_ITEM_VISIBLE : GOO_CANVAS_ITEM_HIDDEN, NULL);
 }
 
+static xmlNodePtr
+browser_canvas_table_serialize (BrowserCanvasItem *citem)
+{
+	BrowserCanvasTable *ctable;
+
+	ctable = BROWSER_CANVAS_TABLE (citem);
+	if (!ctable->priv->table)
+		return NULL;
+
+	GdaMetaDbObject *dbo;
+	xmlNodePtr node;
+	GooCanvasBounds bounds;
+	gchar *str;
+
+	dbo = GDA_META_DB_OBJECT (ctable->priv->table);
+	node = xmlNewNode (NULL, "table");
+	xmlSetProp (node, BAD_CAST "schema", BAD_CAST (dbo->obj_schema));
+	xmlSetProp (node, BAD_CAST "name", BAD_CAST (dbo->obj_name));
+	goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (citem), &bounds);
+	str = g_strdup_printf ("%.1f", bounds.x1);
+	xmlSetProp (node, BAD_CAST "x", BAD_CAST str);
+	g_free (str);
+	str = g_strdup_printf ("%.1f", bounds.y1);
+	xmlSetProp (node, BAD_CAST "y", BAD_CAST str);
+	g_free (str);
+	
+	return node;
+}
+
 /**
  * browser_canvas_table_get_anchor_bounds
  *
diff --git a/tools/browser/canvas/browser-canvas.c b/tools/browser/canvas/browser-canvas.c
index f77f84f..103eefc 100644
--- a/tools/browser/canvas/browser-canvas.c
+++ b/tools/browser/canvas/browser-canvas.c
@@ -1120,15 +1120,40 @@ browser_canvas_scale_layout (BrowserCanvas *canvas, gdouble scale)
 gchar *
 browser_canvas_serialize_items (BrowserCanvas *canvas)
 {
+	gchar *retval = NULL;
 	GSList *list;
+	xmlDocPtr doc;
+	xmlNodePtr topnode;
+
 	g_return_val_if_fail (IS_BROWSER_CANVAS (canvas), NULL);
 	
+	/* create XML doc and root node */
+	doc = xmlNewDoc (BAD_CAST "1.0");
+	topnode = xmlNewDocNode (doc, NULL, BAD_CAST "canvas", NULL);
+        xmlDocSetRootElement (doc, topnode);
+	
+	/* actually serialize all the items which can be serialized */
 	for (list = canvas->priv->items; list; list = list->next) {
 		BrowserCanvasItem *item = BROWSER_CANVAS_ITEM (list->data);
-		TO_IMPLEMENT;
+		BrowserCanvasItemClass *iclass = (BrowserCanvasItemClass*) G_OBJECT_GET_CLASS (item);
+		if (iclass->serialize) {
+			xmlNodePtr node;
+			node = iclass->serialize (item);
+			if (node)
+				xmlAddChild (topnode, node);
+		}
 	}
 
-	return NULL;
+	/* create buffer from XML tree */
+	xmlChar *xstr = NULL;
+	xmlDocDumpMemory (doc, &xstr, NULL);
+	if (xstr) {
+		retval = g_strdup ((gchar *) xstr);
+		xmlFree (xstr);
+	}
+	xmlFreeDoc (doc);
+	
+	return retval;
 }
 
 /**
@@ -1162,3 +1187,10 @@ browser_canvas_item_toggle_select (BrowserCanvas *canvas, BrowserCanvasItem *ite
 	}
 	g_signal_emit (canvas, canvas_signals [ITEM_SELECTED], 0, item);
 }
+
+void
+browser_canvas_translate_item (BrowserCanvas *canvas, BrowserCanvasItem *item,
+			       gdouble dx, gdouble dy)
+{
+	browser_canvas_item_translate (item, dx, dy);
+}
diff --git a/tools/browser/canvas/browser-canvas.h b/tools/browser/canvas/browser-canvas.h
index 151e006..16ac943 100644
--- a/tools/browser/canvas/browser-canvas.h
+++ b/tools/browser/canvas/browser-canvas.h
@@ -81,6 +81,8 @@ void               browser_canvas_scale_layout            (BrowserCanvas *canvas
 gchar             *browser_canvas_serialize_items         (BrowserCanvas *canvas);
 
 void               browser_canvas_item_toggle_select      (BrowserCanvas *canvas, BrowserCanvasItem *item);
+void               browser_canvas_translate_item          (BrowserCanvas *canvas, BrowserCanvasItem *item,
+							   gdouble dx, gdouble dy);
 
 G_END_DECLS
 
diff --git a/tools/browser/mgr-favorites.c b/tools/browser/mgr-favorites.c
index 8d89f33..40a4d17 100644
--- a/tools/browser/mgr-favorites.c
+++ b/tools/browser/mgr-favorites.c
@@ -284,6 +284,12 @@ mgr_favorites_update_children (GdaTreeManager *manager, GdaTreeNode *node, const
 										  MGR_FAVORITES_ID_ATT_NAME,
 										  av, NULL);
 						gda_value_free (av);
+
+						g_value_set_uint ((av = gda_value_new (G_TYPE_UINT)), fav->type);
+						gda_tree_node_set_node_attribute (snode,
+										  MGR_FAVORITES_TYPE_ATT_NAME,
+										  av, NULL);
+						gda_value_free (av);
 						
 						/* icon */
 						GdkPixbuf *pixbuf;
@@ -306,6 +312,13 @@ mgr_favorites_update_children (GdaTreeManager *manager, GdaTreeNode *node, const
 									  MGR_FAVORITES_ID_ATT_NAME,
 									  av, NULL);
 					gda_value_free (av);
+
+					g_value_set_uint ((av = gda_value_new (G_TYPE_UINT)), fav->type);
+					gda_tree_node_set_node_attribute (snode,
+									  MGR_FAVORITES_TYPE_ATT_NAME,
+									  av, NULL);
+					gda_value_free (av);
+
 					
 					/* icon */
 					GdkPixbuf *pixbuf;
diff --git a/tools/browser/mgr-favorites.h b/tools/browser/mgr-favorites.h
index ecb85b7..45b9c18 100644
--- a/tools/browser/mgr-favorites.h
+++ b/tools/browser/mgr-favorites.h
@@ -54,6 +54,8 @@ GdaTreeManager* mgr_favorites_new                      (BrowserConnection *bcnc,
 #define MGR_FAVORITES_CONTENTS_ATT_NAME "fav_contents"
 /* name of the attribute which stores the favorite's id */
 #define MGR_FAVORITES_ID_ATT_NAME "fav_id"
+/* name of the attribute which stores the favorite type */
+#define MGR_FAVORITES_TYPE_ATT_NAME "fav_type"
 
 G_END_DECLS
 
diff --git a/tools/browser/schema-browser/Makefile.am b/tools/browser/schema-browser/Makefile.am
index c55c42c..08a1ac4 100644
--- a/tools/browser/schema-browser/Makefile.am
+++ b/tools/browser/schema-browser/Makefile.am
@@ -8,7 +8,14 @@ AM_CPPFLAGS = \
 	$(LIBGDA_CFLAGS) \
 	$(GTK_CFLAGS)
 
+marshal.h: marshal.list $(GLIB_GENMARSHAL)
+	$(GLIB_GENMARSHAL) $< --header --prefix=_sb_marshal > $@
+marshal.c: marshal.list $(GLIB_GENMARSHAL) marshal.h
+	$(GLIB_GENMARSHAL) $< --body --prefix=_sb_marshal > $@
+
 libperspective_la_SOURCES = \
+	marshal.c \
+	marshal.h \
 	perspective-main.h \
 	perspective-main.c \
 	schema-browser-perspective.h \
@@ -24,6 +31,8 @@ libperspective_la_SOURCES = \
 	mgr-columns.c \
 	mgr-columns.h
 
+$(OBJECTS): marshal.c marshal.h
+
 if HAVE_GOOCANVAS
 libperspective_la_SOURCES += \
 	table-relations.c \
@@ -31,3 +40,10 @@ libperspective_la_SOURCES += \
 	relations-diagram.c \
 	relations-diagram.h
 endif
+
+EXTRA_DIST = \
+	marshal.list
+
+CLEANFILES = \
+	marshal.h \
+	marshal.c
diff --git a/tools/browser/schema-browser/favorite-selector.c b/tools/browser/schema-browser/favorite-selector.c
index 99e8e6f..f6f0726 100644
--- a/tools/browser/schema-browser/favorite-selector.c
+++ b/tools/browser/schema-browser/favorite-selector.c
@@ -29,6 +29,7 @@
 #include <libgda-ui/gdaui-tree-store.h>
 #include "../dnd.h"
 #include "../support.h"
+#include "marshal.h"
 #include "../cc-gray-bar.h"
 #include "../browser-favorites.h"
 
@@ -53,6 +54,15 @@ enum {
 static guint favorite_selector_signals[LAST_SIGNAL] = { 0 };
 static GObjectClass *parent_class = NULL;
 
+/* columns of the resulting GtkTreeModel */
+enum {
+	COLUMN_MARKUP = 0,
+	COLUMN_ICON = 1,
+	COLUMN_CONTENTS = 2,
+	COLUMN_TYPE = 3,
+	COLUMN_ID = 4
+};
+
 
 /*
  * FavoriteSelector class implementation
@@ -72,8 +82,8 @@ favorite_selector_class_init (FavoriteSelectorClass *klass)
                               G_SIGNAL_RUN_FIRST,
                               G_STRUCT_OFFSET (FavoriteSelectorClass, selection_changed),
                               NULL, NULL,
-                              g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
-                              1, G_TYPE_STRING);
+                              _sb_marshal_VOID__INT_ENUM_STRING, G_TYPE_NONE,
+                              3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_STRING);
 	klass->selection_changed = NULL;
 
 	object_class->dispose = favorite_selector_dispose;
@@ -146,8 +156,13 @@ selection_changed_cb (GtkTreeView *treeview,  GtkTreePath *path,
 	select = gtk_tree_view_get_selection (treeview);
 	if (gtk_tree_selection_get_selected (select, &model, &iter)) {
 		gchar *str;
-		gtk_tree_model_get (model, &iter, 2, &str, -1);
-		g_signal_emit (tsel, favorite_selector_signals [SELECTION_CHANGED], 0, str);
+		guint type;
+		gint fav_id;
+		gtk_tree_model_get (model, &iter,
+				    COLUMN_ID, &fav_id,
+				    COLUMN_TYPE, &type,
+				    COLUMN_CONTENTS, &str, -1);
+		g_signal_emit (tsel, favorite_selector_signals [SELECTION_CHANGED], 0, fav_id, type, str);
 		g_free (str);
 	}
 }
@@ -210,10 +225,12 @@ favorite_selector_new (BrowserConnection *bcnc)
 	GtkCellRenderer *renderer;
 	GtkTreeViewColumn *column;
 
-	model = gdaui_tree_store_new (tsel->priv->tree, 3,
+	model = gdaui_tree_store_new (tsel->priv->tree, 5,
 				      G_TYPE_STRING, "markup",
 				      G_TYPE_OBJECT, "icon",
-				      G_TYPE_STRING, MGR_FAVORITES_CONTENTS_ATT_NAME);
+				      G_TYPE_STRING, MGR_FAVORITES_CONTENTS_ATT_NAME,
+				      G_TYPE_UINT, MGR_FAVORITES_TYPE_ATT_NAME,
+				      G_TYPE_INT, MGR_FAVORITES_ID_ATT_NAME);
 	treeview = gtk_tree_view_new_with_model (model);
 	g_object_unref (model);
 
@@ -222,12 +239,12 @@ favorite_selector_new (BrowserConnection *bcnc)
 
 	renderer = gtk_cell_renderer_pixbuf_new ();
 	gtk_tree_view_column_pack_start (column, renderer, FALSE);
-	gtk_tree_view_column_add_attribute (column, renderer, "pixbuf", 1);
+	gtk_tree_view_column_add_attribute (column, renderer, "pixbuf", COLUMN_ICON);
 
 	/* text */
 	renderer = gtk_cell_renderer_text_new ();
 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
-	gtk_tree_view_column_add_attribute (column, renderer, "markup", 0);
+	gtk_tree_view_column_add_attribute (column, renderer, "markup", COLUMN_MARKUP);
 
 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 	
@@ -343,9 +360,9 @@ tree_store_drag_can_drag_cb (GdauiTreeStore *store, const gchar *path, FavoriteS
 	return FALSE;
 }
 
-static
-gboolean tree_store_drag_get_cb (GdauiTreeStore *store, const gchar *path, GtkSelectionData *selection_data,
-				 FavoriteSelector *tsel)
+static gboolean
+tree_store_drag_get_cb (GdauiTreeStore *store, const gchar *path, GtkSelectionData *selection_data,
+			FavoriteSelector *tsel)
 {
 	GdaTreeNode *node;
 	node = gda_tree_get_node (tsel->priv->tree, path, FALSE);
diff --git a/tools/browser/schema-browser/favorite-selector.h b/tools/browser/schema-browser/favorite-selector.h
index bc56a10..7074f14 100644
--- a/tools/browser/schema-browser/favorite-selector.h
+++ b/tools/browser/schema-browser/favorite-selector.h
@@ -46,7 +46,8 @@ struct _FavoriteSelector {
 struct _FavoriteSelectorClass {
 	GtkVBoxClass          parent_class;
 
-	void                (*selection_changed) (FavoriteSelector *sel, const gchar *fav_contents);
+	void                (*selection_changed) (FavoriteSelector *sel, gint fav_id,
+						  BrowserFavoritesType fav_type, const gchar *fav_contents);
 };
 
 GType                    favorite_selector_get_type (void) G_GNUC_CONST;
diff --git a/tools/browser/schema-browser/marshal.list b/tools/browser/schema-browser/marshal.list
new file mode 100644
index 0000000..d9ba6de
--- /dev/null
+++ b/tools/browser/schema-browser/marshal.list
@@ -0,0 +1,26 @@
+# 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/schema-browser/objects-index.c b/tools/browser/schema-browser/objects-index.c
index 88e6786..0b9f342 100644
--- a/tools/browser/schema-browser/objects-index.c
+++ b/tools/browser/schema-browser/objects-index.c
@@ -29,6 +29,7 @@
 #include "../dnd.h"
 #include "../support.h"
 #include "../cc-gray-bar.h"
+#include "marshal.h"
 
 struct _ObjectsIndexPrivate {
 	BrowserConnection *bcnc;
@@ -69,8 +70,8 @@ objects_index_class_init (ObjectsIndexClass *klass)
                               G_SIGNAL_RUN_FIRST,
                               G_STRUCT_OFFSET (ObjectsIndexClass, selection_changed),
                               NULL, NULL,
-                              g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
-                              1, G_TYPE_STRING);
+                              _sb_marshal_VOID__ENUM_STRING, G_TYPE_NONE,
+                              2, G_TYPE_UINT, G_TYPE_STRING);
 	klass->selection_changed = NULL;
 
 	object_class->dispose = objects_index_dispose;
@@ -358,7 +359,7 @@ objects_button_clicked_cb (GtkWidget *button, ObjectsIndex *index)
 	g_free (tmp1);
 	g_free (tmp2);
 	g_free (tmp3);
-	g_signal_emit (index, objects_index_signals [SELECTION_CHANGED], 0, str);
+	g_signal_emit (index, objects_index_signals [SELECTION_CHANGED], 0, BROWSER_FAVORITES_TABLES, str);
 	g_free (str);
 }
 
diff --git a/tools/browser/schema-browser/objects-index.h b/tools/browser/schema-browser/objects-index.h
index 7755462..fd0258e 100644
--- a/tools/browser/schema-browser/objects-index.h
+++ b/tools/browser/schema-browser/objects-index.h
@@ -47,7 +47,8 @@ struct _ObjectsIndexClass {
 	GtkVBoxClass          parent_class;
 
 	/* signals */
-	void                (*selection_changed) (ObjectsIndex *sel, const gchar *fav_contents);
+	void                (*selection_changed) (ObjectsIndex *sel,
+						  BrowserFavoritesType fav_type, const gchar *fav_contents);
 };
 
 GType                    objects_index_get_type (void) G_GNUC_CONST;
diff --git a/tools/browser/schema-browser/relations-diagram.c b/tools/browser/schema-browser/relations-diagram.c
index e0f481e..9bbcc23 100644
--- a/tools/browser/schema-browser/relations-diagram.c
+++ b/tools/browser/schema-browser/relations-diagram.c
@@ -31,7 +31,7 @@
 
 struct _RelationsDiagramPrivate {
 	BrowserConnection *bcnc;
-	gchar *name; /* diagram's name */
+	gint fav_id; /* diagram's ID as a favorite, -1=>not a favorite */
 
 	CcGrayBar *header;
 	GtkWidget *canvas;
@@ -55,6 +55,7 @@ static void relations_diagram_get_property (GObject *object,
 					    GParamSpec *pspec);
 
 static void meta_changed_cb (BrowserConnection *bcnc, GdaMetaStruct *mstruct, RelationsDiagram *diagram);
+static void relations_diagram_set_fav_id (RelationsDiagram *diagram, gint fav_id, GError **error);
 
 /* properties */
 enum {
@@ -93,7 +94,7 @@ static void
 relations_diagram_init (RelationsDiagram *diagram, RelationsDiagramClass *klass)
 {
 	diagram->priv = g_new0 (RelationsDiagramPrivate, 1);
-	diagram->priv->name = NULL;
+	diagram->priv->fav_id = -1;
 	diagram->priv->window = NULL;
 }
 
@@ -113,7 +114,6 @@ relations_diagram_dispose (GObject *object)
 		if (diagram->priv->window)
 			gtk_widget_destroy (diagram->priv->window);
 
-		g_free (diagram->priv->name);
 		g_free (diagram->priv);
 		diagram->priv = NULL;
 	}
@@ -278,8 +278,7 @@ real_save_clicked_cb (GtkWidget *button, RelationsDiagram *diagram)
 {
 	gchar *str;
 
-	//str = browser_canvas_serialize_items (BROWSER_CANVAS (diagram->priv->canvas));
-	str = g_strdup ("OOOOO");
+	str = browser_canvas_serialize_items (BROWSER_CANVAS (diagram->priv->canvas));
 
 	GError *lerror = NULL;
 	BrowserFavorites *bfav;
@@ -307,6 +306,9 @@ real_save_clicked_cb (GtkWidget *button, RelationsDiagram *diagram)
 		if (lerror)
 			g_error_free (lerror);
 	}
+
+	relations_diagram_set_fav_id (diagram, fav.id, NULL);
+
 	g_free (fav.name);
 	g_free (str);
 }
@@ -342,6 +344,19 @@ save_clicked_cb (GtkWidget *button, RelationsDiagram *diagram)
 		wid = gtk_entry_new ();
 		gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 5);
 		diagram->priv->name_entry = wid;
+		if (diagram->priv->fav_id > 0) {
+			BrowserFavoritesAttributes fav;
+			if (browser_favorites_get (browser_connection_get_favorites (diagram->priv->bcnc),
+						   diagram->priv->fav_id, &fav, NULL)) {
+				gtk_entry_set_text (GTK_ENTRY (wid), fav.name);
+				g_free (fav.name);
+				g_free (fav.descr);
+				g_free (fav.contents);
+			}
+		}
+
+		g_signal_connect (wid, "activate",
+				  G_CALLBACK (real_save_clicked_cb), diagram);
 
 		wid = gtk_button_new_with_label (_("Save"));
 		gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 0);
@@ -460,3 +475,124 @@ relations_diagram_new (BrowserConnection *bcnc)
 
 	return (GtkWidget*) diagram;
 }
+
+GtkWidget *
+relations_diagram_new_with_fav_id (BrowserConnection *bcnc, gint fav_id, GError **error)
+{
+	RelationsDiagram *diagram = NULL;
+	BrowserFavoritesAttributes fav;
+	xmlDocPtr doc = NULL;
+
+	if (! browser_favorites_get (browser_connection_get_favorites (bcnc),
+				     fav_id, &fav, error))
+		return FALSE;
+
+
+	doc = xmlParseDoc (BAD_CAST fav.contents);
+	if (!doc) {
+		g_set_error (error, 0, 0,
+			     _("Error parsing favorite's contents"));
+		goto out;
+	}
+
+	/* create diagram */
+	diagram = RELATIONS_DIAGRAM (relations_diagram_new (bcnc));
+	if (!diagram)
+		goto out;
+	gchar *str, *tmp;
+	tmp = g_markup_printf_escaped (_("'%s' diagram"), fav.name);
+	str = g_strdup_printf ("<b>%s</b>\n%s", _("Relations diagram"), tmp);
+	g_free (tmp);
+	cc_gray_bar_set_text (diagram->priv->header, str);
+	g_free (str);
+	diagram->priv->fav_id = fav_id;
+	relations_diagram_set_fav_id (diagram, fav_id, NULL);
+
+	/* fill the diagram */
+	xmlNodePtr root, node;
+	root = xmlDocGetRootElement (doc);
+	if (!root)
+		goto out;
+	for (node = root->children; node; node = node->next) {
+		if (!strcmp ((gchar*) node->name, "table")) {
+			xmlChar *schema;
+			xmlChar *name;
+			schema = xmlGetProp (node, BAD_CAST "schema");
+			name = xmlGetProp (node, BAD_CAST "name");
+			if (schema && name) {
+				BrowserCanvasTable *table;
+				GValue *v1, *v2;
+				g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), (gchar*) schema);
+				g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), (gchar*) name);
+				xmlFree (schema);
+				xmlFree (name);
+				table = browser_canvas_db_relations_add_table (BROWSER_CANVAS_DB_RELATIONS (diagram->priv->canvas),
+									       NULL, v1, v2);
+				gda_value_free (v1);
+				gda_value_free (v2);
+				if (table) {
+					xmlChar *x, *y;
+					x = xmlGetProp (node, BAD_CAST "x");
+					y = xmlGetProp (node, BAD_CAST "y");
+					browser_canvas_translate_item (BROWSER_CANVAS (diagram->priv->canvas),
+								       (BrowserCanvasItem*) table,
+								       x ? atof ((gchar*) x) : 0.,
+								       y ? atof ((gchar*) y) : 0.);
+					if (x)
+						xmlFree (x);
+					if (y)
+						xmlFree (y);
+				}
+			}
+			else {
+				if (schema)
+					xmlFree (schema);
+				if (name)
+					xmlFree (name);
+				g_set_error (error, 0, 0,
+					     _("Missing table attribute in favorite's contents"));
+				gtk_widget_destroy ((GtkWidget*) diagram);
+				diagram = NULL;
+				goto out;
+			}
+		}
+	}
+
+ out:
+	g_free (fav.name);
+	g_free (fav.descr);
+	g_free (fav.contents);
+	if (doc)
+		xmlFreeDoc (doc);
+	return (GtkWidget*) diagram;
+}
+
+/*
+ * relations_diagram_set_fav_id
+ *
+ * Sets the favorite ID of @diagram: ensure every displayed information is up to date
+ */
+static void
+relations_diagram_set_fav_id (RelationsDiagram *diagram, gint fav_id, GError **error)
+{
+	g_return_if_fail (IS_RELATIONS_DIAGRAM (diagram));
+	BrowserFavoritesAttributes fav;
+
+	if (! browser_favorites_get (browser_connection_get_favorites (diagram->priv->bcnc),
+								       fav_id, &fav, error))
+		return;
+
+	gchar *str, *tmp;
+	tmp = g_markup_printf_escaped (_("'%s' diagram"), fav.name);
+	str = g_strdup_printf ("<b>%s</b>\n%s", _("Relations diagram"), tmp);
+	g_free (tmp);
+	cc_gray_bar_set_text (diagram->priv->header, str);
+	g_free (str);
+
+	diagram->priv->fav_id = fav.id;
+
+ 	g_free (fav.name);
+	g_free (fav.descr);
+	g_free (fav.contents);
+}
+
diff --git a/tools/browser/schema-browser/relations-diagram.h b/tools/browser/schema-browser/relations-diagram.h
index d757805..29935b1 100644
--- a/tools/browser/schema-browser/relations-diagram.h
+++ b/tools/browser/schema-browser/relations-diagram.h
@@ -39,16 +39,17 @@ typedef struct _RelationsDiagramClass   RelationsDiagramClass;
 typedef struct _RelationsDiagramPrivate RelationsDiagramPrivate;
 
 struct _RelationsDiagram {
-	GtkVBox               parent;
-	RelationsDiagramPrivate     *priv;
+	GtkVBox                  parent;
+	RelationsDiagramPrivate *priv;
 };
 
 struct _RelationsDiagramClass {
-	GtkVBoxClass          parent_class;
+	GtkVBoxClass             parent_class;
 };
 
 GType                    relations_diagram_get_type (void) G_GNUC_CONST;
 GtkWidget               *relations_diagram_new (BrowserConnection *bcnc);
+GtkWidget               *relations_diagram_new_with_fav_id (BrowserConnection *bcnc, gint fav_id, GError **error);
 
 G_END_DECLS
 
diff --git a/tools/browser/schema-browser/schema-browser-perspective.c b/tools/browser/schema-browser/schema-browser-perspective.c
index 75c251c..5202eb2 100644
--- a/tools/browser/schema-browser/schema-browser-perspective.c
+++ b/tools/browser/schema-browser/schema-browser-perspective.c
@@ -106,7 +106,10 @@ schema_browser_perspective_init (SchemaBrowserPerspective *perspective)
 	perspective->priv = g_new0 (SchemaBrowserPerspectivePrivate, 1);
 }
 
-static void selection_changed_cb (GtkWidget *widget, const gchar *selection, SchemaBrowserPerspective *bpers);
+static void fav_selection_changed_cb (GtkWidget *widget, gint fav_id, BrowserFavoritesType fav_type,
+				      const gchar *selection, SchemaBrowserPerspective *bpers);
+static void objects_index_selection_changed_cb (GtkWidget *widget, BrowserFavoritesType fav_type,
+						const gchar *selection, SchemaBrowserPerspective *bpers);
 
 /**
  * schema_browser_perspective_new
@@ -131,7 +134,7 @@ schema_browser_perspective_new (BrowserWindow *bwin)
 	paned = gtk_hpaned_new ();
 	wid = favorite_selector_new (bcnc);
 	g_signal_connect (wid, "selection-changed",
-			  G_CALLBACK (selection_changed_cb), bpers);
+			  G_CALLBACK (fav_selection_changed_cb), bpers);
 	gtk_paned_add1 (GTK_PANED (paned), wid);
 
 	nb = gtk_notebook_new ();
@@ -142,7 +145,7 @@ schema_browser_perspective_new (BrowserWindow *bwin)
 
 	wid = objects_index_new (bcnc);
 	g_signal_connect (wid, "selection-changed",
-			  G_CALLBACK (selection_changed_cb), bpers);
+			  G_CALLBACK (objects_index_selection_changed_cb), bpers);
 	gtk_paned_add2 (GTK_PANED (paned), wid);
 	gtk_notebook_append_page (GTK_NOTEBOOK (nb), wid,
 				  browser_make_tab_label_with_stock (_("Index"), GTK_STOCK_ABOUT, FALSE,
@@ -166,52 +169,71 @@ close_button_clicked_cb (GtkWidget *wid, GtkWidget *page_widget)
 }
 
 static void
-selection_changed_cb (GtkWidget *widget, const gchar *selection, SchemaBrowserPerspective *bpers)
+objects_index_selection_changed_cb (GtkWidget *widget, BrowserFavoritesType fav_type,
+				    const gchar *selection, SchemaBrowserPerspective *bpers)
 {
-	GdaQuarkList *ql;
-	const gchar *type;
-	const gchar *schema = NULL, *table = NULL, *short_name = NULL;
-
-	ql = gda_quark_list_new_from_string (selection);
-	if (ql) {
-		type = gda_quark_list_find (ql, "OBJ_TYPE");
-		schema = gda_quark_list_find (ql, "OBJ_SCHEMA");
-		table = gda_quark_list_find (ql, "OBJ_NAME");
-		short_name = gda_quark_list_find (ql, "OBJ_SHORT_NAME");
-	}
+	fav_selection_changed_cb (widget, -1, fav_type, selection, bpers);
+}
 
-	if (!type || !schema || !table) {
-		if (ql)
-			gda_quark_list_free (ql);
-		return;
-	}
 
-	if (!strcmp (type, "table")) {
-		schema_browser_perspective_display_table_info (bpers, schema, table, short_name);
-	}
-	else {
-		gint ntabs, i;
-		ntabs = gtk_notebook_get_n_pages (GTK_NOTEBOOK (bpers->priv->notebook));
-		for (i = 0; i < ntabs; i++) {
-			GtkWidget *child;
-			child = gtk_notebook_get_nth_page (GTK_NOTEBOOK (bpers->priv->notebook), i);
-			if (IS_TABLE_INFO (child)) {
-				if (!strcmp (schema, table_info_get_table_schema (TABLE_INFO (child))) &&
-				    !strcmp (table, table_info_get_table_name (TABLE_INFO (child)))) {
-					gtk_notebook_set_current_page (GTK_NOTEBOOK (bpers->priv->notebook), i);
-					return;
+static void
+fav_selection_changed_cb (GtkWidget *widget, gint fav_id, BrowserFavoritesType fav_type,
+			  const gchar *selection, SchemaBrowserPerspective *bpers)
+{
+	if (fav_type == BROWSER_FAVORITES_TABLES) {
+		GdaQuarkList *ql;
+		const gchar *type;
+		const gchar *schema = NULL, *table = NULL, *short_name = NULL;
+
+		ql = gda_quark_list_new_from_string (selection);
+		if (ql) {
+			type = gda_quark_list_find (ql, "OBJ_TYPE");
+			schema = gda_quark_list_find (ql, "OBJ_SCHEMA");
+			table = gda_quark_list_find (ql, "OBJ_NAME");
+			short_name = gda_quark_list_find (ql, "OBJ_SHORT_NAME");
+		}
+		
+		if (!type || !schema || !table) {
+			if (ql)
+				gda_quark_list_free (ql);
+			return;
+		}
+
+		if (!strcmp (type, "table")) {
+			schema_browser_perspective_display_table_info (bpers, schema, table, short_name);
+		}
+		else {
+			gint ntabs, i;
+			ntabs = gtk_notebook_get_n_pages (GTK_NOTEBOOK (bpers->priv->notebook));
+			for (i = 0; i < ntabs; i++) {
+				GtkWidget *child;
+				child = gtk_notebook_get_nth_page (GTK_NOTEBOOK (bpers->priv->notebook), i);
+				if (IS_TABLE_INFO (child)) {
+					if (!strcmp (schema, table_info_get_table_schema (TABLE_INFO (child))) &&
+					    !strcmp (table, table_info_get_table_name (TABLE_INFO (child)))) {
+						gtk_notebook_set_current_page (GTK_NOTEBOOK (bpers->priv->notebook), i);
+						return;
+					}
 				}
 			}
-		}
 
-		g_warning ("Non handled favorite type %s", type);
-		TO_IMPLEMENT;
+			g_warning ("Non handled favorite type: %s", type);
+			TO_IMPLEMENT;
+		}
+	
+		if (ql)
+			gda_quark_list_free (ql);
 	}
-
-	if (ql)
-		gda_quark_list_free (ql);
-
-	g_print ("React to selection %s\n", selection);	
+	else if (fav_type == BROWSER_FAVORITES_DIAGRAMS) {
+#ifdef HAVE_GOOCANVAS
+		schema_browser_perspective_display_diagram (bpers, fav_id);
+#else
+		g_warning ("Can't display diagram because canvas not compiled.");
+#endif
+	}
+#ifdef GDA_DEBUG
+	g_print ("Reacted to selection fav_id=>%d type=>%u, contents=>%s\n", fav_id, fav_type, selection);	
+#endif
 }
 
 static void
@@ -236,32 +258,7 @@ schema_browser_perspective_dispose (GObject *object)
 static void
 action_create_diagram_cb (GtkAction *action, SchemaBrowserPerspective *bpers)
 {
-	GtkWidget *diagram;
-	diagram = relations_diagram_new (browser_window_get_connection (bpers->priv->bwin));
-	if (diagram) {
-		GtkWidget *close_btn;
-		GdkPixbuf *diagram_pixbuf;
-		gint i;
-		
-		diagram_pixbuf = browser_get_pixbuf_icon (BROWSER_ICON_DIAGRAM);
-		i = gtk_notebook_append_page (GTK_NOTEBOOK (bpers->priv->notebook), diagram,
-					      browser_make_tab_label_with_pixbuf (_("Diagram"),
-										  diagram_pixbuf,
-										  TRUE, &close_btn));
-		g_signal_connect (close_btn, "clicked",
-				  G_CALLBACK (close_button_clicked_cb), diagram);
-		
-		gtk_widget_show (diagram);
-		gtk_notebook_set_menu_label (GTK_NOTEBOOK (bpers->priv->notebook), diagram,
-					     browser_make_tab_label_with_pixbuf (_("Diagram"),
-										 diagram_pixbuf,
-										 FALSE, NULL));
-		gtk_notebook_set_current_page (GTK_NOTEBOOK (bpers->priv->notebook), i);
-		gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (bpers->priv->notebook), diagram,
-						  TRUE);
-		gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (bpers->priv->notebook), diagram,
-						 TRUE);
-	}
+	schema_browser_perspective_display_diagram (bpers, -1);
 }
 #endif
 
@@ -305,6 +302,70 @@ schema_browser_perspective_get_actions_ui (BrowserPerspective *bpers)
 	return ui_actions_info;
 }
 
+#ifdef HAVE_GOOCANVAS
+/**
+ * schema_browser_perspective_display_diagram
+ *
+ */
+void
+schema_browser_perspective_display_diagram (SchemaBrowserPerspective *bpers, gint fav_id)
+{
+	GtkWidget *diagram;
+
+	if (fav_id >= 0) {
+		gint ntabs, i;
+		
+		ntabs = gtk_notebook_get_n_pages (GTK_NOTEBOOK (bpers->priv->notebook));
+		for (i = 0; i < ntabs; i++) {
+			GtkWidget *child;
+			child = gtk_notebook_get_nth_page (GTK_NOTEBOOK (bpers->priv->notebook), i);
+			if (IS_RELATIONS_DIAGRAM (child)) {
+				gtk_notebook_set_current_page (GTK_NOTEBOOK (bpers->priv->notebook), i);
+				return;
+			}
+		}
+
+		GError *error = NULL;
+		diagram = relations_diagram_new_with_fav_id (browser_window_get_connection (bpers->priv->bwin),
+							     fav_id, &error);
+		if (! diagram) {
+			browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) bpers),
+					    error && error->message ? error->message :
+					    _("Could not load diagram"));
+			g_clear_error (&error);
+		}
+	}
+	else
+		diagram = relations_diagram_new (browser_window_get_connection (bpers->priv->bwin));
+
+	if (diagram) {
+		GtkWidget *close_btn;
+		GdkPixbuf *diagram_pixbuf;
+		gint i;
+		
+		diagram_pixbuf = browser_get_pixbuf_icon (BROWSER_ICON_DIAGRAM);
+		i = gtk_notebook_append_page (GTK_NOTEBOOK (bpers->priv->notebook), diagram,
+					      browser_make_tab_label_with_pixbuf (_("Diagram"),
+										  diagram_pixbuf,
+										  TRUE, &close_btn));
+		g_signal_connect (close_btn, "clicked",
+				  G_CALLBACK (close_button_clicked_cb), diagram);
+		
+		gtk_widget_show (diagram);
+		gtk_notebook_set_menu_label (GTK_NOTEBOOK (bpers->priv->notebook), diagram,
+					     browser_make_tab_label_with_pixbuf (_("Diagram"),
+										 diagram_pixbuf,
+										 FALSE, NULL));
+		gtk_notebook_set_current_page (GTK_NOTEBOOK (bpers->priv->notebook), i);
+		gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (bpers->priv->notebook), diagram,
+						  TRUE);
+		gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (bpers->priv->notebook), diagram,
+						 TRUE);
+	}
+}
+#endif
+
+
 /**
  * schema_browser_perspective_display_table_info
  *
diff --git a/tools/browser/schema-browser/schema-browser-perspective.h b/tools/browser/schema-browser/schema-browser-perspective.h
index f9ecff7..6e8d060 100644
--- a/tools/browser/schema-browser/schema-browser-perspective.h
+++ b/tools/browser/schema-browser/schema-browser-perspective.h
@@ -54,6 +54,8 @@ void                 schema_browser_perspective_display_table_info     (SchemaBr
 									const gchar *table_schema,
 									const gchar *table_name,
 									const gchar *table_short_name);
+void                 schema_browser_perspective_display_diagram        (SchemaBrowserPerspective *bpers,
+									gint fav_id);
 
 G_END_DECLS
 
diff --git a/tools/browser/support.c b/tools/browser/support.c
index 83dff6a..be0556c 100644
--- a/tools/browser/support.c
+++ b/tools/browser/support.c
@@ -113,6 +113,7 @@ browser_show_error (GtkWindow *parent, const gchar *format, ...)
         va_list args;
         gchar sz[2048];
         GtkWidget *dialog;
+	gchar *tmp;
 
         /* build the message string */
         va_start (args, format);
@@ -120,11 +121,12 @@ browser_show_error (GtkWindow *parent, const gchar *format, ...)
         va_end (args);
 
         /* create the error message dialog */
+	tmp = g_strdup_printf ("<span weight=\"bold\">%s</span>\n%s", _("Error:"), sz);
 	dialog = gtk_message_dialog_new_with_markup (parent,
                                                      GTK_DIALOG_DESTROY_WITH_PARENT |
                                                      GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
-                                                     GTK_BUTTONS_CLOSE, "<span weight=\"bold\">%s</span>\n%s",
-						     _("Error:"), sz);
+                                                     GTK_BUTTONS_CLOSE, tmp);
+	g_free (tmp);
 
         gtk_widget_show_all (dialog);
         gtk_dialog_run (GTK_DIALOG (dialog));



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