1 /*
2 * glade-gtk-table.c - GladeWidgetAdaptor for GtkTable widget
3 *
4 * Copyright (C) 2008 Tristan Van Berkom
5 *
6 * Author(s):
7 * Tristan Van Berkom <tvb@gnome.org>
8 *
9 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24 #include <config.h>
25
26 #include <gtk/gtk.h>
27 #include <glib/gi18n-lib.h>
28 #include <string.h>
29
30 #include "glade-fixed.h"
31
32 typedef struct
33 {
34 /* comparable part: */
35 GladeWidget *widget;
36 gint left_attach;
37 gint right_attach;
38 gint top_attach;
39 gint bottom_attach;
40 } GladeGtkTableChild;
41
42 typedef enum
43 {
44 DIR_UP,
45 DIR_DOWN,
46 DIR_LEFT,
47 DIR_RIGHT
48 } GladeTableDir;
49
50 typedef enum
51 {
52 GROUP_ACTION_INSERT_ROW,
53 GROUP_ACTION_INSERT_COLUMN,
54 GROUP_ACTION_REMOVE_COLUMN,
55 GROUP_ACTION_REMOVE_ROW
56 } GroupAction;
57
58 /* Redefine GTK_TABLE() macro, as GtkTable is deprecated */
59 #undef GTK_TABLE
60 #define GTK_TABLE(obj) ((GtkTable *)obj)
61
62 static void
glade_gtk_table_get_child_attachments(GtkWidget * table,GtkWidget * child,GtkTableChild * tchild)63 glade_gtk_table_get_child_attachments (GtkWidget * table,
64 GtkWidget * child,
65 GtkTableChild * tchild)
66 {
67 guint left, right, top, bottom;
68
69 gtk_container_child_get (GTK_CONTAINER (table), child,
70 "left-attach", (guint *) & left,
71 "right-attach", (guint *) & right,
72 "bottom-attach", (guint *) & bottom,
73 "top-attach", (guint *) & top, NULL);
74
75 tchild->widget = child;
76 tchild->left_attach = left;
77 tchild->right_attach = right;
78 tchild->top_attach = top;
79 tchild->bottom_attach = bottom;
80 }
81
82 static gboolean
glade_gtk_table_widget_exceeds_bounds(GtkTable * table,gint n_rows,gint n_cols)83 glade_gtk_table_widget_exceeds_bounds (GtkTable * table, gint n_rows,
84 gint n_cols)
85 {
86 GList *list, *children;
87 gboolean ret = FALSE;
88
89 children = gtk_container_get_children (GTK_CONTAINER (table));
90
91 for (list = children; list && list->data; list = list->next)
92 {
93 GtkTableChild child;
94
95 glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
96 GTK_WIDGET (list->data), &child);
97
98 if (GLADE_IS_PLACEHOLDER (child.widget) == FALSE &&
99 (child.right_attach > n_cols || child.bottom_attach > n_rows))
100 {
101 ret = TRUE;
102 break;
103 }
104 }
105
106 g_list_free (children);
107
108 return ret;
109 }
110
111 #define TABLE_OCCUPIED(occmap, n_columns, col, row) \
112 (occmap)[row * n_columns + col]
113
114 static void
glade_gtk_table_build_occupation_maps(GtkTable * table,guint n_columns,guint n_rows,gchar ** child_map,gpointer ** placeholder_map)115 glade_gtk_table_build_occupation_maps(GtkTable *table, guint n_columns, guint n_rows,
116 gchar **child_map, gpointer **placeholder_map)
117 {
118 guint i, j;
119 GList *list, *children = gtk_container_get_children (GTK_CONTAINER (table));
120
121 *child_map = g_malloc0(n_columns * n_rows * sizeof(gchar)); /* gchar is smaller than gboolean */
122 *placeholder_map = g_malloc0(n_columns * n_rows * sizeof(gpointer));
123
124 for (list = children; list && list->data; list = list->next)
125 {
126 GtkTableChild child;
127
128 glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
129 GTK_WIDGET (list->data), &child);
130
131 if (GLADE_IS_PLACEHOLDER(list->data))
132 {
133 /* assumption: placeholders are always attached to exactly 1 cell */
134 TABLE_OCCUPIED(*placeholder_map, n_columns, child.left_attach, child.top_attach) = list->data;
135 }
136 else
137 {
138 for (i = child.left_attach; i < child.right_attach && i < n_columns; i++)
139 {
140 for (j = child.top_attach; j < child.bottom_attach && j < n_rows; j++)
141 {
142 TABLE_OCCUPIED(*child_map, n_columns, i, j) = 1;
143 }
144 }
145 }
146 }
147 g_list_free (children);
148 }
149
150 static void
glade_gtk_table_refresh_placeholders(GtkTable * table)151 glade_gtk_table_refresh_placeholders (GtkTable * table)
152 {
153 guint n_columns, n_rows, i, j;
154 gchar *child_map;
155 gpointer *placeholder_map;
156
157 g_object_get (table, "n-columns", &n_columns, "n-rows", &n_rows, NULL);
158 glade_gtk_table_build_occupation_maps (table, n_columns, n_rows,
159 &child_map, &placeholder_map);
160
161 for (i = 0; i < n_columns; i++)
162 {
163 for (j = 0; j < n_rows; j++)
164 {
165 gpointer placeholder = TABLE_OCCUPIED(placeholder_map, n_columns, i, j);
166
167 if (TABLE_OCCUPIED(child_map, n_columns, i, j))
168 {
169 if (placeholder)
170 {
171 gtk_container_remove (GTK_CONTAINER (table),
172 GTK_WIDGET (placeholder));
173 }
174 }
175 else
176 {
177 if (!placeholder)
178 {
179 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
180 gtk_table_attach_defaults (table,
181 glade_placeholder_new (),
182 i, i + 1, j, j + 1);
183 G_GNUC_END_IGNORE_DEPRECATIONS;
184 }
185 }
186 }
187 }
188 g_free(child_map);
189 g_free(placeholder_map);
190
191 if (gtk_widget_get_realized (GTK_WIDGET (table)))
192 gtk_container_check_resize (GTK_CONTAINER (table));
193 }
194
195 static void
gtk_table_children_callback(GtkWidget * widget,gpointer client_data)196 gtk_table_children_callback (GtkWidget * widget, gpointer client_data)
197 {
198 GList **children;
199
200 children = (GList **) client_data;
201 *children = g_list_prepend (*children, widget);
202 }
203
204 GList *
glade_gtk_table_get_children(GladeWidgetAdaptor * adaptor,GtkContainer * container)205 glade_gtk_table_get_children (GladeWidgetAdaptor * adaptor,
206 GtkContainer * container)
207 {
208 GList *children = NULL;
209
210 gtk_container_forall (container, gtk_table_children_callback, &children);
211
212 /* GtkTable has the children list already reversed */
213 return children;
214 }
215
216 void
glade_gtk_table_add_child(GladeWidgetAdaptor * adaptor,GObject * object,GObject * child)217 glade_gtk_table_add_child (GladeWidgetAdaptor * adaptor,
218 GObject * object, GObject * child)
219 {
220 gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
221
222 glade_gtk_table_refresh_placeholders (GTK_TABLE (object));
223 }
224
225 void
glade_gtk_table_remove_child(GladeWidgetAdaptor * adaptor,GObject * object,GObject * child)226 glade_gtk_table_remove_child (GladeWidgetAdaptor * adaptor,
227 GObject * object, GObject * child)
228 {
229 gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
230
231 glade_gtk_table_refresh_placeholders (GTK_TABLE (object));
232 }
233
234 void
glade_gtk_table_replace_child(GladeWidgetAdaptor * adaptor,GtkWidget * container,GtkWidget * current,GtkWidget * new_widget)235 glade_gtk_table_replace_child (GladeWidgetAdaptor * adaptor,
236 GtkWidget * container,
237 GtkWidget * current, GtkWidget * new_widget)
238 {
239 /* Chain Up */
240 GWA_GET_CLASS
241 (GTK_TYPE_CONTAINER)->replace_child (adaptor,
242 G_OBJECT (container),
243 G_OBJECT (current),
244 G_OBJECT (new_widget));
245
246 /* If we are replacing a GladeWidget, we must refresh placeholders
247 * because the widget may have spanned multiple rows/columns, we must
248 * not do so in the case we are pasting multiple widgets into a table,
249 * where destroying placeholders results in default packing properties
250 * (since the remaining placeholder templates no longer exist, only the
251 * first pasted widget would have proper packing properties).
252 */
253 if (!GLADE_IS_PLACEHOLDER (new_widget))
254 glade_gtk_table_refresh_placeholders (GTK_TABLE (container));
255
256 }
257
258 static void
glade_gtk_table_set_n_common(GObject * object,const GValue * value,gboolean for_rows)259 glade_gtk_table_set_n_common (GObject * object, const GValue * value,
260 gboolean for_rows)
261 {
262 GladeWidget *widget;
263 GtkTable *table;
264 guint new_size, old_size, n_columns, n_rows;
265
266 table = GTK_TABLE (object);
267
268 g_object_get (table, "n-columns", &n_columns, "n-rows", &n_rows, NULL);
269
270 new_size = g_value_get_uint (value);
271 old_size = for_rows ? n_rows : n_columns;
272
273 if (new_size < 1)
274 return;
275
276 if (glade_gtk_table_widget_exceeds_bounds
277 (table, for_rows ? new_size : n_rows, for_rows ? n_columns : new_size))
278 /* Refuse to shrink if it means orphaning widgets */
279 return;
280
281 widget = glade_widget_get_from_gobject (GTK_WIDGET (table));
282 g_return_if_fail (widget != NULL);
283
284 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
285 if (for_rows)
286 gtk_table_resize (table, new_size, n_columns);
287 else
288 gtk_table_resize (table, n_rows, new_size);
289 G_GNUC_END_IGNORE_DEPRECATIONS;
290
291 /* Fill table with placeholders */
292 glade_gtk_table_refresh_placeholders (table);
293
294 if (new_size < old_size)
295 {
296 /* Remove from the bottom up */
297 GList *list, *children;
298 GList *list_to_free = NULL;
299
300 children = gtk_container_get_children (GTK_CONTAINER (table));
301
302 for (list = children; list && list->data; list = list->next)
303 {
304 GtkTableChild child;
305 guint start, end;
306
307 glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
308 GTK_WIDGET (list->data),
309 &child);
310
311 start = for_rows ? child.top_attach : child.left_attach;
312 end = for_rows ? child.bottom_attach : child.right_attach;
313
314 /* We need to completely remove it */
315 if (start >= new_size)
316 {
317 list_to_free = g_list_prepend (list_to_free, child.widget);
318 continue;
319 }
320
321 /* If the widget spans beyond the new border,
322 * we should resize it to fit on the new table */
323 if (end > new_size)
324 gtk_container_child_set
325 (GTK_CONTAINER (table), GTK_WIDGET (child.widget),
326 for_rows ? "bottom_attach" : "right_attach", new_size, NULL);
327 }
328
329 g_list_free (children);
330
331 if (list_to_free)
332 {
333 for (list = g_list_first (list_to_free);
334 list && list->data; list = list->next)
335 {
336 g_object_ref (G_OBJECT (list->data));
337 gtk_container_remove (GTK_CONTAINER (table),
338 GTK_WIDGET (list->data));
339 /* This placeholder is no longer valid, force destroy */
340 gtk_widget_destroy (GTK_WIDGET (list->data));
341 }
342 g_list_free (list_to_free);
343 }
344
345 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
346 gtk_table_resize (table,
347 for_rows ? new_size : n_rows,
348 for_rows ? n_columns : new_size);
349 G_GNUC_END_IGNORE_DEPRECATIONS;
350 }
351 }
352
353 void
glade_gtk_table_set_property(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * id,const GValue * value)354 glade_gtk_table_set_property (GladeWidgetAdaptor * adaptor,
355 GObject * object,
356 const gchar * id, const GValue * value)
357 {
358 if (!strcmp (id, "n-rows"))
359 glade_gtk_table_set_n_common (object, value, TRUE);
360 else if (!strcmp (id, "n-columns"))
361 glade_gtk_table_set_n_common (object, value, FALSE);
362 else
363 GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
364 id, value);
365 }
366
367 static gboolean
glade_gtk_table_verify_n_common(GObject * object,const GValue * value,gboolean for_rows)368 glade_gtk_table_verify_n_common (GObject * object, const GValue * value,
369 gboolean for_rows)
370 {
371 GtkTable *table = GTK_TABLE (object);
372 guint n_columns, n_rows, new_size = g_value_get_uint (value);
373
374 g_object_get (table, "n-columns", &n_columns, "n-rows", &n_rows, NULL);
375
376 if (glade_gtk_table_widget_exceeds_bounds
377 (table, for_rows ? new_size : n_rows, for_rows ? n_columns : new_size))
378 /* Refuse to shrink if it means orphaning widgets */
379 return FALSE;
380
381 return TRUE;
382 }
383
384 gboolean
glade_gtk_table_verify_property(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * id,const GValue * value)385 glade_gtk_table_verify_property (GladeWidgetAdaptor * adaptor,
386 GObject * object,
387 const gchar * id, const GValue * value)
388 {
389 if (!strcmp (id, "n-rows"))
390 return glade_gtk_table_verify_n_common (object, value, TRUE);
391 else if (!strcmp (id, "n-columns"))
392 return glade_gtk_table_verify_n_common (object, value, FALSE);
393 else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
394 GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
395 id, value);
396
397 return TRUE;
398 }
399
400 void
glade_gtk_table_set_child_property(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child,const gchar * property_name,GValue * value)401 glade_gtk_table_set_child_property (GladeWidgetAdaptor * adaptor,
402 GObject * container,
403 GObject * child,
404 const gchar * property_name, GValue * value)
405 {
406 GWA_GET_CLASS
407 (GTK_TYPE_CONTAINER)->child_set_property (adaptor,
408 container, child,
409 property_name, value);
410
411 if (strcmp (property_name, "bottom-attach") == 0 ||
412 strcmp (property_name, "left-attach") == 0 ||
413 strcmp (property_name, "right-attach") == 0 ||
414 strcmp (property_name, "top-attach") == 0)
415 {
416 /* Refresh placeholders */
417 glade_gtk_table_refresh_placeholders (GTK_TABLE (container));
418 }
419
420 }
421
422 static gboolean
glade_gtk_table_verify_attach_common(GObject * object,GValue * value,guint * val,const gchar * prop,guint * prop_val,const gchar * parent_prop,guint * parent_val)423 glade_gtk_table_verify_attach_common (GObject * object,
424 GValue * value,
425 guint * val,
426 const gchar * prop,
427 guint * prop_val,
428 const gchar * parent_prop,
429 guint * parent_val)
430 {
431 GladeWidget *widget, *parent;
432
433 widget = glade_widget_get_from_gobject (object);
434 g_return_val_if_fail (GLADE_IS_WIDGET (widget), TRUE);
435 parent = glade_widget_get_parent (widget);
436 g_return_val_if_fail (GLADE_IS_WIDGET (parent), TRUE);
437
438 *val = g_value_get_uint (value);
439 glade_widget_property_get (widget, prop, prop_val);
440 glade_widget_property_get (parent, parent_prop, parent_val);
441
442 return FALSE;
443 }
444
445 static gboolean
glade_gtk_table_verify_left_top_attach(GObject * object,GValue * value,const gchar * prop,const gchar * parent_prop)446 glade_gtk_table_verify_left_top_attach (GObject * object,
447 GValue * value,
448 const gchar * prop,
449 const gchar * parent_prop)
450 {
451 guint val, prop_val, parent_val;
452
453 if (glade_gtk_table_verify_attach_common (object, value, &val,
454 prop, &prop_val,
455 parent_prop, &parent_val))
456 return FALSE;
457
458 if (val >= parent_val || val >= prop_val)
459 return FALSE;
460
461 return TRUE;
462 }
463
464 static gboolean
glade_gtk_table_verify_right_bottom_attach(GObject * object,GValue * value,const gchar * prop,const gchar * parent_prop)465 glade_gtk_table_verify_right_bottom_attach (GObject * object,
466 GValue * value,
467 const gchar * prop,
468 const gchar * parent_prop)
469 {
470 guint val, prop_val, parent_val;
471
472 if (glade_gtk_table_verify_attach_common (object, value, &val,
473 prop, &prop_val,
474 parent_prop, &parent_val))
475 return FALSE;
476
477 if (val <= prop_val || val > parent_val)
478 return FALSE;
479
480 return TRUE;
481 }
482
483 gboolean
glade_gtk_table_child_verify_property(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child,const gchar * id,GValue * value)484 glade_gtk_table_child_verify_property (GladeWidgetAdaptor * adaptor,
485 GObject * container,
486 GObject * child,
487 const gchar * id, GValue * value)
488 {
489 if (!strcmp (id, "left-attach"))
490 return glade_gtk_table_verify_left_top_attach (child,
491 value,
492 "right-attach", "n-columns");
493 else if (!strcmp (id, "right-attach"))
494 return glade_gtk_table_verify_right_bottom_attach (child,
495 value,
496 "left-attach",
497 "n-columns");
498 else if (!strcmp (id, "top-attach"))
499 return glade_gtk_table_verify_left_top_attach (child,
500 value,
501 "bottom-attach", "n-rows");
502 else if (!strcmp (id, "bottom-attach"))
503 return glade_gtk_table_verify_right_bottom_attach (child,
504 value,
505 "top-attach", "n-rows");
506 else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_verify_property)
507 GWA_GET_CLASS
508 (GTK_TYPE_CONTAINER)->child_verify_property (adaptor,
509 container, child,
510 id, value);
511
512 return TRUE;
513 }
514
515 static void
glade_gtk_table_child_insert_remove_action(GladeWidgetAdaptor * adaptor,GObject * container,GObject * object,GroupAction group_action,const gchar * n_row_col,const gchar * attach1,const gchar * attach2,gboolean remove,gboolean after)516 glade_gtk_table_child_insert_remove_action (GladeWidgetAdaptor *adaptor,
517 GObject *container,
518 GObject *object,
519 GroupAction group_action,
520 const gchar *n_row_col,
521 const gchar *attach1, /* should be smaller (top/left) attachment */
522 const gchar *attach2, /* should be larger (bot/right) attachment */
523 gboolean remove,
524 gboolean after)
525 {
526 GladeWidget *parent;
527 GList *children, *l;
528 gint child_pos, size, offset;
529
530 gtk_container_child_get (GTK_CONTAINER (container),
531 GTK_WIDGET (object),
532 after ? attach2 : attach1, &child_pos, NULL);
533
534 parent = glade_widget_get_from_gobject (container);
535 switch (group_action)
536 {
537 case GROUP_ACTION_INSERT_ROW:
538 glade_command_push_group (_("Insert Row on %s"), glade_widget_get_name (parent));
539 break;
540 case GROUP_ACTION_INSERT_COLUMN:
541 glade_command_push_group (_("Insert Column on %s"), glade_widget_get_name (parent));
542 break;
543 case GROUP_ACTION_REMOVE_COLUMN:
544 glade_command_push_group (_("Remove Column on %s"), glade_widget_get_name (parent));
545 break;
546 case GROUP_ACTION_REMOVE_ROW:
547 glade_command_push_group (_("Remove Row on %s"), glade_widget_get_name (parent));
548 break;
549 default:
550 g_assert_not_reached ();
551 }
552
553 children = glade_widget_adaptor_get_children (adaptor, container);
554 /* Make sure widgets does not get destroyed */
555 g_list_foreach (children, (GFunc) g_object_ref, NULL);
556
557 glade_widget_property_get (parent, n_row_col, &size);
558
559 if (remove)
560 {
561 GList *del = NULL;
562 /* Remove children first */
563 for (l = children; l; l = g_list_next (l))
564 {
565 GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
566 gint pos1, pos2;
567
568 /* Skip placeholders */
569 if (gchild == NULL)
570 continue;
571
572 glade_widget_pack_property_get (gchild, attach1, &pos1);
573 glade_widget_pack_property_get (gchild, attach2, &pos2);
574 if ((pos1 + 1 == pos2) && ((after ? pos2 : pos1) == child_pos))
575 {
576 del = g_list_prepend (del, gchild);
577 }
578 }
579 if (del)
580 {
581 glade_command_delete (del);
582 g_list_free (del);
583 }
584 offset = -1;
585 }
586 else
587 {
588 /* Expand the table */
589 glade_command_set_property (glade_widget_get_property (parent, n_row_col),
590 size + 1);
591 offset = 1;
592 }
593
594 /* Reorder children */
595 for (l = children; l; l = g_list_next (l))
596 {
597 GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
598 gint pos;
599
600 /* Skip placeholders */
601 if (gchild == NULL)
602 continue;
603
604 /* if removing, do top/left before bot/right */
605 if (remove)
606 {
607 /* adjust top-left attachment */
608 glade_widget_pack_property_get (gchild, attach1, &pos);
609 if (pos > child_pos || (after && pos == child_pos))
610 {
611 glade_command_set_property (glade_widget_get_pack_property
612 (gchild, attach1), pos + offset);
613 }
614
615 /* adjust bottom-right attachment */
616 glade_widget_pack_property_get (gchild, attach2, &pos);
617 if (pos > child_pos || (after && pos == child_pos))
618 {
619 glade_command_set_property (glade_widget_get_pack_property
620 (gchild, attach2), pos + offset);
621 }
622
623 }
624 /* if inserting, do bot/right before top/left */
625 else
626 {
627 /* adjust bottom-right attachment */
628 glade_widget_pack_property_get (gchild, attach2, &pos);
629 if (pos > child_pos)
630 {
631 glade_command_set_property (glade_widget_get_pack_property
632 (gchild, attach2), pos + offset);
633 }
634
635 /* adjust top-left attachment */
636 glade_widget_pack_property_get (gchild, attach1, &pos);
637 if (pos >= child_pos)
638 {
639 glade_command_set_property (glade_widget_get_pack_property
640 (gchild, attach1), pos + offset);
641 }
642 }
643 }
644
645 if (remove)
646 {
647 /* Shrink the table */
648 glade_command_set_property (glade_widget_get_property (parent, n_row_col),
649 size - 1);
650 }
651
652 g_list_foreach (children, (GFunc) g_object_unref, NULL);
653 g_list_free (children);
654
655 glade_command_pop_group ();
656 }
657
658 void
glade_gtk_table_child_action_activate(GladeWidgetAdaptor * adaptor,GObject * container,GObject * object,const gchar * action_path)659 glade_gtk_table_child_action_activate (GladeWidgetAdaptor * adaptor,
660 GObject * container,
661 GObject * object,
662 const gchar * action_path)
663 {
664 if (strcmp (action_path, "insert_row/after") == 0)
665 {
666 glade_gtk_table_child_insert_remove_action (adaptor, container, object,
667 GROUP_ACTION_INSERT_ROW,
668 "n-rows", "top-attach",
669 "bottom-attach", FALSE, TRUE);
670 }
671 else if (strcmp (action_path, "insert_row/before") == 0)
672 {
673 glade_gtk_table_child_insert_remove_action (adaptor, container, object,
674 GROUP_ACTION_INSERT_ROW,
675 "n-rows", "top-attach",
676 "bottom-attach",
677 FALSE, FALSE);
678 }
679 else if (strcmp (action_path, "insert_column/after") == 0)
680 {
681 glade_gtk_table_child_insert_remove_action (adaptor, container, object,
682 GROUP_ACTION_INSERT_COLUMN,
683 "n-columns", "left-attach",
684 "right-attach", FALSE, TRUE);
685 }
686 else if (strcmp (action_path, "insert_column/before") == 0)
687 {
688 glade_gtk_table_child_insert_remove_action (adaptor, container, object,
689 GROUP_ACTION_INSERT_COLUMN,
690 "n-columns", "left-attach",
691 "right-attach", FALSE, FALSE);
692 }
693 else if (strcmp (action_path, "remove_column") == 0)
694 {
695 glade_gtk_table_child_insert_remove_action (adaptor, container, object,
696 GROUP_ACTION_REMOVE_COLUMN,
697 "n-columns", "left-attach",
698 "right-attach", TRUE, FALSE);
699 }
700 else if (strcmp (action_path, "remove_row") == 0)
701 {
702 glade_gtk_table_child_insert_remove_action (adaptor, container, object,
703 GROUP_ACTION_REMOVE_ROW,
704 "n-rows", "top-attach",
705 "bottom-attach", TRUE, FALSE);
706 }
707 else
708 GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
709 container,
710 object,
711 action_path);
712 }
713