1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * File:    table_dialog.c
19  *
20  * Purpose: This file contains the code the draws and handles the
21  *          (databse) table dialog. This is the dialog box that is
22  *          displayed when the table Icon is double clicked.
23  */
24 
25 /*
26  * The code listed here is very similar to the one for the UML class
27  * dialog. Indeed, I've used it as a template. -- pn
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33 
34 #undef GTK_DISABLE_DEPRECATED /* GtkList, */
35 #include <gtk/gtk.h>
36 #include <string.h>
37 #include "database.h"
38 
39 struct _TablePropDialog {
40   GtkWidget * dialog;
41 
42   /* general page */
43 
44   GtkEntry * table_name;
45   GtkTextView * table_comment;
46   GtkToggleButton * comment_visible;
47   GtkToggleButton * comment_tagging;
48   GtkToggleButton * underline_primary_key;
49   GtkToggleButton * bold_primary_key;
50 
51   DiaColorSelector * text_color;
52   DiaColorSelector * line_color;
53   DiaColorSelector * fill_color;
54 
55   DiaFontSelector *normal_font;
56   GtkSpinButton *normal_font_height;
57 
58   DiaFontSelector *name_font;
59   GtkSpinButton *name_font_height;
60 
61   DiaFontSelector *comment_font;
62   GtkSpinButton *comment_font_height;
63 
64   GtkSpinButton * border_width;
65 
66   /* attributes page */
67 
68   GtkList *     attributes_list;
69   GtkEntry *    attribute_name;
70   GtkEntry *    attribute_type;
71   GtkTextView * attribute_comment;
72   GtkToggleButton * attribute_primary_key;
73   GtkToggleButton * attribute_nullable;
74   GtkToggleButton * attribute_unique;
75 
76   GtkListItem * cur_attr_list_item;
77   GList * added_connections;
78   GList * deleted_connections;
79   GList * disconnected_connections;
80 };
81 
82 void
table_dialog_free(TablePropDialog * dialog)83 table_dialog_free (TablePropDialog *dialog)
84 {
85   gtk_widget_destroy (dialog->dialog);
86   g_free (dialog);
87 }
88 
89 /* ----------------------------------------------------------------------- */
90 
91 static void destroy_prop_dialog (GtkWidget*, gpointer);
92 static void create_dialog_pages(GtkNotebook *, Table *);
93 static void create_general_page (GtkNotebook *, Table *);
94 static void create_attribute_page (GtkNotebook *, Table *);
95 static void create_style_page (GtkNotebook *, Table *);
96 static void fill_in_dialog (Table *);
97 static void general_page_fill_in_dialog (Table *);
98 static void general_page_props_to_object (Table *, TablePropDialog *);
99 static void attribute_page_props_to_object (Table *, TablePropDialog *);
100 static void attributes_page_values_to_attribute (TablePropDialog *,
101                                                  TableAttribute *);
102 static void create_font_props_row (GtkTable   *table,
103                                    const char *kind,
104                                    gint        row,
105                                    DiaFont    *font,
106                                    real        height,
107                                    DiaFontSelector **fontsel,
108                                    GtkSpinButton   **heightsel);
109 static const gchar * get_comment(GtkTextView *view);
110 static void set_comment(GtkTextView *view, gchar *text);
111 static void attributes_list_selection_changed_cb (GtkWidget *, Table *);
112 static void attributes_page_set_sensitive (TablePropDialog *, gboolean);
113 static void attributes_page_clear_values(TablePropDialog *);
114 static void attributes_page_set_values (TablePropDialog *, TableAttribute *);
115 static void attributes_page_update_cur_attr_item (TablePropDialog *);
116 static void attribute_list_item_destroy_cb (GtkWidget *, gpointer);
117 static void attributes_list_new_button_clicked_cb (GtkWidget *, Table *);
118 static void attributes_list_delete_button_clicked_cb (GtkWidget *, Table *);
119 static void attributes_list_moveup_button_clicked_cb (GtkWidget *, Table *);
120 static void attributes_list_movedown_button_clicked_cb (GtkWidget *, Table *);
121 static void attributes_list_add_attribute (Table *, TableAttribute *, gboolean);
122 static void current_attribute_update (GtkWidget *, Table *);
123 static int current_attribute_update_event (GtkWidget *,
124                                            GdkEventFocus *, Table *);
125 static void attributes_page_fill_in_dialog (Table *);
126 static void attribute_primary_key_toggled_cb (GtkToggleButton *, Table *);
127 static void attribute_nullable_toggled_cb (GtkToggleButton *, Table *);
128 static void attribute_unique_toggled_cb (GtkToggleButton *, Table *);
129 
130 static void table_dialog_store_disconnects (TablePropDialog *,
131                                             ConnectionPoint *);
132 static gchar * table_get_attribute_string (TableAttribute *);
133 
134 static void table_state_set (TableState *, Table *);
135 static void table_state_free (TableState *);
136 static void table_change_free (TableChange *);
137 static void table_change_revert (TableChange *, DiaObject *);
138 static void table_change_apply (TableChange *, DiaObject *);
139 
140 
141 /* ----------------------------------------------------------------------- */
142 
143 GtkWidget *
table_get_properties_dialog(Table * table,gboolean is_default)144 table_get_properties_dialog (Table * table, gboolean is_default)
145 {
146   TablePropDialog * prop_dialog;
147   GtkWidget * vbox;
148   GtkWidget * notebook;
149 
150   if (table->prop_dialog == NULL) {
151     prop_dialog = g_new0 (TablePropDialog, 1);
152     table->prop_dialog = prop_dialog;
153 
154     vbox = gtk_vbox_new (FALSE, 0);
155     gtk_object_ref (GTK_OBJECT(vbox));
156     gtk_object_sink (GTK_OBJECT(vbox));
157     prop_dialog->dialog = vbox;
158 
159     notebook = gtk_notebook_new ();
160     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
161     gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
162     gtk_container_set_border_width (GTK_CONTAINER (notebook), 10);
163 
164     gtk_object_set_user_data (GTK_OBJECT (notebook), (gpointer) table);
165 
166     gtk_signal_connect (GTK_OBJECT (notebook),
167                         "destroy",
168                         GTK_SIGNAL_FUNC (destroy_prop_dialog),
169                         (gpointer) table);
170 
171     create_dialog_pages (GTK_NOTEBOOK (notebook), table);
172     /* by default the table name entry is focused */
173     gtk_widget_grab_focus (GTK_WIDGET (table->prop_dialog->table_name));
174     gtk_widget_show (notebook);
175   }
176 
177   fill_in_dialog (table);
178   gtk_widget_show (table->prop_dialog->dialog);
179 
180   return table->prop_dialog->dialog;
181 }
182 
183 ObjectChange *
table_dialog_apply_changes(Table * table,GtkWidget * unused)184 table_dialog_apply_changes (Table * table, GtkWidget * unused)
185 {
186   TableState * state;
187   GList * disconnected;
188   GList * deleted;
189   GList * added;
190   TablePropDialog * prop_dialog;
191 
192   prop_dialog = table->prop_dialog;
193 
194   state = table_state_new (table);
195 
196   general_page_props_to_object (table, prop_dialog);
197   attribute_page_props_to_object (table, prop_dialog);
198 
199   table_update_primary_key_font (table);
200   table_compute_width_height (table);
201   table_update_positions (table);
202 
203   disconnected = prop_dialog->disconnected_connections;
204   prop_dialog->disconnected_connections = NULL;
205 
206   deleted = prop_dialog->deleted_connections;
207   prop_dialog->deleted_connections = NULL;
208 
209   added = prop_dialog->added_connections;
210   prop_dialog->added_connections = NULL;
211 
212   fill_in_dialog (table);
213   return (ObjectChange *)table_change_new (table, state,
214                                            added, deleted, disconnected);
215 }
216 
217 /* TableState & TableChange functions ------------------------------------- */
218 
table_state_new(Table * table)219 TableState * table_state_new (Table * table)
220 {
221   TableState * state = g_new0 (TableState, 1);
222   GList * list;
223 
224   state->name = g_strdup (table->name);
225   state->comment = g_strdup (table->comment);
226   state->visible_comment = table->visible_comment;
227   state->tagging_comment = table->tagging_comment;
228   state->underline_primary_key = table->underline_primary_key;
229   state->bold_primary_key = table->bold_primary_key;
230   state->border_width = table->border_width;
231 
232   list = table->attributes;
233   while (list != NULL)
234     {
235       TableAttribute * attr = (TableAttribute *) list->data;
236       TableAttribute * copy = table_attribute_copy (attr);
237 
238       copy->left_connection = attr->left_connection;
239       copy->right_connection = attr->right_connection;
240 
241       state->attributes = g_list_append (state->attributes, copy);
242       list = g_list_next (list);
243     }
244 
245   return state;
246 }
247 
248 /**
249  * Set the values stored in state to the passed table and reinit the table
250  * object. The table-state object will be free.
251  */
252 static void
table_state_set(TableState * state,Table * table)253 table_state_set (TableState * state, Table * table)
254 {
255   table->name = state->name;
256   table->comment = state->comment;
257   table->visible_comment = state->visible_comment;
258   table->tagging_comment = state->tagging_comment;
259   table->border_width = state->border_width;
260   table->underline_primary_key = state->underline_primary_key;
261   table->bold_primary_key = state->bold_primary_key;
262   table->border_width = state->border_width;
263   table->attributes = state->attributes;
264 
265   g_free (state);
266 
267   table_update_connectionpoints (table);
268   table_update_primary_key_font (table);
269   table_compute_width_height (table);
270   table_update_positions (table);
271 
272   if (table->prop_dialog)
273     gtk_list_clear_items (table->prop_dialog->attributes_list, 0, -1);
274 }
275 
276 static void
table_state_free(TableState * state)277 table_state_free (TableState * state)
278 {
279   GList * list;
280 
281   g_free (state->name);
282   g_free (state->comment);
283 
284   list = state->attributes;
285   while (list != NULL)
286     {
287       TableAttribute * attr = (TableAttribute *) list->data;
288       table_attribute_free (attr);
289       list = g_list_next (list);
290     }
291   g_list_free (state->attributes);
292 
293   g_free (state);
294 }
295 
table_change_new(Table * table,TableState * saved_state,GList * added,GList * deleted,GList * disconnects)296 TableChange * table_change_new (Table * table, TableState * saved_state,
297                                 GList * added, GList * deleted,
298                                 GList * disconnects)
299 {
300   TableChange * change;
301 
302   change = g_new (TableChange, 1);
303 
304   change->obj_change.apply = (ObjectChangeApplyFunc) table_change_apply;
305   change->obj_change.revert = (ObjectChangeRevertFunc) table_change_revert;
306   change->obj_change.free = (ObjectChangeFreeFunc) table_change_free;
307 
308   change->obj = table;
309   change->added_cp = added;
310   change->deleted_cp = deleted;
311   change->disconnected = disconnects;
312   change->applied = TRUE;
313   change->saved_state = saved_state;
314 
315   return change;
316 }
317 
318 /**
319  * Called to REDO a change on the table object.
320  */
321 static void
table_change_apply(TableChange * change,DiaObject * obj)322 table_change_apply (TableChange * change, DiaObject * obj)
323 {
324   TableState * old_state;
325   GList * lst;
326 
327   g_print ("apply (o: 0x%08x) (c: 0x%08x)\n", GPOINTER_TO_UINT(obj), GPOINTER_TO_UINT(change));
328 
329   /* first the get the current state for later use */
330   old_state = table_state_new (change->obj);
331   /* now apply the change */
332   table_state_set (change->saved_state, change->obj);
333 
334   lst = change->disconnected;
335   while (lst)
336     {
337       Disconnect * dis = (Disconnect *) lst->data;
338       object_unconnect (dis->other_object, dis->other_handle);
339       lst = g_list_next (lst);
340     }
341   change->saved_state = old_state;
342   change->applied = TRUE;
343 }
344 
345 /**
346  * Called to UNDO a change on the table object.
347  */
348 static void
table_change_revert(TableChange * change,DiaObject * obj)349 table_change_revert (TableChange *change, DiaObject *obj)
350 {
351   TableState *old_state;
352   GList *list;
353 
354   old_state = table_state_new(change->obj);
355 
356   table_state_set(change->saved_state, change->obj);
357 
358   list = change->disconnected;
359   while (list) {
360     Disconnect *dis = (Disconnect *)list->data;
361 
362     object_connect(dis->other_object, dis->other_handle, dis->cp);
363 
364     list = g_list_next(list);
365   }
366 
367   change->saved_state = old_state;
368   change->applied = FALSE;
369 }
370 
371 static void
table_change_free(TableChange * change)372 table_change_free (TableChange *change)
373 {
374   GList * free_list, * lst;
375 
376   table_state_free (change->saved_state);
377 
378   free_list = (change->applied == TRUE)
379     ? change->deleted_cp
380     : change->added_cp;
381 
382   lst = free_list;
383   while (lst)
384     {
385       ConnectionPoint * cp = (ConnectionPoint *) lst->data;
386       g_assert (cp->connected == NULL);
387       object_remove_connections_to (cp);
388       g_free (cp);
389 
390       lst = g_list_next (lst);
391     }
392   g_list_free (free_list);
393 }
394 
395 /* ------------------------------------------------------------------------ */
396 
397 static void
general_page_props_to_object(Table * table,TablePropDialog * prop_dialog)398 general_page_props_to_object (Table * table, TablePropDialog * prop_dialog)
399 {
400   gchar * s;
401 
402   /* name of the table */
403   if (table->name != NULL)
404     g_free (table->name);
405   s = (gchar *) gtk_entry_get_text (prop_dialog->table_name);
406   if (s != NULL && s[0] != '\0')
407     table->name = g_strdup (s);
408   else
409     table->name = NULL;
410 
411   /* the table's comment */
412   if (table->comment != NULL)
413     g_free (table->comment);
414   s = (gchar *) get_comment (prop_dialog->table_comment);
415   if (s != NULL && s[0] != '\0')
416     table->comment = g_strdup (s);
417   else
418     table->comment = NULL;
419 
420   table->visible_comment =
421     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prop_dialog->comment_visible));
422   table->tagging_comment =
423     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prop_dialog->comment_tagging));
424   table->underline_primary_key =
425     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (prop_dialog->underline_primary_key));
426   table->bold_primary_key =
427     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (prop_dialog->bold_primary_key));
428 
429   table->border_width =
430     gtk_spin_button_get_value (GTK_SPIN_BUTTON (prop_dialog->border_width));
431 
432   table->normal_font = dia_font_selector_get_font (prop_dialog->normal_font);
433   table->name_font = dia_font_selector_get_font (prop_dialog->name_font);
434   table->comment_font = dia_font_selector_get_font (prop_dialog->comment_font);
435 
436   table->normal_font_height =
437     gtk_spin_button_get_value_as_float (prop_dialog->normal_font_height);
438   table->name_font_height =
439     gtk_spin_button_get_value_as_float (prop_dialog->name_font_height);
440   table->comment_font_height =
441     gtk_spin_button_get_value_as_float (prop_dialog->comment_font_height);
442 
443   dia_color_selector_get_color (GTK_WIDGET (prop_dialog->text_color),
444                                 &table->text_color);
445   dia_color_selector_get_color (GTK_WIDGET (prop_dialog->line_color),
446                                 &table->line_color);
447   dia_color_selector_get_color (GTK_WIDGET (prop_dialog->fill_color),
448                                 &table->fill_color);
449 }
450 
451 static void
attribute_page_props_to_object(Table * table,TablePropDialog * prop_dialog)452 attribute_page_props_to_object (Table * table, TablePropDialog * prop_dialog)
453 {
454   GList * list;
455   GList * clear_list = NULL;
456   TableAttribute * attr;
457   GtkWidget * list_item;
458   DiaObject * obj;
459   ConnectionPoint * cp;
460 
461   /* if there is any currently edited item ... update its values */
462   attributes_page_update_cur_attr_item (prop_dialog);
463 
464   obj = &table->element.object;
465 
466   /* free current attributes */
467   list = table->attributes;
468   while (list != NULL)
469     {
470       attr = (TableAttribute *) list->data;
471       table_attribute_free (attr);
472       /* do not free the connection points they are shared by
473        * the corresponding attribute's stored in the gtklist on
474        * the attributes page
475        */
476       list = g_list_next (list);
477     }
478   g_list_free (table->attributes);
479   table->attributes = NULL;
480 
481   /* insert new attributes and remove them from gtklist */
482   list = GTK_LIST (prop_dialog->attributes_list)->children;
483   while (list != NULL)
484     {
485       list_item = GTK_WIDGET (list->data);
486 
487       clear_list = g_list_prepend (clear_list, list_item);
488       attr = (TableAttribute *)
489         gtk_object_get_user_data (GTK_OBJECT (list_item));
490       /* set to NULL so the attribute get's not freed when list_item is
491          destroyed */
492       gtk_object_set_user_data (GTK_OBJECT (list_item), NULL);
493       table->attributes = g_list_append (table->attributes, attr);
494 
495       list = g_list_next (list);
496     }
497 
498   table_update_connectionpoints (table);
499 
500   if (clear_list != NULL)
501     {
502       clear_list = g_list_reverse (clear_list);
503       gtk_list_remove_items (GTK_LIST (prop_dialog->attributes_list), clear_list);
504       g_list_free (clear_list);
505     }
506 
507   list = prop_dialog->deleted_connections;
508   while (list != NULL)
509     {
510       cp = (ConnectionPoint *) list->data;
511 
512       table_dialog_store_disconnects (prop_dialog, cp);
513       object_remove_connections_to (cp);
514 
515       list = g_list_next (list);
516     }
517 }
518 
519 static void
fill_in_dialog(Table * table)520 fill_in_dialog (Table * table)
521 {
522   general_page_fill_in_dialog (table);
523   attributes_page_fill_in_dialog (table);
524 }
525 
526 static void
general_page_fill_in_dialog(Table * table)527 general_page_fill_in_dialog (Table * table)
528 {
529   TablePropDialog * prop_dialog = table->prop_dialog;
530 
531   if (table->name)
532     gtk_entry_set_text (prop_dialog->table_name, table->name);
533   if (table->comment)
534     set_comment (prop_dialog->table_comment, table->comment);
535   else
536     set_comment (prop_dialog->table_comment, "");
537 
538   gtk_toggle_button_set_active (prop_dialog->comment_visible, table->visible_comment);
539   gtk_toggle_button_set_active (prop_dialog->comment_tagging, table->tagging_comment);
540   gtk_toggle_button_set_active (prop_dialog->underline_primary_key, table->underline_primary_key);
541   gtk_toggle_button_set_active (prop_dialog->bold_primary_key, table->bold_primary_key);
542   gtk_spin_button_set_value (prop_dialog->border_width, table->border_width);
543 
544   dia_font_selector_set_font (prop_dialog->normal_font, table->normal_font);
545   dia_font_selector_set_font (prop_dialog->name_font, table->name_font);
546   dia_font_selector_set_font (prop_dialog->comment_font, table->comment_font);
547 
548   dia_color_selector_set_color(GTK_WIDGET(prop_dialog->text_color), &table->text_color);
549   dia_color_selector_set_color(GTK_WIDGET(prop_dialog->line_color), &table->line_color);
550   dia_color_selector_set_color(GTK_WIDGET(prop_dialog->fill_color), &table->fill_color);
551 }
552 
553 static void
attributes_page_fill_in_dialog(Table * table)554 attributes_page_fill_in_dialog (Table * table)
555 {
556   TablePropDialog * prop_dialog;
557   GList * list;
558 
559   prop_dialog = table->prop_dialog;
560 
561   if (prop_dialog->attributes_list->children == NULL)
562     {
563       list = table->attributes;
564       while (list != NULL)
565         {
566           TableAttribute * attr = (TableAttribute *) list->data;
567           TableAttribute * attr_copy = table_attribute_copy (attr);
568           /* see `attribute_page_props_to_object' why we take over
569            * the original connection-points instead of creating new ones.
570            */
571           attr_copy->left_connection = attr->left_connection;
572           attr_copy->right_connection = attr->right_connection;
573 
574           attributes_list_add_attribute (table, attr_copy, FALSE);
575 
576           list = g_list_next (list);
577         }
578 
579       prop_dialog->cur_attr_list_item = NULL;
580       attributes_page_set_sensitive (prop_dialog, FALSE);
581       attributes_page_clear_values (prop_dialog);
582     }
583 }
584 
585 static void
create_dialog_pages(GtkNotebook * notebook,Table * table)586 create_dialog_pages(GtkNotebook * notebook, Table * table)
587 {
588   create_general_page (notebook, table);
589   create_attribute_page (notebook, table);
590   create_style_page (notebook, table);
591 }
592 
593 static void
create_attribute_page(GtkNotebook * notebook,Table * table)594 create_attribute_page (GtkNotebook * notebook, Table * table)
595 {
596   TablePropDialog * prop_dialog;
597   GtkWidget * page_label;
598   GtkWidget * vbox;
599   GtkWidget * hbox;
600   GtkWidget * scrolledwindow;
601   GtkWidget * list;
602   GtkWidget * vbox2;
603   GtkWidget * button;
604   GtkWidget * frame;
605   GtkWidget * gtk_table;
606   GtkWidget * label;
607   GtkWidget * entry;
608   GtkWidget * checkbox;
609 
610   prop_dialog = table->prop_dialog;
611 
612   page_label = gtk_label_new_with_mnemonic (_("_Attributes"));
613 
614   vbox = gtk_vbox_new (FALSE, 5);
615   gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
616 
617   hbox = gtk_hbox_new (FALSE, 5);
618   scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
619   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
620                                   GTK_POLICY_AUTOMATIC,
621                                   GTK_POLICY_AUTOMATIC);
622   gtk_box_pack_start (GTK_BOX (hbox), scrolledwindow, TRUE, TRUE, 0);
623   gtk_widget_show (scrolledwindow);
624 
625   list = gtk_list_new ();
626   prop_dialog->attributes_list = GTK_LIST (list);
627   gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_SINGLE);
628   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolledwindow), list);
629   gtk_container_set_focus_vadjustment (GTK_CONTAINER (list),
630                                        gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolledwindow)));
631   gtk_signal_connect (GTK_OBJECT (list), "selection_changed",
632                       GTK_SIGNAL_FUNC (attributes_list_selection_changed_cb),
633                       table);
634   gtk_widget_show (list);
635 
636   /* vbox for the button on the right side of the attributes list */
637   vbox2 = gtk_vbox_new (FALSE, 5);
638 
639   /* the "new" button */
640   button = gtk_button_new_with_mnemonic (_("_New"));
641   gtk_signal_connect (GTK_OBJECT (button), "clicked",
642                       GTK_SIGNAL_FUNC (attributes_list_new_button_clicked_cb),
643                       table);
644   gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, TRUE, 0);
645   gtk_widget_show (button);
646 
647   /* the "delete" button */
648   button = gtk_button_new_with_mnemonic (_("_Delete"));
649   gtk_signal_connect (GTK_OBJECT (button), "clicked",
650                       GTK_SIGNAL_FUNC (attributes_list_delete_button_clicked_cb),
651                       table);
652   gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, TRUE, 0);
653   gtk_widget_show (button);
654 
655   /* the "Move up" button */
656   button = gtk_button_new_with_mnemonic (_("Move up"));
657   gtk_signal_connect (GTK_OBJECT (button), "clicked",
658                       GTK_SIGNAL_FUNC (attributes_list_moveup_button_clicked_cb),
659                       table);
660   gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, TRUE, 0);
661   gtk_widget_show (button);
662 
663   /* the "Move down" button */
664   button = gtk_button_new_with_mnemonic (_("Move down"));
665   gtk_signal_connect (GTK_OBJECT (button), "clicked",
666                       GTK_SIGNAL_FUNC (attributes_list_movedown_button_clicked_cb),
667                       table);
668   gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, TRUE, 0);
669   gtk_widget_show (button);
670 
671   gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0);
672   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
673 
674   frame = gtk_frame_new (_("Attribute data"));
675   vbox2 = gtk_vbox_new (FALSE, 5);
676   gtk_container_set_border_width (GTK_CONTAINER (vbox2), 10);
677   gtk_container_add (GTK_CONTAINER (frame), vbox2);
678   gtk_widget_show (frame);
679   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
680 
681   gtk_table = gtk_table_new (4, 2, FALSE);
682   gtk_box_pack_start (GTK_BOX (vbox2), gtk_table, FALSE, FALSE, 0);
683 
684   label = gtk_label_new (_("Name:"));
685   entry = gtk_entry_new ();
686   prop_dialog->attribute_name = GTK_ENTRY (entry);
687   gtk_signal_connect (GTK_OBJECT (entry), "focus_out_event",
688                       GTK_SIGNAL_FUNC (current_attribute_update_event), table);
689   gtk_signal_connect (GTK_OBJECT (entry), "activate",
690                       GTK_SIGNAL_FUNC (current_attribute_update), table);
691   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
692   gtk_table_attach (GTK_TABLE (gtk_table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
693   gtk_table_attach (GTK_TABLE (gtk_table), entry, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 2);
694 
695 
696   label = gtk_label_new (_("Type:"));
697   entry = gtk_entry_new ();
698   prop_dialog->attribute_type = GTK_ENTRY (entry);
699   gtk_signal_connect (GTK_OBJECT (entry), "focus_out_event",
700                       GTK_SIGNAL_FUNC (current_attribute_update_event), table);
701   gtk_signal_connect (GTK_OBJECT (entry), "activate",
702                       GTK_SIGNAL_FUNC (current_attribute_update), table);
703   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
704   gtk_table_attach (GTK_TABLE (gtk_table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
705   gtk_table_attach (GTK_TABLE (gtk_table), entry, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 2);
706 
707 
708   label = gtk_label_new (_("Comment:"));
709   scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
710   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
711                                        GTK_SHADOW_IN);
712   entry = gtk_text_view_new ();
713   prop_dialog->attribute_comment = GTK_TEXT_VIEW (entry);
714   gtk_container_add (GTK_CONTAINER (scrolledwindow), entry);
715   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (entry), GTK_WRAP_WORD);
716   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (entry), TRUE);
717   gtk_signal_connect (GTK_OBJECT (entry), "focus_out_event",
718 		      GTK_SIGNAL_FUNC (current_attribute_update_event), table);
719   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
720   gtk_table_attach (GTK_TABLE (gtk_table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
721   gtk_table_attach (GTK_TABLE (gtk_table), scrolledwindow, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 2);
722 
723   /* start a new gtk-table */
724   gtk_table = gtk_table_new (2, 2, FALSE);
725   gtk_box_pack_start (GTK_BOX (vbox2), gtk_table, FALSE, FALSE, 0);
726 
727   checkbox = gtk_check_button_new_with_mnemonic (_("_Primary key"));
728   gtk_signal_connect (GTK_OBJECT (checkbox), "toggled",
729               GTK_SIGNAL_FUNC (attribute_primary_key_toggled_cb), table);
730   prop_dialog->attribute_primary_key = GTK_TOGGLE_BUTTON (checkbox);
731   gtk_table_attach (GTK_TABLE (gtk_table), checkbox, 0, 1, 0, 1,
732                     GTK_FILL | GTK_EXPAND, 0, 0, 0);
733 
734   checkbox = gtk_check_button_new_with_mnemonic (_("N_ullable"));
735   gtk_signal_connect (GTK_OBJECT (checkbox), "toggled",
736               GTK_SIGNAL_FUNC (attribute_nullable_toggled_cb), table);
737   prop_dialog->attribute_nullable = GTK_TOGGLE_BUTTON (checkbox);
738   gtk_table_attach (GTK_TABLE (gtk_table), checkbox, 1, 2, 0, 1,
739                     GTK_FILL | GTK_EXPAND, 0, 0, 0);
740 
741   checkbox = gtk_check_button_new_with_mnemonic (_("Uni_que"));
742   gtk_signal_connect (GTK_OBJECT (checkbox), "toggled",
743                       GTK_SIGNAL_FUNC (attribute_unique_toggled_cb), table);
744   prop_dialog->attribute_unique = GTK_TOGGLE_BUTTON (checkbox);
745   gtk_table_attach (GTK_TABLE (gtk_table), checkbox, 1, 2, 1, 2,
746                     GTK_FILL | GTK_EXPAND, 0, 0, 0);
747 
748   /* show the notebook page */
749   gtk_widget_show_all (vbox);
750   gtk_widget_show (page_label);
751   gtk_notebook_append_page (notebook, vbox, page_label);
752 }
753 
754 static void
attributes_page_set_sensitive(TablePropDialog * prop_dialog,gboolean val)755 attributes_page_set_sensitive (TablePropDialog * prop_dialog, gboolean val)
756 {
757   gtk_widget_set_sensitive (GTK_WIDGET (prop_dialog->attribute_name), val);
758   gtk_widget_set_sensitive (GTK_WIDGET (prop_dialog->attribute_type), val);
759   gtk_widget_set_sensitive (GTK_WIDGET (prop_dialog->attribute_comment), val);
760   gtk_widget_set_sensitive (GTK_WIDGET (prop_dialog->attribute_primary_key), val);
761   gtk_widget_set_sensitive (GTK_WIDGET (prop_dialog->attribute_nullable), val);
762   gtk_widget_set_sensitive (GTK_WIDGET (prop_dialog->attribute_unique), val);
763 }
764 
765 static void
attributes_page_clear_values(TablePropDialog * prop_dialog)766 attributes_page_clear_values(TablePropDialog * prop_dialog)
767 {
768   gtk_entry_set_text(prop_dialog->attribute_name, "");
769   gtk_entry_set_text(prop_dialog->attribute_type, "");
770   set_comment(prop_dialog->attribute_comment, "");
771   gtk_toggle_button_set_active (prop_dialog->attribute_primary_key, FALSE);
772   gtk_toggle_button_set_active (prop_dialog->attribute_nullable, TRUE);
773   gtk_toggle_button_set_active (prop_dialog->attribute_unique, FALSE);
774 }
775 
776 /**
777  * Copy the properties from an attribute to the attribute page.
778  */
779 static void
attributes_page_set_values(TablePropDialog * prop_dialog,TableAttribute * attr)780 attributes_page_set_values (TablePropDialog * prop_dialog, TableAttribute * attr)
781 {
782   gtk_entry_set_text (prop_dialog->attribute_name, attr->name);
783   gtk_entry_set_text (prop_dialog->attribute_type, attr->type);
784   set_comment (prop_dialog->attribute_comment, attr->comment);
785   gtk_toggle_button_set_active (prop_dialog->attribute_primary_key,
786                                 attr->primary_key);
787   gtk_toggle_button_set_active (prop_dialog->attribute_nullable,
788                                 attr->nullable);
789   gtk_toggle_button_set_active (prop_dialog->attribute_unique,
790                                 attr->unique);
791 }
792 
793 /**
794  * Copy the properties of an attribute from the attribute page to a
795  * concrete attribute.
796  */
797 static void
attributes_page_values_to_attribute(TablePropDialog * prop_dialog,TableAttribute * attr)798 attributes_page_values_to_attribute (TablePropDialog * prop_dialog,
799                                      TableAttribute * attr)
800 {
801   if (attr->name) g_free (attr->name);
802   if (attr->type) g_free (attr->type);
803   if (attr->comment) g_free (attr->comment);
804 
805   attr->name = g_strdup (gtk_entry_get_text (prop_dialog->attribute_name));
806   attr->type = g_strdup (gtk_entry_get_text (prop_dialog->attribute_type));
807   attr->comment = g_strdup (get_comment (prop_dialog->attribute_comment));
808   attr->primary_key = gtk_toggle_button_get_active (prop_dialog->attribute_primary_key);
809   attr->nullable = gtk_toggle_button_get_active (prop_dialog->attribute_nullable);
810   attr->unique = gtk_toggle_button_get_active (prop_dialog->attribute_unique);
811 }
812 
813 /**
814  * Update the current attribute from the attributes page. This involves
815  * copying the new values into the attribute as well as updating the
816  * displayed string in the attributes listbox.
817  */
818 static void
attributes_page_update_cur_attr_item(TablePropDialog * prop_dialog)819 attributes_page_update_cur_attr_item (TablePropDialog * prop_dialog)
820 {
821   TableAttribute * attr;
822   GtkLabel * label;
823   gchar * str;
824 
825   if (prop_dialog && prop_dialog->cur_attr_list_item)
826     {
827       attr = (TableAttribute *)
828         gtk_object_get_user_data (GTK_OBJECT (prop_dialog->cur_attr_list_item));
829       if (attr != NULL)
830         {
831           attributes_page_values_to_attribute (prop_dialog, attr);
832           label = GTK_LABEL (GTK_BIN (prop_dialog->cur_attr_list_item)->child);
833           str = table_get_attribute_string (attr);
834           gtk_label_set_text (label, str);
835           g_free (str);
836         }
837     }
838 }
839 
840 static void
attribute_primary_key_toggled_cb(GtkToggleButton * button,Table * table)841 attribute_primary_key_toggled_cb (GtkToggleButton * button, Table * table)
842 {
843   gboolean active;
844   TablePropDialog * prop_dialog = table->prop_dialog;
845 
846   active = gtk_toggle_button_get_active (prop_dialog->attribute_primary_key);
847 
848   if (active)
849     {
850       gtk_toggle_button_set_active (prop_dialog->attribute_nullable, FALSE);
851       gtk_toggle_button_set_active (prop_dialog->attribute_unique, TRUE);
852     }
853   attributes_page_update_cur_attr_item (prop_dialog);
854   gtk_widget_set_sensitive (GTK_WIDGET (prop_dialog->attribute_nullable),
855                             !active);
856   gtk_widget_set_sensitive (GTK_WIDGET (prop_dialog->attribute_unique),
857                             !active);
858 }
859 
860 static void
attribute_nullable_toggled_cb(GtkToggleButton * button,Table * table)861 attribute_nullable_toggled_cb (GtkToggleButton * button, Table * table)
862 {
863   TablePropDialog * prop_dialog = table->prop_dialog;
864 
865   attributes_page_update_cur_attr_item (prop_dialog);
866 }
867 
868 static void
attribute_unique_toggled_cb(GtkToggleButton * button,Table * table)869 attribute_unique_toggled_cb (GtkToggleButton * button, Table * table)
870 {
871   TablePropDialog * prop_dialog = table->prop_dialog;
872 
873   attributes_page_update_cur_attr_item (prop_dialog);
874 }
875 
876 static void
attributes_list_selection_changed_cb(GtkWidget * gtklist,Table * table)877 attributes_list_selection_changed_cb (GtkWidget * gtklist, Table * table)
878 {
879   TablePropDialog * prop_dialog;
880   GList * list;
881   TableAttribute * attr;
882   GtkObject * list_item;
883 
884   /* Due to GtkList oddities, this may get called during destroy.
885    * But it'll reference things that are already dead and crash.
886    * Thus, we stop it before it gets that bad.  See bug #156706 for
887    * one example.
888    */
889   if (table->destroyed || !table->prop_dialog)
890     return;
891 
892   prop_dialog = table->prop_dialog;
893   attributes_page_update_cur_attr_item (prop_dialog);
894 
895   list = GTK_LIST (gtklist)->selection;
896   if (list == NULL)
897     {
898       prop_dialog->cur_attr_list_item = NULL;
899 
900       attributes_page_set_sensitive (prop_dialog, FALSE);
901       attributes_page_clear_values (prop_dialog);
902     }
903   else
904     {
905       list_item = GTK_OBJECT (list->data);
906       attr = (TableAttribute *) gtk_object_get_user_data (list_item);
907       attributes_page_set_sensitive (prop_dialog, TRUE);
908       attributes_page_set_values (prop_dialog, attr);
909 
910       prop_dialog->cur_attr_list_item = GTK_LIST_ITEM (list_item);
911       gtk_widget_grab_focus (GTK_WIDGET (prop_dialog->attribute_name));
912     }
913 }
914 
915 static void
create_general_page(GtkNotebook * notebook,Table * table)916 create_general_page (GtkNotebook * notebook, Table * table)
917 {
918   TablePropDialog * prop_dialog;
919   GtkWidget * page_label;
920   GtkWidget * vbox;
921   GtkWidget * gtk_table;
922   GtkWidget * label;
923   GtkWidget * entry;
924   GtkWidget * scrolled_window;
925   GtkWidget * checkbox;
926 
927   prop_dialog = table->prop_dialog;
928 
929   page_label = gtk_label_new_with_mnemonic (_("_Table"));
930 
931   vbox = gtk_vbox_new (FALSE, 5);
932   gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
933 
934   gtk_table = gtk_table_new (3, 2, FALSE);
935   gtk_box_pack_start (GTK_BOX (vbox), gtk_table, FALSE, FALSE, 0);
936 
937   label = gtk_label_new (_("Table name:"));
938   entry = gtk_entry_new ();
939   prop_dialog->table_name = GTK_ENTRY (entry);
940   gtk_widget_grab_focus (entry);
941   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
942   gtk_table_attach (GTK_TABLE (gtk_table), label, 0, 1, 0, 1,
943                     GTK_FILL, 0, 0, 0);
944   gtk_table_attach (GTK_TABLE (gtk_table), entry, 1, 2, 0, 1,
945                     GTK_FILL | GTK_EXPAND, 0, 0, 2);
946 
947   label = gtk_label_new(_("Comment:"));
948   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
949   gtk_table_attach (GTK_TABLE (gtk_table), scrolled_window, 1, 2, 2, 3,
950                     (GtkAttachOptions) (GTK_FILL),
951                     (GtkAttachOptions) (GTK_FILL), 0, 0);
952   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
953                                        GTK_SHADOW_IN);
954   entry = gtk_text_view_new ();
955   prop_dialog->table_comment = GTK_TEXT_VIEW(entry);
956   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (entry), GTK_WRAP_WORD);
957   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
958   gtk_table_attach (GTK_TABLE (gtk_table), label, 0,1,2,3, GTK_FILL,0, 0,0);
959   gtk_container_add (GTK_CONTAINER (scrolled_window), entry);
960 
961   /* --- table for various checkboxes */
962   gtk_table = gtk_table_new (2, 2, TRUE);
963   gtk_box_pack_start (GTK_BOX (vbox), gtk_table, FALSE, FALSE, 0);
964 
965   /* XXX create a handler and disable the 'show documentation tag' checkbox
966      if 'comment visible' is not active. */
967   checkbox = gtk_check_button_new_with_label(_("Comment visible"));
968   prop_dialog->comment_visible = GTK_TOGGLE_BUTTON(checkbox);
969   gtk_table_attach (GTK_TABLE (gtk_table), checkbox, 0, 1, 0, 1,
970                     GTK_FILL, 10, 0, 0);
971 
972   checkbox = gtk_check_button_new_with_label(_("Show documentation tag"));
973   prop_dialog->comment_tagging = GTK_TOGGLE_BUTTON( checkbox );
974   gtk_table_attach (GTK_TABLE (gtk_table), checkbox, 1, 2, 0, 1,
975                     GTK_FILL, 10, 0, 0);
976 
977   checkbox = gtk_check_button_new_with_label (_("Underline primary keys"));
978   prop_dialog->underline_primary_key = GTK_TOGGLE_BUTTON (checkbox);
979   gtk_table_attach (GTK_TABLE (gtk_table), checkbox, 0, 1, 1, 2,
980                     GTK_FILL, 10, 0, 0);
981 
982   checkbox = gtk_check_button_new_with_label (_("Use bold font for primary keys"));
983   prop_dialog->bold_primary_key = GTK_TOGGLE_BUTTON (checkbox);
984   gtk_table_attach (GTK_TABLE (gtk_table), checkbox, 1, 2, 1, 2,
985                     GTK_FILL, 10, 0, 0);
986   /* +++ end of the table for various checkboxes */
987 
988   /* finally append the created vbox to the notebook */
989   gtk_widget_show_all (vbox);
990   gtk_widget_show (page_label);
991   gtk_notebook_append_page (notebook, vbox, page_label);
992 
993 }
994 
995 static void
create_style_page(GtkNotebook * notebook,Table * table)996 create_style_page (GtkNotebook * notebook, Table * table)
997 {
998   TablePropDialog * prop_dialog;
999   GtkWidget * page_label;
1000   GtkWidget * vbox;
1001   GtkWidget * gtk_table;
1002   GtkWidget * label;
1003   GtkWidget * hbox;
1004   GtkWidget * text_color;
1005   GtkWidget * fill_color;
1006   GtkWidget * line_color;
1007   GtkObject * adj;
1008 
1009   prop_dialog = table->prop_dialog;
1010 
1011   page_label = gtk_label_new_with_mnemonic (_("_Style"));
1012 
1013   vbox = gtk_vbox_new (FALSE, 5);
1014   gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
1015 
1016   hbox = gtk_hbox_new (FALSE, 5);
1017   adj = gtk_adjustment_new (table->border_width, 0.00, 10.0, 0.01, 0.1, 0);
1018   prop_dialog->border_width =
1019     GTK_SPIN_BUTTON (gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0.1, 2));
1020   gtk_spin_button_set_snap_to_ticks (prop_dialog->border_width, TRUE);
1021   gtk_spin_button_set_numeric (prop_dialog->border_width, TRUE);
1022   label = gtk_label_new (_("Border width:"));
1023   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
1024   gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (prop_dialog->border_width),
1025                       TRUE, TRUE, 0);
1026   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
1027 
1028   gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 3);
1029 
1030   /* fonts */
1031   gtk_table = gtk_table_new (5, 6, TRUE);
1032   gtk_box_pack_start (GTK_BOX (vbox), gtk_table, FALSE, TRUE, 0);
1033   gtk_table_set_homogeneous (GTK_TABLE (gtk_table), FALSE);
1034 
1035   label = gtk_label_new (_("Kind"));
1036   gtk_table_attach_defaults (GTK_TABLE (gtk_table), label, 0, 1, 0, 1);
1037   label = gtk_label_new (_("Font"));
1038   gtk_table_attach_defaults (GTK_TABLE (gtk_table), label, 1, 2, 0, 1);
1039   label = gtk_label_new (_("Size"));
1040   gtk_table_attach_defaults (GTK_TABLE (gtk_table), label, 2, 3, 0, 1);
1041 
1042   create_font_props_row (GTK_TABLE (gtk_table), _("Normal:"), 3,
1043                          table->normal_font,
1044                          table->normal_font_height,
1045                          &(prop_dialog->normal_font),
1046                          &(prop_dialog->normal_font_height));
1047   create_font_props_row (GTK_TABLE (gtk_table), _("Name:"), 4,
1048                          table->name_font,
1049                          table->name_font_height,
1050                          &(prop_dialog->name_font),
1051                          &(prop_dialog->name_font_height));
1052   create_font_props_row (GTK_TABLE (gtk_table), _("Comment:"), 5,
1053                          table->comment_font,
1054                          table->comment_font_height,
1055                          &(prop_dialog->comment_font),
1056                          &(prop_dialog->comment_font_height));
1057 
1058   gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 3);
1059 
1060   /* colors */
1061   gtk_table = gtk_table_new (2, 3, TRUE);
1062   gtk_box_pack_start (GTK_BOX (vbox), gtk_table, FALSE, TRUE, 0);
1063   label = gtk_label_new(_("Text Color:"));
1064   gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1065   gtk_table_attach (GTK_TABLE (gtk_table), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 2);
1066   text_color = dia_color_selector_new();
1067   dia_color_selector_set_color(text_color, &table->text_color);
1068   prop_dialog->text_color = (DiaColorSelector *)text_color;
1069   gtk_table_attach (GTK_TABLE (gtk_table), text_color, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 3, 2);
1070 
1071   label = gtk_label_new(_("Foreground Color:"));
1072   gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1073   gtk_table_attach (GTK_TABLE (gtk_table), label, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, 0, 0, 2);
1074   line_color = dia_color_selector_new();
1075   dia_color_selector_set_color(line_color, &table->line_color);
1076   prop_dialog->line_color = (DiaColorSelector *)line_color;
1077   gtk_table_attach (GTK_TABLE (gtk_table), line_color, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 3, 2);
1078 
1079   label = gtk_label_new(_("Background Color:"));
1080   gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1081   gtk_table_attach (GTK_TABLE (gtk_table), label, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, 0, 0, 2);
1082   fill_color = dia_color_selector_new();
1083   dia_color_selector_set_color(fill_color, &table->fill_color);
1084   prop_dialog->fill_color = (DiaColorSelector *)fill_color;
1085   gtk_table_attach (GTK_TABLE (gtk_table), fill_color, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 3, 2);
1086 
1087   /* finally append the created vbox to the notebook */
1088   gtk_widget_show_all (vbox);
1089   gtk_widget_show (page_label);
1090   gtk_notebook_append_page (notebook, vbox, page_label);
1091 }
1092 
1093 /**
1094  * pn: "Borrowed" from the source code of the UML class object.
1095  */
1096 static void
create_font_props_row(GtkTable * table,const char * kind,gint row,DiaFont * font,real height,DiaFontSelector ** fontsel,GtkSpinButton ** heightsel)1097 create_font_props_row (GtkTable   *table,
1098                        const char *kind,
1099                        gint        row,
1100                        DiaFont    *font,
1101                        real        height,
1102                        DiaFontSelector **fontsel,
1103                        GtkSpinButton   **heightsel)
1104 {
1105   GtkWidget *label;
1106   GtkObject *adj;
1107 
1108   label = gtk_label_new (kind);
1109   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1110   gtk_table_attach_defaults (table, label, 0, 1, row, row+1);
1111   *fontsel = DIAFONTSELECTOR (dia_font_selector_new ());
1112   dia_font_selector_set_font (DIAFONTSELECTOR (*fontsel), font);
1113   gtk_table_attach_defaults (GTK_TABLE (table), GTK_WIDGET(*fontsel), 1, 2, row, row+1);
1114 
1115   adj = gtk_adjustment_new (height, 0.1, 10.0, 0.1, 1.0, 0);
1116   *heightsel = GTK_SPIN_BUTTON (gtk_spin_button_new (GTK_ADJUSTMENT(adj), 1.0, 2));
1117   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (*heightsel), TRUE);
1118   gtk_table_attach_defaults (table, GTK_WIDGET (*heightsel), 2, 3, row, row+1);
1119 }
1120 
1121 static void
attributes_list_new_button_clicked_cb(GtkWidget * button,Table * table)1122 attributes_list_new_button_clicked_cb (GtkWidget * button, Table * table)
1123 {
1124   TablePropDialog * prop_dialog;
1125   TableAttribute * attr;
1126 
1127   prop_dialog = table->prop_dialog;
1128   attributes_page_update_cur_attr_item (prop_dialog);
1129 
1130   attr = table_attribute_new ();
1131   table_attribute_ensure_connection_points (attr, &table->element.object);
1132 
1133   prop_dialog->added_connections =
1134     g_list_append (prop_dialog->added_connections, attr->left_connection);
1135   prop_dialog->added_connections =
1136     g_list_append (prop_dialog->added_connections, attr->right_connection);
1137 
1138   attributes_list_add_attribute (table, attr, TRUE);
1139 }
1140 
1141 /**
1142  * Add the passed attribute into the listbox of attributes. The passed
1143  * attribute should be a copy of the original attribute as it will be
1144  * freed when destroying the attribute listbox. If SELECT is TRUE the
1145  * new list item is selected.
1146  */
1147 static void
attributes_list_add_attribute(Table * table,TableAttribute * attribute,gboolean select)1148 attributes_list_add_attribute (Table * table,
1149                                TableAttribute * attribute,
1150                                gboolean select)
1151 {
1152   TablePropDialog * prop_dialog;
1153   gchar * attrstr;
1154   GtkWidget * list_item;
1155   GList * list;
1156 
1157   prop_dialog = table->prop_dialog;
1158 
1159   attrstr = table_get_attribute_string (attribute);
1160   list_item = gtk_list_item_new_with_label (attrstr);
1161   gtk_widget_show (list_item);
1162   g_free (attrstr);
1163 
1164   gtk_object_set_user_data (GTK_OBJECT (list_item), attribute);
1165   gtk_signal_connect (GTK_OBJECT (list_item), "destroy",
1166                       GTK_SIGNAL_FUNC (attribute_list_item_destroy_cb),
1167                       NULL);
1168   list = g_list_append (NULL, list_item);
1169   gtk_list_append_items (prop_dialog->attributes_list, list);
1170   if (select)
1171     {
1172       if (prop_dialog->attributes_list->children != NULL)
1173         gtk_list_unselect_child (prop_dialog->attributes_list,
1174                 GTK_WIDGET (prop_dialog->attributes_list->children->data));
1175       gtk_list_select_child (prop_dialog->attributes_list, list_item);
1176     }
1177 }
1178 
1179 static void
current_attribute_update(GtkWidget * unused,Table * table)1180 current_attribute_update (GtkWidget * unused, Table * table)
1181 {
1182   attributes_page_update_cur_attr_item (table->prop_dialog);
1183 }
1184 
1185 static int
current_attribute_update_event(GtkWidget * unused,GdkEventFocus * unused2,Table * table)1186 current_attribute_update_event (GtkWidget * unused,
1187                                 GdkEventFocus *unused2,
1188                                 Table * table)
1189 {
1190   attributes_page_update_cur_attr_item (table->prop_dialog);
1191   return 0;
1192 }
1193 
1194 
1195 static void
attributes_list_delete_button_clicked_cb(GtkWidget * button,Table * table)1196 attributes_list_delete_button_clicked_cb (GtkWidget * button, Table * table)
1197 {
1198   GList * list;
1199   GtkList * gtklist;
1200   TablePropDialog * prop_dialog;
1201   TableAttribute * attr;
1202 
1203   prop_dialog = table->prop_dialog;
1204   gtklist = GTK_LIST (prop_dialog->attributes_list);
1205 
1206   if (gtklist->selection != NULL)
1207     {
1208       attr = (TableAttribute *)
1209         gtk_object_get_user_data (GTK_OBJECT (gtklist->selection->data));
1210       prop_dialog->deleted_connections =
1211         g_list_prepend (prop_dialog->deleted_connections,
1212                         attr->left_connection);
1213       prop_dialog->deleted_connections =
1214         g_list_prepend (prop_dialog->deleted_connections,
1215                         attr->right_connection);
1216 
1217       list = g_list_append (NULL, gtklist->selection->data);
1218       gtk_list_remove_items (gtklist, list);
1219       g_list_free (list);
1220       attributes_page_clear_values (prop_dialog);
1221       attributes_page_set_sensitive (prop_dialog, FALSE);
1222     }
1223 }
1224 
1225 static void
attributes_list_moveup_button_clicked_cb(GtkWidget * button,Table * table)1226 attributes_list_moveup_button_clicked_cb (GtkWidget * button, Table * table)
1227 {
1228   TablePropDialog * prop_dialog;
1229   GtkList * gtklist;
1230   GList * list;
1231   GtkWidget * list_item;
1232   gint i;
1233 
1234   prop_dialog = table->prop_dialog;
1235   gtklist = GTK_LIST (prop_dialog->attributes_list);
1236 
1237   if (gtklist->selection != NULL)
1238     {
1239       list_item = GTK_WIDGET (gtklist->selection->data);
1240 
1241       i = gtk_list_child_position (gtklist, list_item);
1242       if (i > 0)
1243         {
1244           i--;
1245 
1246           gtk_widget_ref (list_item);
1247           list = g_list_prepend (NULL, list_item);
1248           gtk_list_remove_items (gtklist, list);
1249           gtk_list_insert_items (gtklist, list, i);
1250           gtk_widget_unref (list_item);
1251 
1252           gtk_list_select_child (gtklist, list_item);
1253         }
1254     }
1255 }
1256 
1257 static void
attributes_list_movedown_button_clicked_cb(GtkWidget * button,Table * table)1258 attributes_list_movedown_button_clicked_cb (GtkWidget * button, Table * table)
1259 {
1260   TablePropDialog * prop_dialog;
1261   GtkList * gtklist;
1262   GList * list;
1263   GtkWidget * list_item;
1264   gint i;
1265 
1266   prop_dialog = table->prop_dialog;
1267   gtklist = GTK_LIST (prop_dialog->attributes_list);
1268 
1269   if (gtklist->selection != NULL)
1270     {
1271       list_item = GTK_WIDGET (gtklist->selection->data);
1272 
1273       i = gtk_list_child_position (gtklist, list_item);
1274       if (i < (g_list_length (gtklist->children) - 1))
1275         {
1276           i++;
1277 
1278           gtk_widget_ref (list_item);
1279           list = g_list_prepend (NULL, list_item);
1280           gtk_list_remove_items (gtklist, list);
1281           gtk_list_insert_items (gtklist, list, i);
1282           gtk_widget_unref (list_item);
1283 
1284           gtk_list_select_child (gtklist, list_item);
1285         }
1286     }
1287 }
1288 
1289 static void
attribute_list_item_destroy_cb(GtkWidget * list_item,gpointer data)1290 attribute_list_item_destroy_cb (GtkWidget * list_item, gpointer data)
1291 {
1292   TableAttribute * attr;
1293 
1294   attr = (TableAttribute *) gtk_object_get_user_data (GTK_OBJECT (list_item));
1295   if (attr != NULL)
1296     table_attribute_free (attr);
1297 }
1298 
1299 static void
destroy_prop_dialog(GtkWidget * widget,gpointer user_data)1300 destroy_prop_dialog (GtkWidget *widget, gpointer user_data)
1301 {
1302   Table * table = (Table *) user_data;
1303 
1304   g_free (table->prop_dialog);
1305   table->prop_dialog = NULL;
1306 }
1307 
1308 /*
1309  * pn: borrowed from the source code of the UML class.
1310  *
1311  * get the contents of a comment text view.
1312  */
get_comment(GtkTextView * view)1313 const gchar * get_comment(GtkTextView *view)
1314 {
1315   GtkTextBuffer * buffer = gtk_text_view_get_buffer(view);
1316   GtkTextIter start;
1317   GtkTextIter end;
1318 
1319   gtk_text_buffer_get_start_iter(buffer, &start);
1320   gtk_text_buffer_get_end_iter(buffer, &end);
1321 
1322   return gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
1323 }
1324 
1325 /*
1326  * pn: "borrowed" from the source code for the UML class.
1327  */
1328 static void
set_comment(GtkTextView * view,gchar * text)1329 set_comment(GtkTextView *view, gchar *text)
1330 {
1331   GtkTextBuffer * buffer = gtk_text_view_get_buffer(view);
1332   GtkTextIter start;
1333   GtkTextIter end;
1334 
1335   gtk_text_buffer_get_start_iter(buffer, &start);
1336   gtk_text_buffer_get_end_iter(buffer, &end);
1337   gtk_text_buffer_delete(buffer,&start,&end);
1338   gtk_text_buffer_get_start_iter(buffer, &start);
1339   gtk_text_buffer_insert( buffer, &start, text, strlen(text));
1340 }
1341 
1342 /**
1343  * pn: "borrowed" from the source code for the UML class object.
1344  */
1345 static void
table_dialog_store_disconnects(TablePropDialog * prop_dialog,ConnectionPoint * cp)1346 table_dialog_store_disconnects (TablePropDialog * prop_dialog,
1347                                 ConnectionPoint * cp)
1348 {
1349   Disconnect *dis;
1350   DiaObject *connected_obj;
1351   GList *list;
1352   gint i;
1353 
1354   list = cp->connected;
1355   while (list != NULL) {
1356     connected_obj = (DiaObject *)list->data;
1357 
1358     for (i=0;i<connected_obj->num_handles;i++) {
1359       if (connected_obj->handles[i]->connected_to == cp) {
1360         dis = g_new0(Disconnect, 1);
1361         dis->cp = cp;
1362         dis->other_object = connected_obj;
1363         dis->other_handle = connected_obj->handles[i];
1364 
1365         prop_dialog->disconnected_connections =
1366           g_list_prepend(prop_dialog->disconnected_connections, dis);
1367       }
1368     }
1369     list = g_list_next(list);
1370   }
1371 }
1372 
1373 
1374 /**
1375  * Return the string representation of the passed attribute to be
1376  * rendered. The returned string is allocated in memory and its the
1377  * caller's responsibility to free this memory if it's not needed
1378  * anymore.
1379  */
1380 static gchar *
table_get_attribute_string(TableAttribute * attrib)1381 table_get_attribute_string (TableAttribute * attrib)
1382 {
1383   int len = 2; /* two chars at the beginning */
1384   gchar * not_null_str = _("not null");
1385   gchar * null_str = _("null");
1386   gchar * is_unique_str = _("unique");
1387   gchar * str = NULL;
1388   gchar * strp = NULL;
1389   gboolean is_nullable = attrib->nullable;
1390   gboolean is_unique = attrib->unique;
1391 
1392   /* first compute how much we need to allocate */
1393 
1394   if (IS_NOT_EMPTY (attrib->name))
1395     len += strlen (attrib->name);
1396   if (IS_NOT_EMPTY (attrib->type))
1397     {
1398       len += strlen (attrib->type);
1399       len += 2; /* comma and a blank between the type and "nullable" */
1400     }
1401   len += strlen (is_nullable ? null_str : not_null_str);
1402   if (IS_NOT_EMPTY (attrib->name))
1403       len += 2; /* colon and a blank after the  name */
1404   if (is_unique)
1405     {
1406       len += 2; /* command and a blank */
1407       len += strlen (is_unique_str);
1408     }
1409 
1410   /* now create the string */
1411 
1412   /* add one gchar for the null termaintor */
1413   strp = str = g_malloc (sizeof(gchar) * (len + 1));
1414   strp = g_stpcpy (strp, (attrib->primary_key == TRUE) ? "# " : "  ");
1415   if (IS_NOT_EMPTY (attrib->name))
1416     {
1417       strp = g_stpcpy (strp, attrib->name);
1418       strp = g_stpcpy (strp, ": ");
1419     }
1420   if (IS_NOT_EMPTY (attrib->type))
1421     {
1422       strp = g_stpcpy (strp, attrib->type);
1423       strp = g_stpcpy (strp, ", ");
1424     }
1425   strp = g_stpcpy (strp, is_nullable ? null_str : not_null_str);
1426   if (is_unique)
1427     {
1428       strp = g_stpcpy (strp, ", ");
1429       strp = g_stpcpy (strp, is_unique_str);
1430     }
1431 
1432   g_assert (strlen (str) == len);
1433 
1434   return str;
1435 }
1436