1 /*
2  * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2010 David King <davidk@openismus.com>
4  * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 
21 #include <glib/gi18n-lib.h>
22 #include <string.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <libgda/gda-tree.h>
26 #include "table-info.h"
27 #include "table-relations.h"
28 #include <libgda-ui/gdaui-tree-store.h>
29 #include "../support.h"
30 #include "../gdaui-bar.h"
31 #include "schema-browser-perspective.h"
32 #include "../canvas/browser-canvas-db-relations.h"
33 
34 struct _TableRelationsPrivate {
35 	BrowserConnection *bcnc;
36 	TableInfo *tinfo;
37 	GtkWidget *canvas;
38 	gboolean all_schemas;
39 };
40 
41 static void table_relations_class_init (TableRelationsClass *klass);
42 static void table_relations_init       (TableRelations *trels, TableRelationsClass *klass);
43 static void table_relations_dispose   (GObject *object);
44 
45 static void meta_changed_cb (BrowserConnection *bcnc, GdaMetaStruct *mstruct, TableRelations *trels);
46 
47 static GObjectClass *parent_class = NULL;
48 
49 
50 /*
51  * TableRelations class implementation
52  */
53 
54 static void
table_relations_class_init(TableRelationsClass * klass)55 table_relations_class_init (TableRelationsClass *klass)
56 {
57 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
58 
59 	parent_class = g_type_class_peek_parent (klass);
60 
61 	object_class->dispose = table_relations_dispose;
62 }
63 
64 
65 static void
table_relations_init(TableRelations * trels,G_GNUC_UNUSED TableRelationsClass * klass)66 table_relations_init (TableRelations *trels, G_GNUC_UNUSED TableRelationsClass *klass)
67 {
68 	trels->priv = g_new0 (TableRelationsPrivate, 1);
69 	trels->priv->all_schemas = FALSE;
70 
71 	gtk_orientable_set_orientation (GTK_ORIENTABLE (trels), GTK_ORIENTATION_VERTICAL);
72 }
73 
74 static void
table_relations_dispose(GObject * object)75 table_relations_dispose (GObject *object)
76 {
77 	TableRelations *trels = (TableRelations *) object;
78 
79 	/* free memory */
80 	if (trels->priv) {
81 		if (trels->priv->bcnc) {
82 			g_signal_handlers_disconnect_by_func (trels->priv->bcnc,
83 							      G_CALLBACK (meta_changed_cb), trels);
84 			g_object_unref (trels->priv->bcnc);
85 		}
86 		g_free (trels->priv);
87 		trels->priv = NULL;
88 	}
89 
90 	parent_class->dispose (object);
91 }
92 
93 GType
table_relations_get_type(void)94 table_relations_get_type (void)
95 {
96 	static GType type = 0;
97 
98 	if (G_UNLIKELY (type == 0)) {
99 		static const GTypeInfo relations = {
100 			sizeof (TableRelationsClass),
101 			(GBaseInitFunc) NULL,
102 			(GBaseFinalizeFunc) NULL,
103 			(GClassInitFunc) table_relations_class_init,
104 			NULL,
105 			NULL,
106 			sizeof (TableRelations),
107 			0,
108 			(GInstanceInitFunc) table_relations_init,
109 			0
110 		};
111 		type = g_type_register_static (GTK_TYPE_BOX, "TableRelations", &relations, 0);
112 	}
113 	return type;
114 }
115 
116 static void
meta_changed_cb(G_GNUC_UNUSED BrowserConnection * bcnc,GdaMetaStruct * mstruct,TableRelations * trels)117 meta_changed_cb (G_GNUC_UNUSED BrowserConnection *bcnc, GdaMetaStruct *mstruct, TableRelations *trels)
118 {
119 	GdaMetaDbObject *dbo;
120 	GValue *tname, *tschema;
121 	BrowserCanvasTable *ctable;
122 
123 	g_object_set (G_OBJECT (trels->priv->canvas), "meta-struct", mstruct, NULL);
124 
125 	g_value_set_string ((tschema = gda_value_new (G_TYPE_STRING)),
126 			    table_info_get_table_schema (trels->priv->tinfo));
127 	g_value_set_string ((tname = gda_value_new (G_TYPE_STRING)),
128 			    table_info_get_table_name (trels->priv->tinfo));
129         ctable = browser_canvas_db_relations_add_table (BROWSER_CANVAS_DB_RELATIONS (trels->priv->canvas), NULL,
130 							tschema, tname);
131 	browser_canvas_db_relations_select_table (BROWSER_CANVAS_DB_RELATIONS (trels->priv->canvas),
132 						  ctable);
133 
134 	dbo = gda_meta_struct_get_db_object (mstruct, NULL, tschema, tname);
135 
136 	if (dbo && (dbo->obj_type == GDA_META_DB_TABLE)) {
137 		GdaMetaTable *table;
138 		table = GDA_META_TABLE (dbo);
139 
140 		GSList *list;
141 		for (list = table->reverse_fk_list; list; list = list->next) {
142 			GdaMetaTableForeignKey *fkey = (GdaMetaTableForeignKey*) list->data;
143 			if (! trels->priv->all_schemas &&
144 			    ! strcmp (fkey->meta_table->obj_short_name, fkey->meta_table->obj_full_name))
145 				continue;
146 			g_value_set_string (tname, fkey->meta_table->obj_name);
147 			g_value_set_string (tschema, fkey->meta_table->obj_schema);
148 			browser_canvas_db_relations_add_table (BROWSER_CANVAS_DB_RELATIONS (trels->priv->canvas),
149 							       NULL,
150 							       tschema, tname);
151 		}
152 
153 		for (list = table->fk_list; list; list = list->next) {
154 			GdaMetaTableForeignKey *fkey = (GdaMetaTableForeignKey*) list->data;
155 
156 			if (! trels->priv->all_schemas &&
157 			    (fkey->depend_on->obj_type != GDA_META_DB_UNKNOWN) &&
158 			    ! strcmp (fkey->depend_on->obj_short_name, fkey->depend_on->obj_full_name))
159 				continue;
160 
161 			g_value_set_string (tname, fkey->depend_on->obj_name);
162 			g_value_set_string (tschema, fkey->depend_on->obj_schema);
163 			browser_canvas_db_relations_add_table (BROWSER_CANVAS_DB_RELATIONS (trels->priv->canvas),
164 							       NULL,
165 							       tschema, tname);
166 		}
167 	}
168 	gda_value_free (tschema);
169 	gda_value_free (tname);
170 
171 	browser_canvas_perform_auto_layout (BROWSER_CANVAS (trels->priv->canvas), TRUE,
172 					    BROWSER_CANVAS_LAYOUT_DEFAULT);
173 }
174 
175 /**
176  * table_relations_new
177  *
178  * Returns: a new #GtkWidget
179  */
180 GtkWidget *
table_relations_new(TableInfo * tinfo)181 table_relations_new (TableInfo *tinfo)
182 {
183 	TableRelations *trels;
184 
185 	g_return_val_if_fail (IS_TABLE_INFO (tinfo), NULL);
186 
187 	trels = TABLE_RELATIONS (g_object_new (TABLE_RELATIONS_TYPE, NULL));
188 
189 	trels->priv->tinfo = tinfo;
190 	trels->priv->bcnc = g_object_ref (table_info_get_connection (tinfo));
191 	g_signal_connect (trels->priv->bcnc, "meta-changed",
192 			  G_CALLBACK (meta_changed_cb), trels);
193 
194 	/*
195 	 * Relations
196 	 */
197 	trels->priv->canvas = browser_canvas_db_relations_new (NULL);
198 	gtk_box_pack_start (GTK_BOX (trels), trels->priv->canvas, TRUE, TRUE, 0);
199 	gtk_widget_show (GTK_WIDGET (trels));
200 
201 	/*
202 	 * initial update
203 	 */
204 	GdaMetaStruct *mstruct;
205 	mstruct = browser_connection_get_meta_struct (trels->priv->bcnc);
206 	if (mstruct)
207 		meta_changed_cb (trels->priv->bcnc, mstruct, trels);
208 
209 	return (GtkWidget*) trels;
210 }
211 
212