1 /* 2 * Copyright (C) 2009 - 2012 Vivien Malerba <malerba@gnome-db.org> 3 * Copyright (C) 2010 David King <davidk@openismus.com> 4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the 18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22 #include <stdlib.h> 23 #include <libgda/libgda.h> 24 #include <glib/gi18n-lib.h> 25 #include "gdaui-entry-combo.h" 26 #include "gdaui-data-cell-renderer-combo.h" 27 #include "marshallers/gdaui-custom-marshal.h" 28 #include <libgda-ui/gdaui-combo.h> 29 #include <libgda-ui/gdaui-data-entry.h> 30 #include <libgda/gda-enum-types.h> 31 #include "gdaui-data-cell-renderer-util.h" 32 33 #define GDAUI_DATA_CELL_RENDERER_COMBO_PATH "gdaui-data-cell-renderer-combo-path" 34 35 static void gdaui_data_cell_renderer_combo_init (GdauiDataCellRendererCombo *celltext); 36 static void gdaui_data_cell_renderer_combo_class_init (GdauiDataCellRendererComboClass *class); 37 static void gdaui_data_cell_renderer_combo_dispose (GObject *object); 38 static void gdaui_data_cell_renderer_combo_finalize (GObject *object); 39 40 static void gdaui_data_cell_renderer_combo_get_property (GObject *object, 41 guint param_id, 42 GValue *value, 43 GParamSpec *pspec); 44 static void gdaui_data_cell_renderer_combo_set_property (GObject *object, 45 guint param_id, 46 const GValue *value, 47 GParamSpec *pspec); 48 static void gdaui_data_cell_renderer_combo_get_size (GtkCellRenderer *cell, 49 GtkWidget *widget, 50 const GdkRectangle *cell_area, 51 gint *x_offset, 52 gint *y_offset, 53 gint *width, 54 gint *height); 55 static void gdaui_data_cell_renderer_combo_render (GtkCellRenderer *cell, 56 cairo_t *cr, 57 GtkWidget *widget, 58 const GdkRectangle *background_area, 59 const GdkRectangle *cell_area, 60 GtkCellRendererState flags); 61 62 static GtkCellEditable *gdaui_data_cell_renderer_combo_start_editing (GtkCellRenderer *cell, 63 GdkEvent *event, 64 GtkWidget *widget, 65 const gchar *path, 66 const GdkRectangle *background_area, 67 const GdkRectangle *cell_area, 68 GtkCellRendererState flags); 69 70 enum { 71 CHANGED, 72 LAST_SIGNAL 73 }; 74 75 enum { 76 PROP_0, 77 PROP_VALUES, 78 PROP_VALUES_DISPLAY, 79 PROP_VALUE_ATTRIBUTES, 80 PROP_TO_BE_DELETED, 81 PROP_SET_DEFAULT_IF_INVALID, 82 PROP_SHOW_EXPANDER, 83 PROP_PARAMLIST, 84 PROP_PARAMLISTSOURCE 85 }; 86 87 struct _GdauiDataCellRendererComboPrivate 88 { 89 GdauiSet *paramlist; 90 GdauiSetSource *source; 91 guint focus_out_id; 92 guint attributes; 93 gboolean to_be_deleted; 94 gboolean set_default_if_invalid; 95 gboolean show_expander; 96 gboolean invalid; 97 }; 98 99 100 static GObjectClass *parent_class = NULL; 101 static guint text_cell_renderer_combo_signals [LAST_SIGNAL] = { 0 }; 102 103 GType 104 gdaui_data_cell_renderer_combo_get_type (void) 105 { 106 static GType cell_text_type = 0; 107 108 if (!cell_text_type) { 109 static const GTypeInfo cell_text_info = { 110 sizeof (GdauiDataCellRendererComboClass), 111 NULL, /* base_init */ 112 NULL, /* base_finalize */ 113 (GClassInitFunc) gdaui_data_cell_renderer_combo_class_init, 114 NULL, /* class_finalize */ 115 NULL, /* class_data */ 116 sizeof (GdauiDataCellRendererCombo), 117 0, /* n_preallocs */ 118 (GInstanceInitFunc) gdaui_data_cell_renderer_combo_init, 119 0 120 }; 121 122 cell_text_type = 123 g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT, "GdauiDataCellRendererCombo", 124 &cell_text_info, 0); 125 } 126 127 return cell_text_type; 128 } 129 130 static void 131 gdaui_data_cell_renderer_combo_init (GdauiDataCellRendererCombo *datacell) 132 { 133 g_object_set ((GObject*) datacell, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); 134 datacell->priv = g_new0 (GdauiDataCellRendererComboPrivate, 1); 135 datacell->priv->attributes = 0; 136 datacell->priv->set_default_if_invalid = FALSE; 137 datacell->priv->show_expander = TRUE; 138 } 139 140 static void 141 gdaui_data_cell_renderer_combo_class_init (GdauiDataCellRendererComboClass *class) 142 { 143 GObjectClass *object_class = G_OBJECT_CLASS (class); 144 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class); 145 146 parent_class = g_type_class_peek_parent (class); 147 148 object_class->dispose = gdaui_data_cell_renderer_combo_dispose; 149 object_class->finalize = gdaui_data_cell_renderer_combo_finalize; 150 151 object_class->get_property = gdaui_data_cell_renderer_combo_get_property; 152 object_class->set_property = gdaui_data_cell_renderer_combo_set_property; 153 154 cell_class->get_size = gdaui_data_cell_renderer_combo_get_size; 155 cell_class->render = gdaui_data_cell_renderer_combo_render; 156 cell_class->start_editing = gdaui_data_cell_renderer_combo_start_editing; 157 158 g_object_class_install_property (object_class, 159 PROP_VALUES, 160 g_param_spec_pointer ("values", 161 _("Values limited to PK fields"), 162 _("GList of GValue to render, limited to PK fields"), 163 G_PARAM_WRITABLE)); 164 165 g_object_class_install_property (object_class, 166 PROP_VALUES_DISPLAY, 167 g_param_spec_pointer ("values-display", 168 _("Values"), 169 _("GList of GValue to render, not limited to PK fields "), 170 G_PARAM_WRITABLE)); 171 172 g_object_class_install_property (object_class, 173 PROP_VALUE_ATTRIBUTES, 174 g_param_spec_flags ("value-attributes", NULL, NULL, GDA_TYPE_VALUE_ATTRIBUTE, 175 GDA_VALUE_ATTR_NONE, G_PARAM_READWRITE)); 176 177 g_object_class_install_property (object_class, 178 PROP_TO_BE_DELETED, 179 g_param_spec_boolean ("to-be-deleted", NULL, NULL, FALSE, 180 G_PARAM_WRITABLE)); 181 g_object_class_install_property (object_class, 182 PROP_SHOW_EXPANDER, 183 g_param_spec_boolean ("show-expander", NULL, NULL, FALSE, 184 G_PARAM_WRITABLE)); 185 186 g_object_class_install_property (object_class, PROP_SET_DEFAULT_IF_INVALID, 187 g_param_spec_boolean ("set-default-if-invalid", NULL, NULL, FALSE, 188 (G_PARAM_READABLE | G_PARAM_WRITABLE))); 189 190 g_object_class_install_property (object_class, PROP_PARAMLIST, 191 g_param_spec_object ("data-set", NULL, NULL, GDAUI_TYPE_SET, 192 (G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE))); 193 194 /* Ideally, GdaSetSource would be a boxed type, but it is not yet, so we use g_param_spec_pointer(). */ 195 g_object_class_install_property (object_class, PROP_PARAMLISTSOURCE, 196 g_param_spec_pointer ("data-set-source", NULL, NULL, 197 (G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE))); 198 199 text_cell_renderer_combo_signals [CHANGED] = 200 g_signal_new ("changed", 201 G_OBJECT_CLASS_TYPE (object_class), 202 G_SIGNAL_RUN_LAST, 203 G_STRUCT_OFFSET (GdauiDataCellRendererComboClass, changed), 204 NULL, NULL, 205 _gdaui_marshal_VOID__STRING_SLIST_SLIST, 206 G_TYPE_NONE, 3, 207 G_TYPE_STRING, 208 G_TYPE_POINTER, 209 G_TYPE_POINTER); 210 211 } 212 213 static void 214 gdaui_data_cell_renderer_combo_dispose (GObject *object) 215 { 216 GdauiDataCellRendererCombo *datacell = GDAUI_DATA_CELL_RENDERER_COMBO (object); 217 218 if (datacell->priv->paramlist) { 219 g_object_unref (datacell->priv->paramlist); 220 datacell->priv->paramlist = NULL; 221 } 222 223 /* parent class */ 224 parent_class->dispose (object); 225 } 226 227 static void 228 gdaui_data_cell_renderer_combo_finalize (GObject *object) 229 { 230 GdauiDataCellRendererCombo *datacell = GDAUI_DATA_CELL_RENDERER_COMBO (object); 231 232 if (datacell->priv) { 233 g_free (datacell->priv); 234 datacell->priv = NULL; 235 } 236 237 /* parent class */ 238 parent_class->finalize (object); 239 } 240 241 242 static void 243 gdaui_data_cell_renderer_combo_get_property (GObject *object, 244 guint param_id, 245 GValue *value, 246 GParamSpec *pspec) 247 { 248 GdauiDataCellRendererCombo *datacell = GDAUI_DATA_CELL_RENDERER_COMBO (object); 249 250 switch (param_id) { 251 case PROP_VALUE_ATTRIBUTES: 252 g_value_set_flags (value, datacell->priv->attributes); 253 break; 254 case PROP_SET_DEFAULT_IF_INVALID: 255 g_value_set_boolean (value, datacell->priv->set_default_if_invalid); 256 break; 257 default: 258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); 259 break; 260 } 261 } 262 263 static gchar *render_text_to_display_from_values (GList *values); 264 265 static void 266 gdaui_data_cell_renderer_combo_set_property (GObject *object, 267 guint param_id, 268 const GValue *value, 269 GParamSpec *pspec) 270 { 271 GdauiDataCellRendererCombo *datacell = GDAUI_DATA_CELL_RENDERER_COMBO (object); 272 273 switch (param_id) { 274 case PROP_VALUES: 275 datacell->priv->invalid = FALSE; 276 if (value) { 277 GList *gvalues = g_value_get_pointer (value); 278 if (gvalues) { 279 GSList *values = NULL; 280 gint length = 0, row; 281 gboolean allnull = TRUE; 282 283 /* copy gvalues into the values GSList */ 284 while (gvalues) { 285 values = g_slist_append (values, gvalues->data); 286 287 if (!gvalues->data || 288 (gvalues->data && !gda_value_is_null ((GValue *)(gvalues->data)))) 289 allnull = FALSE; 290 291 length ++; 292 gvalues = g_list_next (gvalues); 293 } 294 295 g_return_if_fail (length == gdaui_set_source_get_ref_n_cols (datacell->priv->source)); 296 297 if (allnull) 298 g_object_set (G_OBJECT (object), "text", "", NULL); 299 else { 300 /* find the data model row for the values */ 301 /* if (gdaui_data_model_get_status (datacell->priv->data_model) & */ 302 /* GDAUI_DATA_MODEL_NEEDS_INIT_REFRESH) */ 303 /* gdaui_data_model_refresh (datacell->priv->data_model, NULL); */ 304 GdaDataModel *source_model; 305 source_model = gda_set_source_get_data_model (gdaui_set_source_get_source (datacell->priv->source)); 306 row = gda_data_model_get_row_from_values (source_model, 307 values, 308 gdaui_set_source_get_ref_columns (datacell->priv->source)); 309 if (row >= 0) { 310 GList *dsplay_values = NULL; 311 gint i; 312 gchar *str; 313 314 for (i = 0; i < gdaui_set_source_get_shown_n_cols (datacell->priv->source); i++) { 315 const GValue *value; 316 gint* cols; 317 cols = gdaui_set_source_get_shown_columns (datacell->priv->source); 318 value = gda_data_model_get_value_at (source_model, cols [i], row, NULL); 319 dsplay_values = g_list_append (dsplay_values, (GValue *) value); 320 } 321 str = render_text_to_display_from_values (dsplay_values); 322 g_list_free (dsplay_values); 323 g_object_set (G_OBJECT (object), "text", str, NULL); 324 g_free (str); 325 } 326 else { 327 if (datacell->priv->attributes & GDA_VALUE_ATTR_CAN_BE_NULL) 328 g_object_set (G_OBJECT (object), "text", "", NULL); 329 else 330 g_object_set (G_OBJECT (object), "text", "???", NULL); 331 } 332 } 333 334 g_slist_free (values); 335 } 336 else { 337 datacell->priv->invalid = TRUE; 338 g_object_set (G_OBJECT (object), "text", "", NULL); 339 } 340 } 341 else { 342 datacell->priv->invalid = TRUE; 343 g_object_set (G_OBJECT (object), "text", "", NULL); 344 } 345 346 g_object_notify (object, "values"); 347 break; 348 case PROP_VALUES_DISPLAY: 349 if (value) { 350 GList *gvalues = g_value_get_pointer (value); 351 gchar *str; 352 353 g_assert (g_list_length (gvalues) == (guint) gdaui_set_source_get_shown_n_cols (datacell->priv->source)); 354 str = render_text_to_display_from_values (gvalues); 355 g_object_set (G_OBJECT (object), "text", str, NULL); 356 g_free (str); 357 } 358 else 359 g_object_set (G_OBJECT (object), "text", "", NULL); 360 361 g_object_notify (object, "values-display"); 362 break; 363 case PROP_VALUE_ATTRIBUTES: 364 datacell->priv->attributes = g_value_get_flags (value); 365 break; 366 case PROP_TO_BE_DELETED: 367 datacell->priv->to_be_deleted = g_value_get_boolean (value); 368 break; 369 case PROP_SHOW_EXPANDER: 370 datacell->priv->show_expander = g_value_get_boolean (value); 371 break; 372 case PROP_SET_DEFAULT_IF_INVALID: 373 datacell->priv->set_default_if_invalid = g_value_get_boolean (value); 374 break; 375 case PROP_PARAMLIST: 376 if (datacell->priv->paramlist) 377 g_object_unref (datacell->priv->paramlist); 378 379 datacell->priv->paramlist = GDAUI_SET (g_value_get_object(value)); 380 if(datacell->priv->paramlist) 381 g_object_ref(datacell->priv->paramlist); 382 383 g_object_ref (G_OBJECT (datacell->priv->paramlist)); 384 break; 385 case PROP_PARAMLISTSOURCE: 386 datacell->priv->source = GDAUI_SET_SOURCE (g_value_get_pointer(value)); 387 break; 388 default: 389 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); 390 break; 391 } 392 } 393 394 static gchar * 395 render_text_to_display_from_values (GList *values) 396 { 397 GList *list = values; 398 gboolean allnull = TRUE; 399 GString *string = g_string_new (""); 400 gchar *retval; 401 gchar *str; 402 403 while (list) { 404 if (list->data && !gda_value_is_null ((GValue *)(list->data))) 405 allnull = FALSE; 406 407 if (list != values) 408 g_string_append (string, " / "); 409 if (list->data) { 410 str = gda_value_stringify ((GValue *)(list->data)); 411 /* TODO: use GdaDataHandler */ 412 g_string_append (string, str); 413 g_free (str); 414 } 415 else 416 g_string_append (string, " ? "); 417 418 list = g_list_next (list); 419 } 420 421 if (!allnull) { 422 retval = string->str; 423 g_string_free (string, FALSE); 424 } 425 else { 426 retval = g_strdup (""); 427 g_string_free (string, TRUE); 428 } 429 430 return retval; 431 } 432 433 /** 434 * gdaui_data_cell_renderer_combo_new: 435 * @paramlist: a #GdaSet object 436 * @source: a #GdauiSetSource structure listed in @paramlist->sources_list 437 * 438 * Creates a new #GdauiDataCellRendererCombo which will fill the parameters listed in 439 * @source->nodes with values available from @source->data_model. 440 * 441 * Returns: (transfer full): the new cell renderer 442 **/ 443 GtkCellRenderer * 444 gdaui_data_cell_renderer_combo_new (GdauiSet *paramlist, GdauiSetSource *source) 445 { 446 GObject *obj; 447 448 g_return_val_if_fail (GDAUI_IS_SET (paramlist), NULL); 449 g_return_val_if_fail (source, NULL); 450 g_return_val_if_fail (g_slist_find (paramlist->sources_list, source), NULL); 451 452 obj = g_object_new (GDAUI_TYPE_DATA_CELL_RENDERER_COMBO, "data-set", paramlist, 453 "data-set-source", source, NULL); 454 455 return GTK_CELL_RENDERER (obj); 456 } 457 458 static void 459 gdaui_data_cell_renderer_combo_get_size (GtkCellRenderer *cell, 460 GtkWidget *widget, 461 const GdkRectangle *cell_area, 462 gint *x_offset, 463 gint *y_offset, 464 gint *width, 465 gint *height) 466 { 467 gint calc_width = 0; 468 gint calc_height = 0; 469 470 /* get the size as calculated by the GtkCellRendererText */ 471 GtkCellRendererClass *text_class = g_type_class_peek (GTK_TYPE_CELL_RENDERER_TEXT); 472 (text_class->get_size) (cell, widget, cell_area, x_offset, y_offset, width, height); 473 474 /* Add more space for the popdown menu symbol */ 475 if (GDAUI_DATA_CELL_RENDERER_COMBO (cell)->priv->show_expander) { 476 guint xpad, ypad; 477 g_object_get ((GObject*) cell, "xpad", &xpad, "ypad", &ypad, NULL); 478 gint expander_size; 479 gtk_widget_style_get (widget, "expander-size", &expander_size, NULL); 480 calc_width = (gint) xpad * 2 + expander_size; 481 calc_height = (gint) ypad * 2 + expander_size; 482 } 483 484 if (width) 485 *width += calc_width; 486 487 if (height && (*height < calc_height)) 488 *height = calc_height; 489 } 490 491 static void 492 gdaui_data_cell_renderer_combo_render (GtkCellRenderer *cell, 493 cairo_t *cr, 494 GtkWidget *widget, 495 const GdkRectangle *background_area, 496 const GdkRectangle *cell_area, 497 GtkCellRendererState flags) 498 499 { 500 GdauiDataCellRendererCombo *combocell = GDAUI_DATA_CELL_RENDERER_COMBO (cell); 501 502 /* render the text as for the GtkCellRendererText */ 503 GtkCellRendererClass *text_class = g_type_class_peek (GTK_TYPE_CELL_RENDERER_TEXT); 504 (text_class->render) (cell, cr, widget, background_area, cell_area, flags); 505 506 /* render the popdown menu symbol */ 507 if (combocell->priv->show_expander) { 508 gint expander_size; 509 GtkStyleContext *style_context = gtk_widget_get_style_context (widget); 510 guint xpad, ypad; 511 512 gtk_widget_style_get (widget, "expander-size", &expander_size, NULL); 513 g_object_get ((GObject*) cell, "xpad", &xpad, "ypad", &ypad, NULL); 514 515 516 gtk_render_expander (style_context, 517 cr, 518 cell_area->x + cell_area->width - xpad - expander_size/2., 519 cell_area->y + cell_area->height - ypad - expander_size/2., 520 expander_size, expander_size); 521 } 522 523 if (combocell->priv->to_be_deleted) { 524 GtkStyleContext *style_context = gtk_widget_get_style_context (widget); 525 guint xpad; 526 g_object_get ((GObject*) cell, "xpad", &xpad, NULL); 527 528 gdouble y = cell_area->y + cell_area->height / 2.; 529 gtk_render_line (style_context, 530 cr, 531 cell_area->x + xpad, cell_area->x + cell_area->width - xpad, 532 y, y); 533 } 534 535 if (combocell->priv->invalid) 536 gdaui_data_cell_renderer_draw_invalid_area (cr, cell_area); 537 } 538 539 static void gdaui_data_cell_renderer_combo_editing_done (GtkCellEditable *combo, GdauiDataCellRendererCombo *datacell); 540 static gboolean gdaui_data_cell_renderer_combo_focus_out_event (GtkWidget *widget, GdkEvent *event, 541 GdauiDataCellRendererCombo *datacell); 542 543 static GtkCellEditable * 544 gdaui_data_cell_renderer_combo_start_editing (GtkCellRenderer *cell, 545 G_GNUC_UNUSED GdkEvent *event, 546 G_GNUC_UNUSED GtkWidget *widget, 547 const gchar *path, 548 G_GNUC_UNUSED const GdkRectangle *background_area, 549 G_GNUC_UNUSED const GdkRectangle *cell_area, 550 G_GNUC_UNUSED GtkCellRendererState flags) 551 { 552 GdauiDataCellRendererCombo *datacell; 553 GtkWidget *combo; 554 gboolean editable; 555 GdaDataModel *source_model; 556 557 g_object_get ((GObject*) cell, "editable", &editable, NULL); 558 if (editable == FALSE) 559 return NULL; 560 561 datacell = GDAUI_DATA_CELL_RENDERER_COMBO (cell); 562 source_model = gda_set_source_get_data_model (gdaui_set_source_get_source (datacell->priv->source)); 563 combo = gdaui_combo_new_with_model (source_model, 564 gdaui_set_source_get_shown_n_cols (datacell->priv->source), 565 gdaui_set_source_get_shown_columns (datacell->priv->source)); 566 567 g_object_set (combo, "has-frame", FALSE, NULL); 568 g_object_set_data_full (G_OBJECT (combo), 569 GDAUI_DATA_CELL_RENDERER_COMBO_PATH, 570 g_strdup (path), g_free); 571 gdaui_combo_add_null (GDAUI_COMBO (combo), 572 (datacell->priv->attributes & GDA_VALUE_ATTR_CAN_BE_NULL) ? TRUE : FALSE); 573 gtk_widget_show (combo); 574 575 g_signal_connect (GTK_CELL_EDITABLE (combo), "editing-done", 576 G_CALLBACK (gdaui_data_cell_renderer_combo_editing_done), datacell); 577 datacell->priv->focus_out_id = g_signal_connect (combo, "focus-out-event", 578 G_CALLBACK (gdaui_data_cell_renderer_combo_focus_out_event), 579 datacell); 580 581 return GTK_CELL_EDITABLE (combo); 582 } 583 584 585 static void 586 gdaui_data_cell_renderer_combo_editing_done (GtkCellEditable *combo, GdauiDataCellRendererCombo *datacell) 587 { 588 const gchar *path; 589 gboolean canceled; 590 GSList *list, *list_all; 591 592 if (datacell->priv->focus_out_id > 0) { 593 g_signal_handler_disconnect (combo, datacell->priv->focus_out_id); 594 datacell->priv->focus_out_id = 0; 595 } 596 597 /*canceled = _gtk_combo_box_editing_canceled (GTK_COMBO_BOX (combo));*/ 598 canceled = FALSE; /* FIXME */ 599 gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (datacell), canceled); 600 if (canceled) 601 return; 602 603 list = _gdaui_combo_get_selected_ext (GDAUI_COMBO (combo), 604 gdaui_set_source_get_ref_n_cols (datacell->priv->source), 605 gdaui_set_source_get_ref_columns (datacell->priv->source)); 606 list_all = _gdaui_combo_get_selected_ext (GDAUI_COMBO (combo), 0, NULL); 607 608 path = g_object_get_data (G_OBJECT (combo), GDAUI_DATA_CELL_RENDERER_COMBO_PATH); 609 g_signal_emit (datacell, text_cell_renderer_combo_signals [CHANGED], 0, path, list, list_all); 610 g_slist_free (list); 611 g_slist_free (list_all); 612 } 613 614 615 static gboolean 616 gdaui_data_cell_renderer_combo_focus_out_event (GtkWidget *widget, G_GNUC_UNUSED GdkEvent *event, 617 GdauiDataCellRendererCombo *datacell) 618 { 619 620 gdaui_data_cell_renderer_combo_editing_done (GTK_CELL_EDITABLE (widget), datacell); 621 622 return FALSE; 623 } 624