1 /*
2 * Copyright (C) 2011 - 2012 Vivien Malerba <malerba@gnome-db.org>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <glib/gi18n-lib.h>
20 #include <string.h>
21 #include <sql-parser/gda-sql-parser.h>
22 #include "fk-declare.h"
23 #include "../support.h"
24 #include "../../tool-utils.h"
25
26 /*
27 * Main static functions
28 */
29 static void fk_declare_class_init (FkDeclareClass * class);
30 static void fk_declare_init (FkDeclare *declare);
31 static void fk_declare_dispose (GObject *object);
32
33 enum {
34 MODEL_COLUMNS_COLUMN_PIXBUF,
35 MODEL_COLUMNS_COLUMN_STRING,
36 MODEL_COLUMNS_COLUMN_META_COLUMN,
37 MODEL_COLUMNS_COLUMN_LAST
38 };
39
40 enum {
41 MODEL_TABLES_COLUMN_PIXBUF,
42 MODEL_TABLES_COLUMN_STRING,
43 MODEL_TABLES_COLUMN_META_TABLE,
44 MODEL_TABLES_COLUMN_LAST
45 };
46 static GtkTreeModel *create_tables_model (GdaMetaStruct *mstruct);
47 static void update_reference_column_choices (FkDeclare *dec);
48 static void update_dialog_response_sensitiveness (FkDeclare *dec);
49
50 /* get a pointer to the parents to be able to call their destructor */
51 static GObjectClass *parent_class = NULL;
52
53 typedef struct {
54 GtkWidget *checkbox; /* column name chackbox */
55 GtkComboBox *cbox; /* referenced column combo box */
56 GdaMetaTableColumn *column;
57 } Assoc;
58
59 struct _FkDeclarePrivate
60 {
61 GdaMetaStruct *mstruct;
62 GdaMetaTable *mtable;
63 GtkWidget *fk_name;
64 GtkComboBox *ref_table_cbox;
65 gint n_cols; /* length (@mtable->columns) */
66 Assoc *associations; /* size is @n_cols */
67
68 gboolean dialog_sensitive;
69 };
70
71 GType
fk_declare_get_type(void)72 fk_declare_get_type (void)
73 {
74 static GType type = 0;
75
76 if (G_UNLIKELY (type == 0)) {
77 static GMutex registering;
78 static const GTypeInfo info = {
79 sizeof (FkDeclareClass),
80 (GBaseInitFunc) NULL,
81 (GBaseFinalizeFunc) NULL,
82 (GClassInitFunc) fk_declare_class_init,
83 NULL,
84 NULL,
85 sizeof (FkDeclare),
86 0,
87 (GInstanceInitFunc) fk_declare_init,
88 0
89 };
90
91 g_mutex_lock (®istering);
92 if (type == 0)
93 type = g_type_register_static (GTK_TYPE_DIALOG, "FkDeclare", &info, 0);
94 g_mutex_unlock (®istering);
95 }
96
97 return type;
98 }
99
100
101 static void
fk_declare_class_init(FkDeclareClass * class)102 fk_declare_class_init (FkDeclareClass *class)
103 {
104 GObjectClass *object_class = G_OBJECT_CLASS (class);
105
106 parent_class = g_type_class_peek_parent (class);
107
108 /* virtual functions */
109 object_class->dispose = fk_declare_dispose;
110 }
111
112 #ifdef HAVE_GDU
113 static void
help_clicked_cb(GtkButton * button,G_GNUC_UNUSED FkDeclare * declare)114 help_clicked_cb (GtkButton *button, G_GNUC_UNUSED FkDeclare *declare)
115 {
116 browser_show_help ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) button),
117 "declared-fk");
118 g_signal_stop_emission_by_name (button, "clicked");
119 }
120 #endif
121
122 static void
fk_declare_init(FkDeclare * declare)123 fk_declare_init (FkDeclare *declare)
124 {
125 declare->priv = g_new0 (FkDeclarePrivate, 1);
126 declare->priv->dialog_sensitive = FALSE;
127
128 gtk_dialog_add_buttons (GTK_DIALOG (declare),
129 GTK_STOCK_ADD,
130 GTK_RESPONSE_ACCEPT,
131 GTK_STOCK_CANCEL,
132 GTK_RESPONSE_REJECT,
133 NULL);
134 #ifdef HAVE_GDU
135 GtkWidget *help_btn;
136 help_btn = gtk_button_new_from_stock (GTK_STOCK_HELP);
137 g_signal_connect (help_btn, "clicked",
138 G_CALLBACK (help_clicked_cb), declare);
139 gtk_widget_show (help_btn);
140 gtk_dialog_add_action_widget (GTK_DIALOG (declare), help_btn, GTK_RESPONSE_HELP);
141 #endif
142
143 gtk_dialog_set_response_sensitive (GTK_DIALOG (declare), GTK_RESPONSE_ACCEPT, FALSE);
144 }
145
146 static void
fk_declare_dispose(GObject * object)147 fk_declare_dispose (GObject *object)
148 {
149 FkDeclare *declare;
150 declare = FK_DECLARE (object);
151 if (declare->priv) {
152 g_free (declare->priv->associations);
153 if (declare->priv->mstruct)
154 g_object_unref (declare->priv->mstruct);
155
156 g_free (declare->priv);
157 declare->priv = NULL;
158 }
159
160 /* parent class */
161 parent_class->dispose (object);
162 }
163
164 static void is_node_sensitive (GtkCellLayout *cell_layout, GtkCellRenderer *cell, GtkTreeModel *tree_model,
165 GtkTreeIter *iter, gpointer data);
166 static void fk_name_changed_cb (GtkWidget *entry, FkDeclare *decl);
167 static void table_selection_changed_cb (GtkComboBox *cbox, FkDeclare *decl);
168 static void column_toggled_cb (GtkToggleButton *toggle, FkDeclare *decl);
169 static void column_selection_changed_cb (GtkComboBox *cbox, FkDeclare *decl);
170
171 static void
create_internal_layout(FkDeclare * decl)172 create_internal_layout (FkDeclare *decl)
173 {
174 GtkWidget *label, *grid, *cbox, *entry;
175 char *markup, *str;
176 GtkWidget *dcontents;
177 gint i;
178 GSList *list;
179
180 dcontents = gtk_dialog_get_content_area (GTK_DIALOG (decl));
181 gtk_box_set_spacing (GTK_BOX (dcontents), 5);
182
183 /* label */
184 label = gtk_label_new ("");
185 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
186 str = g_strdup_printf (_("Declare a foreign key for table '%s'"),
187 GDA_META_DB_OBJECT (decl->priv->mtable)->obj_short_name);
188 markup = g_markup_printf_escaped ("<big><b>%s:</b></big>\n%s", str,
189 _("define which table is references, which columns are "
190 "part of the foreign key, "
191 "and which column each one references"));
192 g_free (str);
193
194 gtk_label_set_markup (GTK_LABEL (label), markup);
195 g_free (markup);
196 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
197 gtk_box_pack_start (GTK_BOX (dcontents), label, FALSE, FALSE, 0);
198 gtk_widget_show_all (label);
199
200 /* GtkTable to hold contents */
201 grid = gtk_grid_new ();
202 gtk_box_pack_start (GTK_BOX (dcontents), grid, TRUE, TRUE, 0);
203 gtk_grid_set_column_spacing (GTK_GRID (grid), 5);
204 gtk_grid_set_row_spacing (GTK_GRID (grid), 5);
205
206 /* FK name */
207 gfloat yalign;
208 label = gtk_label_new (_("Foreign key name:"));
209 gtk_misc_get_alignment (GTK_MISC (label), NULL, &yalign);
210 gtk_misc_set_alignment (GTK_MISC (label), 0., yalign);
211 gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
212 entry = gtk_entry_new ();
213 decl->priv->fk_name = entry;
214 gtk_grid_attach (GTK_GRID (grid), entry, 1, 0, 1, 1);
215 g_signal_connect (entry, "changed",
216 G_CALLBACK (fk_name_changed_cb), decl);
217
218 /* table to reference */
219 label = gtk_label_new (_("Referenced table:"));
220 gtk_misc_get_alignment (GTK_MISC (label), NULL, &yalign);
221 gtk_misc_set_alignment (GTK_MISC (label), 0., yalign);
222 gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
223
224 GtkTreeModel *model;
225 GtkCellRenderer *renderer;
226 model = create_tables_model (decl->priv->mstruct);
227 cbox = gtk_combo_box_new_with_model (model);
228 decl->priv->ref_table_cbox = GTK_COMBO_BOX (cbox);
229 g_signal_connect (cbox, "changed",
230 G_CALLBACK (table_selection_changed_cb), decl);
231 g_object_unref (G_OBJECT (model));
232 renderer = gtk_cell_renderer_pixbuf_new ();
233 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), renderer, FALSE);
234 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), renderer,
235 "pixbuf", MODEL_TABLES_COLUMN_PIXBUF,
236 NULL);
237 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cbox),
238 renderer,
239 is_node_sensitive,
240 NULL, NULL);
241
242 renderer = gtk_cell_renderer_text_new ();
243 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), renderer, TRUE);
244 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), renderer,
245 "text", MODEL_TABLES_COLUMN_STRING,
246 NULL);
247 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cbox),
248 renderer,
249 is_node_sensitive,
250 NULL, NULL);
251 gtk_grid_attach (GTK_GRID (grid), cbox, 1, 1, 1, 1);
252
253 /* more labels */
254 label = gtk_label_new ("");
255 markup = g_strdup_printf ("<b>%s:</b>", _("Columns"));
256 gtk_label_set_markup (GTK_LABEL (label), markup);
257 g_free (markup);
258 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
259 gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
260
261 label = gtk_label_new ("");
262 markup = g_strdup_printf ("<b>%s:</b>", _("Referenced column"));
263 gtk_label_set_markup (GTK_LABEL (label), markup);
264 g_free (markup);
265 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
266 gtk_grid_attach (GTK_GRID (grid), label, 1, 2, 1, 1);
267
268 /* columns */
269 decl->priv->n_cols = g_slist_length (decl->priv->mtable->columns);
270 decl->priv->associations = g_new0 (Assoc, decl->priv->n_cols);
271 for (i = 3, list = decl->priv->mtable->columns; list; i++, list = list->next) {
272 GtkCellRenderer *renderer;
273 GdaMetaTableColumn *column = (GdaMetaTableColumn*) list->data;
274 Assoc *assoc = &(decl->priv->associations [i-3]);
275 assoc->column = column;
276
277 label = gtk_check_button_new_with_label (column->column_name);
278 gtk_grid_attach (GTK_GRID (grid), label, 0, i, 1, 1);
279 assoc->checkbox = label;
280 g_signal_connect (label, "toggled",
281 G_CALLBACK (column_toggled_cb), decl);
282
283 cbox = gtk_combo_box_new ();
284 g_object_set_data (G_OBJECT (label), "cbox", cbox);
285 renderer = gtk_cell_renderer_pixbuf_new ();
286 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), renderer, FALSE);
287 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), renderer,
288 "pixbuf", MODEL_COLUMNS_COLUMN_PIXBUF,
289 NULL);
290 renderer = gtk_cell_renderer_text_new ();
291 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), renderer, TRUE);
292 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), renderer,
293 "text", MODEL_COLUMNS_COLUMN_STRING,
294 NULL);
295 gtk_grid_attach (GTK_GRID (grid), cbox, 1, i, 1, 1);
296 assoc->cbox = GTK_COMBO_BOX (cbox);
297 g_signal_connect (cbox, "changed",
298 G_CALLBACK (column_selection_changed_cb), decl);
299 gtk_widget_set_sensitive (cbox, FALSE);
300 }
301 gtk_widget_show_all (grid);
302 }
303
304 static void
is_node_sensitive(G_GNUC_UNUSED GtkCellLayout * cell_layout,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,G_GNUC_UNUSED gpointer data)305 is_node_sensitive (G_GNUC_UNUSED GtkCellLayout *cell_layout,
306 GtkCellRenderer *cell, GtkTreeModel *tree_model,
307 GtkTreeIter *iter, G_GNUC_UNUSED gpointer data)
308 {
309 gboolean sensitive;
310 sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
311 g_object_set (cell, "sensitive", sensitive, NULL);
312 }
313
314 static void
fk_name_changed_cb(G_GNUC_UNUSED GtkWidget * entry,FkDeclare * decl)315 fk_name_changed_cb (G_GNUC_UNUSED GtkWidget *entry, FkDeclare *decl)
316 {
317 update_dialog_response_sensitiveness (decl);
318 }
319
320 static void
table_selection_changed_cb(G_GNUC_UNUSED GtkComboBox * cbox,FkDeclare * decl)321 table_selection_changed_cb (G_GNUC_UNUSED GtkComboBox *cbox, FkDeclare *decl)
322 {
323 update_reference_column_choices (decl);
324 update_dialog_response_sensitiveness (decl);
325 }
326
327 static void
column_toggled_cb(GtkToggleButton * toggle,FkDeclare * decl)328 column_toggled_cb (GtkToggleButton *toggle, FkDeclare *decl)
329 {
330 GtkWidget *cbox;
331 cbox = g_object_get_data (G_OBJECT (toggle), "cbox");
332 gtk_widget_set_sensitive (cbox, gtk_toggle_button_get_active (toggle));
333 update_dialog_response_sensitiveness (decl);
334 }
335
336 static void
column_selection_changed_cb(G_GNUC_UNUSED GtkComboBox * cbox,FkDeclare * decl)337 column_selection_changed_cb (G_GNUC_UNUSED GtkComboBox *cbox, FkDeclare *decl)
338 {
339 update_dialog_response_sensitiveness (decl);
340 }
341
342 static void
update_reference_column_choices(FkDeclare * decl)343 update_reference_column_choices (FkDeclare *decl)
344 {
345 gint i;
346 GtkTreeIter iter;
347 GdaMetaTable *mtable = NULL;
348
349 if (gtk_combo_box_get_active_iter (decl->priv->ref_table_cbox, &iter))
350 gtk_tree_model_get (gtk_combo_box_get_model (decl->priv->ref_table_cbox), &iter,
351 MODEL_TABLES_COLUMN_META_TABLE, &mtable, -1);
352
353 for (i = 0; i < decl->priv->n_cols; i++) {
354 Assoc *assoc = &(decl->priv->associations [i]);
355 GtkListStore *lstore;
356 lstore = (GtkListStore*) gtk_combo_box_get_model (assoc->cbox);
357 if (! lstore) {
358 lstore = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
359 gtk_combo_box_set_model (assoc->cbox, GTK_TREE_MODEL (lstore));
360 g_object_unref (lstore);
361 }
362 else
363 gtk_list_store_clear (lstore);
364
365 if (!mtable)
366 continue;
367
368 /* add columns */
369 GSList *list;
370 for (list = mtable->columns; list; list = list->next) {
371 GdaMetaTableColumn *col = (GdaMetaTableColumn*) list->data;
372 GdkPixbuf *pix;
373 gtk_list_store_append (lstore, &iter);
374 pix = browser_get_pixbuf_icon (BROWSER_ICON_COLUMN);
375 gtk_list_store_set (lstore, &iter,
376 MODEL_COLUMNS_COLUMN_PIXBUF, pix,
377 MODEL_COLUMNS_COLUMN_STRING, col->column_name,
378 MODEL_COLUMNS_COLUMN_META_COLUMN, col, -1);
379 }
380 }
381 }
382
383 /**
384 * fk_declare_new
385 */
386 GtkWidget *
fk_declare_new(GtkWindow * parent,GdaMetaStruct * mstruct,GdaMetaTable * table)387 fk_declare_new (GtkWindow *parent, GdaMetaStruct *mstruct, GdaMetaTable *table)
388 {
389 GtkWidget *wid;
390 FkDeclare *decl;
391 gchar *str;
392
393 g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
394 g_return_val_if_fail (table, NULL);
395 g_return_val_if_fail (GDA_META_DB_OBJECT (table)->obj_type == GDA_META_DB_TABLE, NULL);
396 g_return_val_if_fail (table->columns, NULL);
397
398 str = g_strdup_printf (_("Declare a foreign key for table '%s'"),
399 GDA_META_DB_OBJECT (table)->obj_short_name);
400 wid = (GtkWidget*) g_object_new (FK_DECLARE_TYPE, "title", str,
401 "transient-for", parent,
402 "border-width", 10, NULL);
403 g_free (str);
404
405 decl = FK_DECLARE (wid);
406 decl->priv->mstruct = g_object_ref ((GObject*) mstruct);
407 decl->priv->mtable = table;
408
409 create_internal_layout (decl);
410
411 return wid;
412 }
413
414 static gint
dbo_sort_func(GdaMetaDbObject * dbo1,GdaMetaDbObject * dbo2)415 dbo_sort_func (GdaMetaDbObject *dbo1, GdaMetaDbObject *dbo2)
416 {
417 const gchar *n1, *n2;
418 g_assert (dbo1);
419 g_assert (dbo2);
420 if (dbo1->obj_name[0] == '"')
421 n1 = dbo1->obj_name + 1;
422 else
423 n1 = dbo1->obj_name;
424 if (dbo2->obj_name[0] == '"')
425 n2 = dbo2->obj_name + 1;
426 else
427 n2 = dbo2->obj_name;
428 return strcmp (n2, n1);
429 }
430
431 static GtkTreeModel *
create_tables_model(GdaMetaStruct * mstruct)432 create_tables_model (GdaMetaStruct *mstruct)
433 {
434 GtkTreeStore *tstore;
435 GSList *all_dbo, *list;
436 GHashTable *schemas = NULL; /* key = schema name, value = a #GtkTreeRowReference as parent */
437
438 tstore = gtk_tree_store_new (MODEL_TABLES_COLUMN_LAST, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
439 schemas = g_hash_table_new_full (g_str_hash, g_str_equal,
440 NULL, (GDestroyNotify) gtk_tree_row_reference_free);
441 all_dbo = gda_meta_struct_get_all_db_objects (mstruct);
442 all_dbo = g_slist_sort (all_dbo, (GCompareFunc) dbo_sort_func);
443 for (list = all_dbo; list; list = list->next) {
444 GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (list->data);
445 GtkTreeIter iter;
446 GdkPixbuf *pix;
447 if (dbo->obj_type != GDA_META_DB_TABLE)
448 continue;
449
450 if (strcmp (dbo->obj_short_name, dbo->obj_full_name)) {
451 gtk_tree_store_prepend (tstore, &iter, NULL);
452 pix = browser_get_pixbuf_icon (BROWSER_ICON_TABLE);
453 gtk_tree_store_set (tstore, &iter,
454 MODEL_TABLES_COLUMN_PIXBUF, pix,
455 MODEL_TABLES_COLUMN_STRING, dbo->obj_short_name,
456 MODEL_TABLES_COLUMN_META_TABLE, GDA_META_TABLE (dbo), -1);
457 }
458
459 GtkTreePath *path;
460 GtkTreeRowReference *rref;
461 GtkTreeIter parent;
462 rref = g_hash_table_lookup (schemas, dbo->obj_schema);
463 if (!rref) {
464 GtkTreeIter iter;
465 GtkTreePath *path;
466 GdkPixbuf *pix;
467 gtk_tree_store_append (tstore, &iter, NULL);
468 pix = browser_get_pixbuf_icon (BROWSER_ICON_SCHEMA);
469 gtk_tree_store_set (tstore, &iter,
470 MODEL_TABLES_COLUMN_PIXBUF, pix,
471 MODEL_TABLES_COLUMN_STRING, dbo->obj_schema,
472 MODEL_TABLES_COLUMN_META_TABLE, NULL, -1);
473 path = gtk_tree_model_get_path ((GtkTreeModel*) tstore, &iter);
474 rref = gtk_tree_row_reference_new ((GtkTreeModel*) tstore, path);
475 gtk_tree_path_free (path);
476 g_hash_table_insert (schemas, dbo->obj_schema, rref);
477 }
478
479 path = gtk_tree_row_reference_get_path (rref);
480 g_assert (gtk_tree_model_get_iter ((GtkTreeModel*) tstore, &parent, path));
481 gtk_tree_path_free (path);
482 gtk_tree_store_prepend (tstore, &iter, &parent);
483 pix = browser_get_pixbuf_icon (BROWSER_ICON_TABLE);
484 gtk_tree_store_set (tstore, &iter,
485 MODEL_TABLES_COLUMN_PIXBUF, pix,
486 MODEL_TABLES_COLUMN_STRING, dbo->obj_short_name,
487 MODEL_TABLES_COLUMN_META_TABLE, GDA_META_TABLE (dbo), -1);
488 }
489 g_slist_free (all_dbo);
490 g_hash_table_destroy (schemas);
491
492 return GTK_TREE_MODEL (tstore);
493 }
494
495 /*
496 * Sets the dialog's sensitiveness for the GTK_RESPONSE_ACCEPT response
497 *
498 * It is sensitive if:
499 * - the FK is named
500 * - a reference table is selected
501 * - at least one column is checked
502 * - for each checked column, there is a selected reference column
503 */
504 static void
update_dialog_response_sensitiveness(FkDeclare * decl)505 update_dialog_response_sensitiveness (FkDeclare *decl)
506 {
507 gboolean sensitive = FALSE;
508 gint i;
509 gboolean onechecked = FALSE;
510 const gchar *fkname;
511
512 fkname = gtk_entry_get_text (GTK_ENTRY (decl->priv->fk_name));
513 if (!fkname || !*fkname)
514 goto out;
515
516 if (gtk_combo_box_get_active (decl->priv->ref_table_cbox) == -1)
517 goto out;
518
519 sensitive = TRUE;
520 for (i = 0; i < decl->priv->n_cols; i++) {
521 Assoc *assoc = &(decl->priv->associations [i]);
522 if (! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (assoc->checkbox)))
523 continue;
524
525 onechecked = TRUE;
526 if (gtk_combo_box_get_active (assoc->cbox) == -1)
527 sensitive = FALSE;
528 }
529
530 if (! onechecked) {
531 sensitive = FALSE;
532 goto out;
533 }
534
535 out:
536 decl->priv->dialog_sensitive = sensitive;
537 gtk_dialog_set_response_sensitive (GTK_DIALOG (decl), GTK_RESPONSE_ACCEPT, sensitive);
538 }
539
540 /**
541 * fk_declare_write
542 * @decl: a #FkDeclare widget
543 * @bwin: (allow-none): a #BrowserWindow, or %NULL
544 * @error: a place to store errors or %NULL
545 *
546 * Actually declares the new foreign key in the meta store
547 *
548 * Returns: %TRUE if no error occurred
549 */
550 gboolean
fk_declare_write(FkDeclare * decl,BrowserWindow * bwin,GError ** error)551 fk_declare_write (FkDeclare *decl, BrowserWindow *bwin, GError **error)
552 {
553 gboolean retval = FALSE;
554
555 g_return_val_if_fail (IS_FK_DECLARE (decl), FALSE);
556 g_return_val_if_fail (!bwin || BROWSER_IS_WINDOW (bwin), FALSE);
557
558 if (! decl->priv->dialog_sensitive) {
559 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_COMMAND_ARGUMENTS_ERROR,
560 "%s", _("Missing information to declare foreign key"));
561 return FALSE;
562 }
563
564 GdaMetaTable *mtable = NULL;
565 GtkTreeIter iter;
566 g_assert (gtk_combo_box_get_active_iter (decl->priv->ref_table_cbox, &iter));
567 gtk_tree_model_get (gtk_combo_box_get_model (decl->priv->ref_table_cbox), &iter,
568 MODEL_TABLES_COLUMN_META_TABLE, &mtable, -1);
569
570 GdaMetaStore *mstore;
571 gchar **colnames, **ref_colnames;
572 colnames = g_new0 (gchar *, decl->priv->n_cols);
573 ref_colnames = g_new0 (gchar *, decl->priv->n_cols);
574 gint i, j;
575 for (i = 0, j = 0; i < decl->priv->n_cols; i++) {
576 Assoc *assoc = &(decl->priv->associations [i]);
577 if (! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (assoc->checkbox)))
578 continue;
579 colnames [j] = assoc->column->column_name;
580 g_assert (gtk_combo_box_get_active_iter (assoc->cbox, &iter));
581 GdaMetaTableColumn *ref_column;
582 gtk_tree_model_get (gtk_combo_box_get_model (assoc->cbox), &iter,
583 MODEL_TABLES_COLUMN_META_TABLE, &ref_column, -1);
584 g_assert (ref_column);
585 ref_colnames [j] = ref_column->column_name;
586 j++;
587 }
588
589 g_object_get (G_OBJECT (decl->priv->mstruct), "meta-store", &mstore, NULL);
590 retval = gda_meta_store_declare_foreign_key (mstore, NULL,
591 gtk_entry_get_text (GTK_ENTRY (decl->priv->fk_name)),
592 GDA_META_DB_OBJECT (decl->priv->mtable)->obj_catalog,
593 GDA_META_DB_OBJECT (decl->priv->mtable)->obj_schema,
594 GDA_META_DB_OBJECT (decl->priv->mtable)->obj_name,
595 GDA_META_DB_OBJECT (mtable)->obj_catalog,
596 GDA_META_DB_OBJECT (mtable)->obj_schema,
597 GDA_META_DB_OBJECT (mtable)->obj_name,
598 j, colnames, ref_colnames, error);
599 g_free (colnames);
600 g_free (ref_colnames);
601
602 if (retval && bwin) {
603 BrowserConnection *bcnc;
604 bcnc = browser_window_get_connection (bwin);
605 browser_connection_meta_data_changed (bcnc);
606 }
607
608 g_object_unref (mstore);
609 return retval;
610 }
611
612 /**
613 * fk_declare_undeclare:
614 * @mstruct: the #GdaMEtaStruct to delete the FK from
615 * @bwin: (allow-none): a #BrowserWindow, or %NULL
616 * @decl_fk: the #GdaMetaTableForeignKey fk to delete
617 * @error: a place to store errors, or %NULL
618 *
619 * Deletes a declared FK.
620 *
621 * Returns: %TRUE if no error occurred
622 */
623 gboolean
fk_declare_undeclare(GdaMetaStruct * mstruct,BrowserWindow * bwin,GdaMetaTableForeignKey * decl_fk,GError ** error)624 fk_declare_undeclare (GdaMetaStruct *mstruct, BrowserWindow *bwin, GdaMetaTableForeignKey *decl_fk,
625 GError **error)
626 {
627 gboolean retval = FALSE;
628 GdaMetaStore *mstore;
629
630 g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE);
631 g_return_val_if_fail (!bwin || BROWSER_IS_WINDOW (bwin), FALSE);
632 g_return_val_if_fail (decl_fk, FALSE);
633 if (!decl_fk->meta_table ||
634 !decl_fk->meta_table->obj_catalog ||
635 !decl_fk->meta_table->obj_schema ||
636 !decl_fk->meta_table->obj_name ||
637 !decl_fk->depend_on ||
638 !decl_fk->depend_on->obj_catalog ||
639 !decl_fk->depend_on->obj_schema ||
640 !decl_fk->depend_on->obj_name) {
641 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_COMMAND_ARGUMENTS_ERROR,
642 "%s", _("Missing information to undeclare foreign key"));
643 return FALSE;
644 }
645
646 g_object_get (G_OBJECT (mstruct), "meta-store", &mstore, NULL);
647 retval = gda_meta_store_undeclare_foreign_key (mstore, NULL,
648 decl_fk->fk_name,
649 decl_fk->meta_table->obj_catalog,
650 decl_fk->meta_table->obj_schema,
651 decl_fk->meta_table->obj_name,
652 decl_fk->depend_on->obj_catalog,
653 decl_fk->depend_on->obj_schema,
654 decl_fk->depend_on->obj_name,
655 error);
656 if (retval && bwin) {
657 BrowserConnection *bcnc;
658 bcnc = browser_window_get_connection (bwin);
659 browser_connection_meta_data_changed (bcnc);
660 }
661
662 g_object_unref (mstore);
663 return retval;
664 }
665