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 <gtk/gtk.h>
22 #include <math.h>
23 #include <libgda/libgda.h>
24 #include <glib/gi18n-lib.h>
25 #include "browser-canvas.h"
26 #include "browser-canvas-fkey.h"
27 #include "browser-canvas-table.h"
28 #include "browser-canvas-text.h"
29 #include "browser-canvas-utility.h"
30 #include "browser-canvas-db-relations.h"
31 #include "../../tool-utils.h"
32 #include "../support.h"
33 #include "../browser-window.h"
34 #include "../common/fk-declare.h"
35
36 static void browser_canvas_fkey_class_init (BrowserCanvasFkeyClass * class);
37 static void browser_canvas_fkey_init (BrowserCanvasFkey * cc);
38 static void browser_canvas_fkey_dispose (GObject *object);
39 static void browser_canvas_fkey_finalize (GObject *object);
40
41 static void browser_canvas_fkey_set_property (GObject *object,
42 guint param_id,
43 const GValue *value,
44 GParamSpec *pspec);
45 static void browser_canvas_fkey_get_property (GObject *object,
46 guint param_id,
47 GValue *value,
48 GParamSpec *pspec);
49
50 static void browser_canvas_fkey_get_edge_nodes (BrowserCanvasItem *citem,
51 BrowserCanvasItem **from, BrowserCanvasItem **to);
52
53 static void clean_items (BrowserCanvasFkey *cc);
54 static void create_items (BrowserCanvasFkey *cc);
55 static void update_items (BrowserCanvasFkey *cc);
56
57 enum
58 {
59 PROP_0,
60 PROP_META_STRUCT,
61 PROP_FK_CONSTRAINT
62 };
63
64 struct _BrowserCanvasFkeyPrivate
65 {
66 GdaMetaStruct *mstruct;
67 GdaMetaTableForeignKey *fk;
68 BrowserCanvasTable *fk_table_item;
69 BrowserCanvasTable *ref_pk_table_item;
70 GSList *shapes; /* list of BrowserCanvasCanvasShape structures */
71 };
72
73 /* get a pointer to the parents to be able to call their destructor */
74 static GObjectClass *parent_class = NULL;
75 static GooCanvasLineDash *dash = NULL, *no_dash = NULL;
76
77 GType
browser_canvas_fkey_get_type(void)78 browser_canvas_fkey_get_type (void)
79 {
80 static GType type = 0;
81
82 if (G_UNLIKELY (type == 0)) {
83 static const GTypeInfo info = {
84 sizeof (BrowserCanvasFkeyClass),
85 (GBaseInitFunc) NULL,
86 (GBaseFinalizeFunc) NULL,
87 (GClassInitFunc) browser_canvas_fkey_class_init,
88 NULL,
89 NULL,
90 sizeof (BrowserCanvasFkey),
91 0,
92 (GInstanceInitFunc) browser_canvas_fkey_init,
93 0
94 };
95
96 type = g_type_register_static (TYPE_BROWSER_CANVAS_ITEM, "BrowserCanvasFkey", &info, 0);
97 }
98
99 return type;
100 }
101
102 static void
browser_canvas_fkey_class_init(BrowserCanvasFkeyClass * class)103 browser_canvas_fkey_class_init (BrowserCanvasFkeyClass * class)
104 {
105 GObjectClass *object_class = G_OBJECT_CLASS (class);
106
107 parent_class = g_type_class_peek_parent (class);
108
109 BROWSER_CANVAS_ITEM_CLASS (class)->get_edge_nodes = browser_canvas_fkey_get_edge_nodes;
110
111 object_class->dispose = browser_canvas_fkey_dispose;
112 object_class->finalize = browser_canvas_fkey_finalize;
113
114 /* Properties */
115 object_class->set_property = browser_canvas_fkey_set_property;
116 object_class->get_property = browser_canvas_fkey_get_property;
117
118 g_object_class_install_property
119 (object_class, PROP_META_STRUCT,
120 g_param_spec_object ("meta-struct", NULL, NULL,
121 GDA_TYPE_META_STRUCT,
122 (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
123 g_object_class_install_property (object_class, PROP_FK_CONSTRAINT,
124 g_param_spec_pointer ("fk_constraint", "FK constraint",
125 NULL,
126 G_PARAM_WRITABLE));
127
128 dash = goo_canvas_line_dash_new (2, 5., 1.5);
129 no_dash = goo_canvas_line_dash_new (0);
130 }
131
132 static void
browser_canvas_fkey_init(BrowserCanvasFkey * cc)133 browser_canvas_fkey_init (BrowserCanvasFkey *cc)
134 {
135 cc->priv = g_new0 (BrowserCanvasFkeyPrivate, 1);
136 cc->priv->mstruct = NULL;
137 cc->priv->fk = NULL;
138 cc->priv->fk_table_item = NULL;
139 cc->priv->ref_pk_table_item = NULL;
140 cc->priv->shapes = NULL;
141 }
142
143 static void
fk_table_item_weak_ref_lost(BrowserCanvasFkey * cc,G_GNUC_UNUSED BrowserCanvasTable * old_table_item)144 fk_table_item_weak_ref_lost (BrowserCanvasFkey *cc, G_GNUC_UNUSED BrowserCanvasTable *old_table_item)
145 {
146 cc->priv->fk_table_item = NULL;
147 }
148
149 static void
ref_pk_table_item_weak_ref_lost(BrowserCanvasFkey * cc,G_GNUC_UNUSED BrowserCanvasTable * old_table_item)150 ref_pk_table_item_weak_ref_lost (BrowserCanvasFkey *cc, G_GNUC_UNUSED BrowserCanvasTable *old_table_item)
151 {
152 cc->priv->ref_pk_table_item = NULL;
153 }
154
155
156 static void
browser_canvas_fkey_dispose(GObject * object)157 browser_canvas_fkey_dispose (GObject *object)
158 {
159 BrowserCanvasFkey *cc;
160 g_return_if_fail (object != NULL);
161 g_return_if_fail (IS_BROWSER_CANVAS_FKEY (object));
162
163 cc = BROWSER_CANVAS_FKEY (object);
164
165 clean_items (cc);
166 if (cc->priv->mstruct) {
167 g_object_unref (cc->priv->mstruct);
168 cc->priv->mstruct = NULL;
169 }
170 cc->priv->fk = NULL;
171 if (cc->priv->fk_table_item) {
172 g_object_weak_unref (G_OBJECT (cc->priv->fk_table_item),
173 (GWeakNotify) fk_table_item_weak_ref_lost, cc);
174 cc->priv->fk_table_item = NULL;
175 }
176 if (cc->priv->ref_pk_table_item) {
177 g_object_weak_unref (G_OBJECT (cc->priv->ref_pk_table_item),
178 (GWeakNotify) ref_pk_table_item_weak_ref_lost, cc);
179 cc->priv->ref_pk_table_item = NULL;
180 }
181
182 /* for the parent class */
183 parent_class->dispose (object);
184 }
185
186
187 static void
browser_canvas_fkey_finalize(GObject * object)188 browser_canvas_fkey_finalize (GObject *object)
189 {
190 BrowserCanvasFkey *cc;
191 g_return_if_fail (object != NULL);
192 g_return_if_fail (IS_BROWSER_CANVAS_FKEY (object));
193
194 cc = BROWSER_CANVAS_FKEY (object);
195 if (cc->priv) {
196 g_slist_free (cc->priv->shapes);
197 g_free (cc->priv);
198 cc->priv = NULL;
199 }
200
201 /* for the parent class */
202 parent_class->finalize (object);
203 }
204
205 static void
browser_canvas_fkey_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)206 browser_canvas_fkey_set_property (GObject *object,
207 guint param_id,
208 const GValue *value,
209 GParamSpec *pspec)
210 {
211 BrowserCanvasFkey *cc;
212
213 cc = BROWSER_CANVAS_FKEY (object);
214
215 switch (param_id) {
216 case PROP_META_STRUCT:
217 cc->priv->mstruct = g_value_dup_object (value);
218 break;
219 case PROP_FK_CONSTRAINT:
220 if (cc->priv->fk != g_value_get_pointer (value)) {
221 cc->priv->fk = g_value_get_pointer (value);
222 clean_items (cc);
223 create_items (cc);
224 }
225 break;
226 default:
227 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
228 break;
229 }
230 }
231
232 static void
browser_canvas_fkey_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)233 browser_canvas_fkey_get_property (GObject *object,
234 guint param_id,
235 GValue *value,
236 GParamSpec *pspec)
237 {
238 BrowserCanvasFkey *cc;
239
240 cc = BROWSER_CANVAS_FKEY (object);
241
242 switch (param_id) {
243 case PROP_META_STRUCT:
244 g_value_set_object (value, cc->priv->mstruct);
245 break;
246 default:
247 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
248 break;
249 }
250 }
251
252 static void
browser_canvas_fkey_get_edge_nodes(BrowserCanvasItem * citem,BrowserCanvasItem ** from,BrowserCanvasItem ** to)253 browser_canvas_fkey_get_edge_nodes (BrowserCanvasItem *citem,
254 BrowserCanvasItem **from, BrowserCanvasItem **to)
255 {
256 BrowserCanvasFkey *cc;
257
258 cc = BROWSER_CANVAS_FKEY (citem);
259
260 if (from)
261 *from = (BrowserCanvasItem*) cc->priv->fk_table_item;
262 if (to)
263 *to = (BrowserCanvasItem*) cc->priv->ref_pk_table_item;
264 }
265
266 static gboolean single_item_enter_notify_event_cb (GooCanvasItem *ci, GooCanvasItem *target_item,
267 GdkEventCrossing *event, BrowserCanvasFkey *cc);
268 static gboolean single_item_leave_notify_event_cb (GooCanvasItem *ci, GooCanvasItem *target_item,
269 GdkEventCrossing *event, BrowserCanvasFkey *cc);
270 static gboolean single_item_button_press_event_cb (GooCanvasItem *ci, GooCanvasItem *target_item,
271 GdkEventButton *event, BrowserCanvasFkey *cc);
272 static void table_item_moved_cb (GooCanvasItem *table, BrowserCanvasFkey *cc);
273
274 /*
275 * destroy any existing GooCanvasItem objects
276 */
277 static void
clean_items(BrowserCanvasFkey * cc)278 clean_items (BrowserCanvasFkey *cc)
279 {
280 if (cc->priv->fk_table_item) {
281 g_signal_handlers_disconnect_by_func (G_OBJECT (cc->priv->fk_table_item),
282 G_CALLBACK (table_item_moved_cb), cc);
283 g_object_weak_unref (G_OBJECT (cc->priv->fk_table_item),
284 (GWeakNotify) fk_table_item_weak_ref_lost, cc);
285 cc->priv->fk_table_item = NULL;
286 }
287
288 if (cc->priv->ref_pk_table_item) {
289 g_signal_handlers_disconnect_by_func (G_OBJECT (cc->priv->ref_pk_table_item),
290 G_CALLBACK (table_item_moved_cb), cc);
291 g_object_weak_unref (G_OBJECT (cc->priv->ref_pk_table_item),
292 (GWeakNotify) ref_pk_table_item_weak_ref_lost, cc);
293 cc->priv->ref_pk_table_item = NULL;
294 }
295
296 /* remove all the GooCanvasItem objects */
297 browser_canvas_canvas_shapes_remove_all (cc->priv->shapes);
298 cc->priv->shapes = NULL;
299 }
300
301 /*
302 * create new GooCanvasItem objects
303 */
304 static void
create_items(BrowserCanvasFkey * cc)305 create_items (BrowserCanvasFkey *cc)
306 {
307 GSList *list, *canvas_shapes;
308 BrowserCanvasTable *table_item;
309 BrowserCanvas *canvas = g_object_get_data (G_OBJECT (goo_canvas_item_get_canvas (GOO_CANVAS_ITEM (cc))),
310 "browsercanvas");
311
312 g_assert (cc->priv->fk);
313
314 /* Analyse FK constraint */
315 table_item = browser_canvas_db_relations_get_table_item (BROWSER_CANVAS_DB_RELATIONS (canvas),
316 GDA_META_TABLE (cc->priv->fk->meta_table));
317 cc->priv->fk_table_item = table_item;
318 g_return_if_fail (table_item);
319 g_object_weak_ref (G_OBJECT (table_item), (GWeakNotify) fk_table_item_weak_ref_lost, cc);
320
321 g_signal_connect (G_OBJECT (table_item), "moving",
322 G_CALLBACK (table_item_moved_cb), cc);
323 g_signal_connect (G_OBJECT (table_item), "moved",
324 G_CALLBACK (table_item_moved_cb), cc);
325
326 table_item = browser_canvas_db_relations_get_table_item (BROWSER_CANVAS_DB_RELATIONS (canvas),
327 GDA_META_TABLE (cc->priv->fk->depend_on));
328 cc->priv->ref_pk_table_item = table_item;
329 g_return_if_fail (table_item);
330
331 g_object_weak_ref (G_OBJECT (table_item), (GWeakNotify) ref_pk_table_item_weak_ref_lost, cc);
332 g_signal_connect (G_OBJECT (table_item), "moving",
333 G_CALLBACK (table_item_moved_cb), cc);
334 g_signal_connect (G_OBJECT (table_item), "moved",
335 G_CALLBACK (table_item_moved_cb), cc);
336
337 /* actual line(s) */
338 g_assert (!cc->priv->shapes);
339 canvas_shapes = browser_canvas_util_compute_anchor_shapes (GOO_CANVAS_ITEM (cc), NULL,
340 cc->priv->fk_table_item,
341 cc->priv->ref_pk_table_item,
342 /*MAX (cc->priv->fk->cols_nb, 1)*/ 1,
343 0, TRUE);
344
345 cc->priv->shapes = browser_canvas_canvas_shapes_remove_obsolete_shapes (canvas_shapes);
346 for (list = canvas_shapes; list; list = list->next) {
347 GooCanvasItem *item = BROWSER_CANVAS_CANVAS_SHAPE (list->data)->item;
348 gchar *color = "black";
349 g_object_set (G_OBJECT (item),
350 "stroke-color", color,
351 "line-dash", GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED (cc->priv->fk) ? dash : no_dash,
352 NULL);
353
354 if (G_OBJECT_TYPE (item) == GOO_TYPE_CANVAS_POLYLINE) {
355 g_object_set (G_OBJECT (item),
356 "start-arrow", TRUE,
357 "arrow-tip-length", 4.,
358 "arrow-length", 5.,
359 "arrow-width", 4.,
360 NULL);
361 }
362 else if (G_OBJECT_TYPE (item) == GOO_TYPE_CANVAS_ELLIPSE)
363 g_object_set (G_OBJECT (item),
364 "fill-color", color,
365 NULL);
366
367 g_object_set_data (G_OBJECT (item), "fkcons", cc->priv->fk);
368 g_signal_connect (G_OBJECT (item), "enter-notify-event",
369 G_CALLBACK (single_item_enter_notify_event_cb), cc);
370 g_signal_connect (G_OBJECT (item), "leave-notify-event",
371 G_CALLBACK (single_item_leave_notify_event_cb), cc);
372 g_signal_connect (G_OBJECT (item), "button-press-event",
373 G_CALLBACK (single_item_button_press_event_cb), cc);
374
375 }
376 }
377
378 /*
379 * update GooCanvasItem objects
380 */
381 static void
update_items(BrowserCanvasFkey * cc)382 update_items (BrowserCanvasFkey *cc)
383 {
384 cc->priv->shapes = browser_canvas_util_compute_anchor_shapes (GOO_CANVAS_ITEM (cc), cc->priv->shapes,
385 cc->priv->fk_table_item,
386 cc->priv->ref_pk_table_item,
387 /*MAX (cc->priv->fk->cols_nb, 1)*/ 1,
388 0, TRUE);
389 cc->priv->shapes = browser_canvas_canvas_shapes_remove_obsolete_shapes (cc->priv->shapes);
390 }
391
392 /*
393 * item is for a single FK constraint
394 */
395 static gboolean
single_item_enter_notify_event_cb(GooCanvasItem * ci,G_GNUC_UNUSED GooCanvasItem * target_item,G_GNUC_UNUSED GdkEventCrossing * event,BrowserCanvasFkey * cc)396 single_item_enter_notify_event_cb (GooCanvasItem *ci, G_GNUC_UNUSED GooCanvasItem *target_item,
397 G_GNUC_UNUSED GdkEventCrossing *event, BrowserCanvasFkey *cc)
398 {
399 gint i;
400
401 for (i = 0; i < cc->priv->fk->cols_nb; i++) {
402 GdaMetaTableColumn *tcol;
403 BrowserCanvasColumn *column;
404
405 /* fk column */
406 tcol = g_slist_nth_data (GDA_META_TABLE (cc->priv->fk->meta_table)->columns,
407 cc->priv->fk->fk_cols_array[i] - 1);
408
409 column = browser_canvas_table_get_column_item (cc->priv->fk_table_item, tcol);
410 browser_canvas_text_set_highlight (BROWSER_CANVAS_TEXT (column), TRUE);
411
412 /* ref pk column */
413 tcol = g_slist_nth_data (GDA_META_TABLE (cc->priv->fk->depend_on)->columns,
414 cc->priv->fk->ref_pk_cols_array[i] - 1);
415
416 column = browser_canvas_table_get_column_item (cc->priv->ref_pk_table_item, tcol);
417 browser_canvas_text_set_highlight (BROWSER_CANVAS_TEXT (column), TRUE);
418
419 gchar *str;
420 str = g_strdup_printf ("%s '%s'\n%s: %s\n%s: %s",
421 GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED (cc->priv->fk) ?
422 _("Declared foreign key") : _("Foreign key"),
423 cc->priv->fk->fk_name,
424 _("Policy on UPDATE"),
425 gda_tools_utils_fk_policy_to_string (GDA_META_TABLE_FOREIGN_KEY_ON_UPDATE_POLICY (cc->priv->fk)),
426 _("Policy on DELETE"),
427 gda_tools_utils_fk_policy_to_string (GDA_META_TABLE_FOREIGN_KEY_ON_DELETE_POLICY (cc->priv->fk)));
428 gtk_widget_set_tooltip_text (GTK_WIDGET (goo_canvas_item_get_canvas (GOO_CANVAS_ITEM (ci))),
429 str);
430 g_free (str);
431 }
432
433 return FALSE;
434 }
435
436 static gboolean
single_item_leave_notify_event_cb(G_GNUC_UNUSED GooCanvasItem * ci,G_GNUC_UNUSED GooCanvasItem * target_item,G_GNUC_UNUSED GdkEventCrossing * event,BrowserCanvasFkey * cc)437 single_item_leave_notify_event_cb (G_GNUC_UNUSED GooCanvasItem *ci, G_GNUC_UNUSED GooCanvasItem *target_item,
438 G_GNUC_UNUSED GdkEventCrossing *event, BrowserCanvasFkey *cc)
439 {
440 gint i;
441
442 for (i = 0; i < cc->priv->fk->cols_nb; i++) {
443 GdaMetaTableColumn *tcol;
444 BrowserCanvasColumn *column;
445
446 /* fk column */
447 tcol = g_slist_nth_data (GDA_META_TABLE (cc->priv->fk->meta_table)->columns,
448 cc->priv->fk->fk_cols_array[i] - 1);
449
450 column = browser_canvas_table_get_column_item (cc->priv->fk_table_item, tcol);
451 browser_canvas_text_set_highlight (BROWSER_CANVAS_TEXT (column), FALSE);
452
453 /* ref pk column */
454 tcol = g_slist_nth_data (GDA_META_TABLE (cc->priv->fk->depend_on)->columns,
455 cc->priv->fk->ref_pk_cols_array[i] - 1);
456
457 column = browser_canvas_table_get_column_item (cc->priv->ref_pk_table_item, tcol);
458 browser_canvas_text_set_highlight (BROWSER_CANVAS_TEXT (column), FALSE);
459 }
460
461 return FALSE;
462 }
463
464 static void
delete_declared_fk_cb(G_GNUC_UNUSED GtkMenuItem * mitem,BrowserCanvasFkey * cc)465 delete_declared_fk_cb (G_GNUC_UNUSED GtkMenuItem *mitem, BrowserCanvasFkey *cc)
466 {
467 GError *error = NULL;
468 GtkWidget *parent;
469 parent = (GtkWidget*) gtk_widget_get_toplevel ((GtkWidget*) goo_canvas_item_get_canvas (GOO_CANVAS_ITEM (cc)));
470 if (! fk_declare_undeclare (cc->priv->mstruct,
471 BROWSER_IS_WINDOW (parent) ? BROWSER_WINDOW (parent) : NULL,
472 cc->priv->fk, &error)) {
473 browser_show_error ((GtkWindow *) parent, _("Failed to undeclare foreign key: %s"),
474 error && error->message ? error->message : _("No detail"));
475 g_clear_error (&error);
476 }
477 else if (BROWSER_IS_WINDOW (parent))
478 browser_window_show_notice (BROWSER_WINDOW (parent),
479 GTK_MESSAGE_INFO, "fkdeclare",
480 _("Successfully undeclared foreign key"));
481 else
482 browser_show_message ((GtkWindow *) parent, "%s",
483 _("Successfully undeclared foreign key"));
484 }
485
486 static gboolean
single_item_button_press_event_cb(G_GNUC_UNUSED GooCanvasItem * ci,G_GNUC_UNUSED GooCanvasItem * target_item,G_GNUC_UNUSED GdkEventButton * event,BrowserCanvasFkey * cc)487 single_item_button_press_event_cb (G_GNUC_UNUSED GooCanvasItem *ci, G_GNUC_UNUSED GooCanvasItem *target_item,
488 G_GNUC_UNUSED GdkEventButton *event, BrowserCanvasFkey *cc)
489 {
490 GdaMetaTableForeignKey *fk = g_object_get_data (G_OBJECT (ci), "fkcons");
491 if (GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED (fk)) {
492 GtkWidget *menu, *entry;
493
494 menu = gtk_menu_new ();
495 entry = gtk_menu_item_new_with_label (_("Remove this declared foreign key"));
496 g_object_set_data (G_OBJECT (entry), "fkcons", fk);
497 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (delete_declared_fk_cb), cc);
498 gtk_menu_shell_append (GTK_MENU_SHELL (menu), entry);
499 gtk_widget_show (entry);
500 gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
501 NULL, NULL, ((GdkEventButton *)event)->button,
502 ((GdkEventButton *)event)->time);
503 return TRUE;
504 }
505 else
506 return FALSE;
507 }
508
509 static void
table_item_moved_cb(G_GNUC_UNUSED GooCanvasItem * table,BrowserCanvasFkey * cc)510 table_item_moved_cb (G_GNUC_UNUSED GooCanvasItem *table, BrowserCanvasFkey *cc)
511 {
512 update_items (cc);
513 }
514
515 /**
516 * browser_canvas_fkey_new
517 * @parent: the parent item, or NULL.
518 * @fkcons: the #GdaMetaTableForeignKey to represent
519 * @...: optional pairs of property names and values, and a terminating NULL.
520 *
521 * Creates a new canvas item to represent the @fkcons FK constraint
522 *
523 * Returns: a new #GooCanvasItem object
524 */
525 GooCanvasItem *
browser_canvas_fkey_new(GooCanvasItem * parent,GdaMetaStruct * mstruct,GdaMetaTableForeignKey * fkcons,...)526 browser_canvas_fkey_new (GooCanvasItem *parent, GdaMetaStruct *mstruct, GdaMetaTableForeignKey *fkcons, ...)
527 {
528 GooCanvasItem *item;
529 const char *first_property;
530 va_list var_args;
531
532 g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
533
534 item = g_object_new (TYPE_BROWSER_CANVAS_FKEY, "meta-struct", mstruct, NULL);
535
536 if (parent) {
537 goo_canvas_item_add_child (parent, item, -1);
538 g_object_unref (item);
539 }
540
541 g_object_set (item, "fk_constraint", fkcons, NULL);
542
543 va_start (var_args, fkcons);
544 first_property = va_arg (var_args, char*);
545 if (first_property)
546 g_object_set_valist ((GObject*) item, first_property, var_args);
547 va_end (var_args);
548
549 return item;
550 }
551