1 /*
2 * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include <gtk/gtk.h>
21 #include <libgda/libgda.h>
22 #include "browser-canvas.h"
23 #include "browser-canvas-priv.h"
24 #include "browser-canvas-table.h"
25 #include "browser-canvas-column.h"
26 #include <glib/gi18n-lib.h>
27 #include <string.h>
28
29 static void browser_canvas_table_class_init (BrowserCanvasTableClass *class);
30 static void browser_canvas_table_init (BrowserCanvasTable *drag);
31 static void browser_canvas_table_dispose (GObject *object);
32 static void browser_canvas_table_finalize (GObject *object);
33
34 static void browser_canvas_table_set_property (GObject *object,
35 guint param_id,
36 const GValue *value,
37 GParamSpec *pspec);
38 static void browser_canvas_table_get_property (GObject *object,
39 guint param_id,
40 GValue *value,
41 GParamSpec *pspec);
42
43 static void browser_canvas_table_drag_data_get (BrowserCanvasItem *citem, GdkDragContext *drag_context,
44 GtkSelectionData *data, guint info, guint time);
45 static void browser_canvas_table_set_selected (BrowserCanvasItem *citem, gboolean selected);
46
47 static xmlNodePtr browser_canvas_table_serialize (BrowserCanvasItem *citem);
48
49 enum
50 {
51 PROP_0,
52 PROP_META_STRUCT,
53 PROP_TABLE,
54 PROP_MENU_FUNC
55 };
56
57 struct _BrowserCanvasTablePrivate
58 {
59 GdaMetaStruct *mstruct;
60 GdaMetaTable *table;
61
62 /* UI building information */
63 GSList *column_items; /* list of GooCanvasItem for the columns */
64 GSList *other_items; /* list of GooCanvasItem for other purposes */
65 gdouble *column_ypos; /* array for each column's Y position in this canvas group */
66 GtkWidget *(*popup_menu_func) (BrowserCanvasTable *ce);
67
68 GooCanvasItem *selection_mark;
69 };
70
71 /* get a pointer to the parents to be able to call their destructor */
72 static GObjectClass *table_parent_class = NULL;
73
74 GType
browser_canvas_table_get_type(void)75 browser_canvas_table_get_type (void)
76 {
77 static GType type = 0;
78
79 if (G_UNLIKELY (type == 0)) {
80 static const GTypeInfo info = {
81 sizeof (BrowserCanvasTableClass),
82 (GBaseInitFunc) NULL,
83 (GBaseFinalizeFunc) NULL,
84 (GClassInitFunc) browser_canvas_table_class_init,
85 NULL,
86 NULL,
87 sizeof (BrowserCanvasTable),
88 0,
89 (GInstanceInitFunc) browser_canvas_table_init,
90 0
91 };
92
93 type = g_type_register_static (TYPE_BROWSER_CANVAS_ITEM, "BrowserCanvasTable", &info, 0);
94 }
95
96 return type;
97 }
98
99
100 static void
browser_canvas_table_class_init(BrowserCanvasTableClass * class)101 browser_canvas_table_class_init (BrowserCanvasTableClass *class)
102 {
103 GObjectClass *object_class = G_OBJECT_CLASS (class);
104 BrowserCanvasItemClass *iclass = BROWSER_CANVAS_ITEM_CLASS (class);
105
106 table_parent_class = g_type_class_peek_parent (class);
107 iclass->drag_data_get = browser_canvas_table_drag_data_get;
108 iclass->set_selected = browser_canvas_table_set_selected;
109 iclass->serialize = browser_canvas_table_serialize;
110
111 object_class->dispose = browser_canvas_table_dispose;
112 object_class->finalize = browser_canvas_table_finalize;
113
114 /* Properties */
115 object_class->set_property = browser_canvas_table_set_property;
116 object_class->get_property = browser_canvas_table_get_property;
117
118 g_object_class_install_property
119 (object_class, PROP_META_STRUCT,
120 g_param_spec_object ("meta-struct", NULL, NULL,
121 GDA_TYPE_META_STRUCT,
122 (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
123 g_object_class_install_property
124 (object_class, PROP_TABLE,
125 g_param_spec_pointer ("table", NULL, NULL,
126 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
127 g_object_class_install_property
128 (object_class, PROP_MENU_FUNC,
129 g_param_spec_pointer ("popup_menu_func", "Popup menu function",
130 "Function to create a popup menu on each BrowserCanvasTable",
131 G_PARAM_WRITABLE));
132 }
133
134 static gboolean button_press_event_cb (BrowserCanvasTable *ce, GooCanvasItem *target_item, GdkEventButton *event,
135 gpointer unused_data);
136
137 static void
browser_canvas_table_init(BrowserCanvasTable * table)138 browser_canvas_table_init (BrowserCanvasTable *table)
139 {
140 table->priv = g_new0 (BrowserCanvasTablePrivate, 1);
141 table->priv->mstruct = NULL;
142 table->priv->table = NULL;
143 table->priv->column_ypos = NULL;
144 table->priv->popup_menu_func = NULL;
145
146 table->priv->selection_mark = NULL;
147
148 g_signal_connect (G_OBJECT (table), "button-press-event",
149 G_CALLBACK (button_press_event_cb), NULL);
150 }
151
152 static void clean_items (BrowserCanvasTable *ce);
153 static void create_items (BrowserCanvasTable *ce);
154
155 static void
browser_canvas_table_dispose(GObject * object)156 browser_canvas_table_dispose (GObject *object)
157 {
158 BrowserCanvasTable *ce;
159
160 g_return_if_fail (IS_BROWSER_CANVAS_TABLE (object));
161
162 ce = BROWSER_CANVAS_TABLE (object);
163
164 /* REM: let the GooCanvas library destroy the items itself */
165 ce->priv->table = NULL;
166 if (ce->priv->mstruct) {
167 g_object_unref (ce->priv->mstruct);
168 ce->priv->mstruct = NULL;
169 }
170
171 /* for the parent class */
172 table_parent_class->dispose (object);
173 }
174
175
176 static void
browser_canvas_table_finalize(GObject * object)177 browser_canvas_table_finalize (GObject *object)
178 {
179 BrowserCanvasTable *ce;
180 g_return_if_fail (object != NULL);
181 g_return_if_fail (IS_BROWSER_CANVAS_TABLE (object));
182
183 ce = BROWSER_CANVAS_TABLE (object);
184 if (ce->priv) {
185 g_slist_free (ce->priv->column_items);
186 g_slist_free (ce->priv->other_items);
187 if (ce->priv->column_ypos)
188 g_free (ce->priv->column_ypos);
189
190 g_free (ce->priv);
191 ce->priv = NULL;
192 }
193
194 /* for the parent class */
195 table_parent_class->finalize (object);
196 }
197
198 static void
browser_canvas_table_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)199 browser_canvas_table_set_property (GObject *object,
200 guint param_id,
201 const GValue *value,
202 GParamSpec *pspec)
203 {
204 BrowserCanvasTable *ce = NULL;
205
206 ce = BROWSER_CANVAS_TABLE (object);
207
208 switch (param_id) {
209 case PROP_META_STRUCT:
210 ce->priv->mstruct = g_value_dup_object (value);
211 break;
212 case PROP_TABLE: {
213 GdaMetaTable *table;
214 table = g_value_get_pointer (value);
215 if (table && (table == ce->priv->table))
216 return;
217
218 if (ce->priv->table) {
219 ce->priv->table = NULL;
220 clean_items (ce);
221 }
222
223 if (table) {
224 ce->priv->table = (GdaMetaTable*) table;
225 create_items (ce);
226 }
227 break;
228 }
229 case PROP_MENU_FUNC:
230 ce->priv->popup_menu_func = (GtkWidget *(*) (BrowserCanvasTable *ce)) g_value_get_pointer (value);
231 break;
232 default:
233 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
234 break;
235 }
236 }
237
238 static void
browser_canvas_table_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)239 browser_canvas_table_get_property (GObject *object,
240 guint param_id,
241 GValue *value,
242 GParamSpec *pspec)
243 {
244 BrowserCanvasTable *ce = NULL;
245
246 ce = BROWSER_CANVAS_TABLE (object);
247
248 switch (param_id) {
249 case PROP_META_STRUCT:
250 g_value_set_object (value, ce->priv->mstruct);
251 break;
252 case PROP_TABLE:
253 g_value_set_pointer (value, ce->priv->table);
254 break;
255 default:
256 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
257 break;
258 }
259 }
260
261 /*
262 * destroy any existing GooCanvasItem obejcts
263 */
264 static void
clean_items(BrowserCanvasTable * ce)265 clean_items (BrowserCanvasTable *ce)
266 {
267 GSList *list;
268 /* destroy all the items in the group */
269 while (ce->priv->column_items)
270 g_object_unref (G_OBJECT (ce->priv->column_items->data));
271
272 for (list = ce->priv->other_items; list; list = list->next)
273 g_object_unref (G_OBJECT (list->data));
274 g_slist_free (ce->priv->other_items);
275 ce->priv->other_items = NULL;
276
277 /* free the columns positions */
278 if (ce->priv->column_ypos) {
279 g_free (ce->priv->column_ypos);
280 ce->priv->column_ypos = NULL;
281 }
282 }
283
284 /*
285 * create new GooCanvasItem objects
286 */
287 static void
create_items(BrowserCanvasTable * ce)288 create_items (BrowserCanvasTable *ce)
289 {
290 GooCanvasItem *item, *frame, *title;
291 gdouble y, ysep;
292 #define HEADER_Y_PAD 3.
293 #define Y_PAD 0.
294 #define X_PAD 3.
295 #define RADIUS_X 5.
296 #define RADIUS_Y 5.
297 #define MIN_HEIGHT 70.
298 #define SELECTION_SIZE 4.
299 GooCanvasBounds border_bounds;
300 GooCanvasBounds bounds;
301 const gchar *cstr;
302 gchar *tmpstr = NULL;
303 GSList *columns, *list;
304 gint column_nb;
305 gdouble column_width;
306
307 clean_items (ce);
308 g_assert (ce->priv->table);
309
310 /* title */
311 cstr = GDA_META_DB_OBJECT (ce->priv->table)->obj_short_name;
312 if (cstr)
313 tmpstr = g_markup_printf_escaped ("<b>%s</b>", cstr);
314 else
315 tmpstr = g_strdup_printf ("<b>%s</b>", _("No name"));
316
317 y = RADIUS_Y;
318 title = goo_canvas_text_new (GOO_CANVAS_ITEM (ce), tmpstr,
319 RADIUS_X + X_PAD, y,
320 -1, GOO_CANVAS_ANCHOR_NORTH_WEST,
321 "font", "Sans 11",
322 "use-markup", TRUE, NULL);
323
324 g_free (tmpstr);
325 goo_canvas_item_get_bounds (title, &bounds);
326 border_bounds = bounds;
327 border_bounds.x1 = 0.;
328 border_bounds.y1 = 0.;
329 y += bounds.y2 - bounds.y1 + HEADER_Y_PAD;
330
331 /* separator's placeholder */
332 ysep = y;
333 y += HEADER_Y_PAD;
334
335 /* columns' vertical position */
336 columns = ce->priv->table->columns;
337 ce->priv->column_ypos = g_new0 (gdouble, g_slist_length (columns) + 1);
338
339 /* columns */
340 for (column_nb = 0, list = columns; list; list = list->next, column_nb++) {
341 ce->priv->column_ypos [column_nb] = y;
342 item = browser_canvas_column_new (GOO_CANVAS_ITEM (ce),
343 ce->priv->mstruct,
344 GDA_META_TABLE_COLUMN (list->data),
345 X_PAD, ce->priv->column_ypos [column_nb], NULL);
346 ce->priv->column_items = g_slist_append (ce->priv->column_items, item);
347 goo_canvas_item_get_bounds (item, &bounds);
348 border_bounds.x1 = MIN (border_bounds.x1, bounds.x1);
349 border_bounds.x2 = MAX (border_bounds.x2, bounds.x2);
350 border_bounds.y1 = MIN (border_bounds.y1, bounds.y1);
351 border_bounds.y2 = MAX (border_bounds.y2, bounds.y2);
352
353 y += bounds.y2 - bounds.y1 + Y_PAD;
354 }
355 if (!columns && (border_bounds.y2 - border_bounds.y1 < MIN_HEIGHT))
356 border_bounds.y2 += MIN_HEIGHT - (border_bounds.y2 - border_bounds.y1);
357
358 /* border */
359 column_width = border_bounds.x2 - border_bounds.x1;
360 border_bounds.y2 += RADIUS_Y;
361 border_bounds.x2 += RADIUS_X;
362 frame = goo_canvas_rect_new (GOO_CANVAS_ITEM (ce), border_bounds.x1, border_bounds.y1,
363 border_bounds.x2, border_bounds.y2,
364 "radius-x", RADIUS_X,
365 "radius-y", RADIUS_Y,
366 "fill-color", "#f8f8f8",
367 NULL);
368 ce->priv->other_items = g_slist_prepend (ce->priv->other_items, frame);
369
370 ce->priv->selection_mark = goo_canvas_rect_new (GOO_CANVAS_ITEM (ce), border_bounds.x1 - SELECTION_SIZE,
371 border_bounds.y1 - SELECTION_SIZE,
372 border_bounds.x2 + 2 * SELECTION_SIZE,
373 border_bounds.y2 + 2 * SELECTION_SIZE,
374 "radius-x", RADIUS_X,
375 "radius-y", RADIUS_Y,
376 "fill-color", "#11d155",//"#ffea08",
377 "stroke-color", "#11d155",//"#ffea08",
378 NULL);
379 g_object_set (G_OBJECT (ce->priv->selection_mark), "visibility", GOO_CANVAS_ITEM_HIDDEN, NULL);
380
381 /* title's background */
382 gchar *cpath;
383 cpath = g_strdup_printf ("M %d %d H %d V %d H %d Z",
384 (gint) border_bounds.x1, (gint) border_bounds.y1,
385 (gint) border_bounds.x2, (gint) ysep,
386 (gint) border_bounds.x1);
387 item = goo_canvas_rect_new (GOO_CANVAS_ITEM (ce), border_bounds.x1, border_bounds.y1,
388 border_bounds.x2, ysep + RADIUS_X,
389 "clip_path", cpath,
390 "radius-x", RADIUS_X,
391 "radius-y", RADIUS_Y,
392 "fill-color", "#aaaaff",
393 NULL);
394 g_free (cpath);
395 goo_canvas_item_lower (item, NULL);
396
397 /* separator */
398 item = goo_canvas_polyline_new_line (GOO_CANVAS_ITEM (ce), border_bounds.x1, ysep, border_bounds.x2, ysep,
399 "close-path", FALSE,
400 "line-width", .7, NULL);
401 ce->priv->other_items = g_slist_prepend (ce->priv->other_items, item);
402
403 goo_canvas_item_lower (frame, NULL);
404 goo_canvas_item_lower (ce->priv->selection_mark, NULL);
405
406 /* setting the columns' background width to be the same for all */
407 for (list = ce->priv->column_items; list; list = list->next)
408 g_object_set (G_OBJECT (list->data), "width", column_width, NULL);
409 }
410
411 static gboolean
button_press_event_cb(BrowserCanvasTable * ce,G_GNUC_UNUSED GooCanvasItem * target_item,GdkEventButton * event,G_GNUC_UNUSED gpointer data)412 button_press_event_cb (BrowserCanvasTable *ce, G_GNUC_UNUSED GooCanvasItem *target_item,
413 GdkEventButton *event,
414 G_GNUC_UNUSED gpointer data)
415 {
416 if ((event->button == 3) && ce->priv->popup_menu_func) {
417 GtkWidget *menu;
418 menu = ce->priv->popup_menu_func (ce);
419 gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
420 NULL, NULL, ((GdkEventButton *)event)->button,
421 ((GdkEventButton *)event)->time);
422 return TRUE;
423 }
424
425 return FALSE;
426 }
427
428 /**
429 * browser_canvas_table_get_column_item
430 * @ce: a #BrowserCanvasTable object
431 * @column: a #GdaMetaTableColumn object
432 *
433 * Get the #BrowserCanvasColumn object representing @column
434 * in @ce.
435 *
436 * Returns: the corresponding #BrowserCanvasColumn
437 */
438 BrowserCanvasColumn *
browser_canvas_table_get_column_item(BrowserCanvasTable * ce,GdaMetaTableColumn * column)439 browser_canvas_table_get_column_item (BrowserCanvasTable *ce, GdaMetaTableColumn *column)
440 {
441 gint pos;
442
443 g_return_val_if_fail (ce && IS_BROWSER_CANVAS_TABLE (ce), NULL);
444 g_return_val_if_fail (ce->priv, NULL);
445 g_return_val_if_fail (ce->priv->table, NULL);
446
447 pos = g_slist_index (ce->priv->table->columns, column);
448 g_return_val_if_fail (pos >= 0, NULL);
449
450 return g_slist_nth_data (ce->priv->column_items, pos);
451 }
452
453
454 /**
455 * browser_canvas_table_get_column_ypos
456 * @ce: a #BrowserCanvasTable object
457 * @column: a #GdaMetaTableColumn object
458 *
459 * Get the Y position of the middle of the #BrowserCanvasColumn object representing @column
460 * in @ce, in @ce's coordinates.
461 *
462 * Returns: the Y coordinate.
463 */
464 gdouble
browser_canvas_table_get_column_ypos(BrowserCanvasTable * ce,GdaMetaTableColumn * column)465 browser_canvas_table_get_column_ypos (BrowserCanvasTable *ce, GdaMetaTableColumn *column)
466 {
467 gint pos;
468
469 g_return_val_if_fail (ce && IS_BROWSER_CANVAS_TABLE (ce), 0.);
470 g_return_val_if_fail (ce->priv, 0.);
471 g_return_val_if_fail (ce->priv->table, 0.);
472 g_return_val_if_fail (ce->priv->column_ypos, 0.);
473
474 pos = g_slist_index (ce->priv->table->columns, column);
475 g_return_val_if_fail (pos >= 0, 0.);
476 return (0.75 * ce->priv->column_ypos[pos+1] + 0.25 * ce->priv->column_ypos[pos]);
477 }
478
479
480 /**
481 * browser_canvas_table_new
482 * @parent: the parent item, or NULL.
483 * @table: a #GdaMetaTable to display
484 * @x: the x coordinate
485 * @y: the y coordinate
486 * @...: optional pairs of property names and values, and a terminating NULL.
487 *
488 * Creates a new canvas item to display the @table table
489 *
490 * Returns: a new #GooCanvasItem object
491 */
492 GooCanvasItem *
browser_canvas_table_new(GooCanvasItem * parent,GdaMetaStruct * mstruct,GdaMetaTable * table,gdouble x,gdouble y,...)493 browser_canvas_table_new (GooCanvasItem *parent, GdaMetaStruct *mstruct, GdaMetaTable *table,
494 gdouble x, gdouble y, ...)
495 {
496 GooCanvasItem *item;
497 const char *first_property;
498 va_list var_args;
499
500 g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
501
502 item = g_object_new (TYPE_BROWSER_CANVAS_TABLE, "meta-struct", mstruct,
503 "allow-move", TRUE,
504 "allow-select", TRUE, NULL);
505
506 if (parent) {
507 goo_canvas_item_add_child (parent, item, -1);
508 g_object_unref (item);
509 }
510
511 g_object_set (item, "table", table, NULL);
512
513 va_start (var_args, y);
514 first_property = va_arg (var_args, char*);
515 if (first_property)
516 g_object_set_valist ((GObject*) item, first_property, var_args);
517 va_end (var_args);
518
519 goo_canvas_item_translate (item, x, y);
520
521 return item;
522 }
523
524 static void
browser_canvas_table_drag_data_get(BrowserCanvasItem * citem,G_GNUC_UNUSED GdkDragContext * drag_context,GtkSelectionData * data,G_GNUC_UNUSED guint info,G_GNUC_UNUSED guint time)525 browser_canvas_table_drag_data_get (BrowserCanvasItem *citem, G_GNUC_UNUSED GdkDragContext *drag_context,
526 GtkSelectionData *data, G_GNUC_UNUSED guint info,
527 G_GNUC_UNUSED guint time)
528 {
529 BrowserCanvasTable *ctable;
530
531 ctable = BROWSER_CANVAS_TABLE (citem);
532 if (!ctable->priv->table)
533 return;
534
535 GdaMetaDbObject *dbo;
536 gchar *str, *tmp1, *tmp2, *tmp3;
537
538 dbo = GDA_META_DB_OBJECT (ctable->priv->table);
539 tmp1 = gda_rfc1738_encode (dbo->obj_schema);
540 tmp2 = gda_rfc1738_encode (dbo->obj_name);
541 tmp3 = gda_rfc1738_encode (dbo->obj_short_name);
542 str = g_strdup_printf ("OBJ_TYPE=table;OBJ_SCHEMA=%s;OBJ_NAME=%s;OBJ_SHORT_NAME=%s", tmp1, tmp2, tmp3);
543 g_free (tmp1);
544 g_free (tmp2);
545 g_free (tmp3);
546 gtk_selection_data_set (data, gtk_selection_data_get_target (data), 8, (guchar*) str, strlen (str));
547 g_free (str);
548 }
549
550 static void
browser_canvas_table_set_selected(BrowserCanvasItem * citem,gboolean selected)551 browser_canvas_table_set_selected (BrowserCanvasItem *citem, gboolean selected)
552 {
553 g_object_set (G_OBJECT (BROWSER_CANVAS_TABLE (citem)->priv->selection_mark),
554 "visibility", selected ? GOO_CANVAS_ITEM_VISIBLE : GOO_CANVAS_ITEM_HIDDEN, NULL);
555 }
556
557 static xmlNodePtr
browser_canvas_table_serialize(BrowserCanvasItem * citem)558 browser_canvas_table_serialize (BrowserCanvasItem *citem)
559 {
560 BrowserCanvasTable *ctable;
561
562 ctable = BROWSER_CANVAS_TABLE (citem);
563 if (!ctable->priv->table)
564 return NULL;
565
566 GdaMetaDbObject *dbo;
567 xmlNodePtr node;
568 GooCanvasBounds bounds;
569 gchar *str;
570
571 dbo = GDA_META_DB_OBJECT (ctable->priv->table);
572 node = xmlNewNode (NULL, BAD_CAST "table");
573 xmlSetProp (node, BAD_CAST "schema", BAD_CAST (dbo->obj_schema));
574 xmlSetProp (node, BAD_CAST "name", BAD_CAST (dbo->obj_name));
575 goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (citem), &bounds);
576 str = g_strdup_printf ("%.1f", bounds.x1);
577 xmlSetProp (node, BAD_CAST "x", BAD_CAST str);
578 g_free (str);
579 str = g_strdup_printf ("%.1f", bounds.y1);
580 xmlSetProp (node, BAD_CAST "y", BAD_CAST str);
581 g_free (str);
582
583 return node;
584 }
585
586 /**
587 * browser_canvas_table_get_anchor_bounds
588 *
589 * Get the bounds to be used to compute anchors, ie. without the selection mark or any other
590 * artefact not part of the table's rectangle.
591 */
592 void
browser_canvas_table_get_anchor_bounds(BrowserCanvasTable * ce,GooCanvasBounds * bounds)593 browser_canvas_table_get_anchor_bounds (BrowserCanvasTable *ce, GooCanvasBounds *bounds)
594 {
595 g_return_if_fail (IS_BROWSER_CANVAS_TABLE (ce));
596 g_return_if_fail (bounds);
597
598 goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (ce), bounds);
599 bounds->x1 += SELECTION_SIZE;
600 bounds->y1 += SELECTION_SIZE;
601 bounds->x2 -= SELECTION_SIZE;
602 bounds->y2 -= SELECTION_SIZE;
603 }
604