1 /* GtkCellRendererCombo
2 * Copyright (C) 2004 Lorenzo Gil Sanchez
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
27 #include "gtkcelllayout.h"
28 #include "gtkcellrenderercombo.h"
29 #include "gtkcellrenderertext.h"
30 #include "gtkcombobox.h"
31 #include "gtkcomboboxentry.h"
33 static void gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass);
34 static void gtk_cell_renderer_combo_init (GtkCellRendererCombo *self);
35 static void gtk_cell_renderer_combo_finalize (GObject *object);
36 static void gtk_cell_renderer_combo_get_property (GObject *object,
41 static void gtk_cell_renderer_combo_set_property (GObject *object,
46 static GtkCellEditable *gtk_cell_renderer_combo_start_editing (GtkCellRenderer *cell,
50 GdkRectangle *background_area,
51 GdkRectangle *cell_area,
52 GtkCellRendererState flags);
61 #define GTK_CELL_RENDERER_COMBO_PATH "gtk-cell-renderer-combo-path"
63 G_DEFINE_TYPE (GtkCellRendererCombo, gtk_cell_renderer_combo, GTK_TYPE_CELL_RENDERER_TEXT);
66 gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass)
68 GObjectClass *object_class = G_OBJECT_CLASS (klass);
69 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
71 object_class->finalize = gtk_cell_renderer_combo_finalize;
72 object_class->get_property = gtk_cell_renderer_combo_get_property;
73 object_class->set_property = gtk_cell_renderer_combo_set_property;
75 cell_class->start_editing = gtk_cell_renderer_combo_start_editing;
78 * GtkCellRendererCombo:model:
80 * The :model property holds a tree model containing the possible
81 * values for the combo box. Use the :text_column property to specify
82 * the column holding the values.
86 g_object_class_install_property (object_class,
88 g_param_spec_object ("model",
90 P_("The model containing the possible values for the combo box"),
95 * GtkCellRendererCombo:text_column:
97 * The :text_column property specifies the model column which
98 * holds the possible values for the combo box. Note that this
99 * refers to the model specified in the :model property,
100 * <emphasis>not</emphasis> the model backing the tree view to
101 * which this cell renderer is attached.
105 g_object_class_install_property (object_class,
107 g_param_spec_int ("text_column",
109 P_("A column in the data source model to get the strings from"),
116 * GtkCellRendererCombo:has_entry:
118 * If the :has_entry property is %TRUE, the cell renderer will
119 * include an entry and allow to enter values other than the ones
124 g_object_class_install_property (object_class,
126 g_param_spec_boolean ("has_entry",
128 P_("If %FALSE, don't allow to enter strings other than the chosen ones"),
135 gtk_cell_renderer_combo_init (GtkCellRendererCombo *self)
138 self->text_column = -1;
139 self->has_entry = TRUE;
140 self->focus_out_id = 0;
144 * gtk_cell_renderer_combo_new:
146 * Creates a new #GtkCellRendererCombo
147 * Adjust how text is drawn using object properties.
148 * Object properties can be set globally (with g_object_set()).
149 * Also, with #GtkTreeViewColumn, you can bind a property to a value
150 * in a #GtkTreeModel. For example, you can bind the "text" property
151 * on the cell renderer to a string value in the model, thus rendering
152 * a different string in each row of the #GtkTreeView.
154 * Returns: the new cell renderer
159 gtk_cell_renderer_combo_new (void)
161 return g_object_new (GTK_TYPE_CELL_RENDERER_COMBO, NULL);
165 gtk_cell_renderer_combo_finalize (GObject *object)
167 GtkCellRendererCombo *cell = GTK_CELL_RENDERER_COMBO (object);
171 g_object_unref (cell->model);
175 G_OBJECT_CLASS (gtk_cell_renderer_combo_parent_class)->finalize (object);
179 gtk_cell_renderer_combo_get_property (GObject *object,
184 GtkCellRendererCombo *cell;
186 g_return_if_fail (GTK_IS_CELL_RENDERER_COMBO (object));
188 cell = GTK_CELL_RENDERER_COMBO (object);
193 g_value_set_object (value, cell->model);
195 case PROP_TEXT_COLUMN:
196 g_value_set_int (value, cell->text_column);
199 g_value_set_boolean (value, cell->has_entry);
202 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
207 gtk_cell_renderer_combo_set_property (GObject *object,
212 GtkCellRendererCombo *cell;
214 g_return_if_fail (GTK_IS_CELL_RENDERER_COMBO (object));
216 cell = GTK_CELL_RENDERER_COMBO (object);
224 object = g_value_get_object (value);
225 g_return_if_fail (GTK_IS_TREE_MODEL (object));
226 g_object_ref (object);
230 g_object_unref (cell->model);
233 cell->model = GTK_TREE_MODEL (object);
236 case PROP_TEXT_COLUMN:
237 cell->text_column = g_value_get_int (value);
240 cell->has_entry = g_value_get_boolean (value);
243 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248 gtk_cell_renderer_combo_editing_done (GtkCellEditable *combo,
252 gchar *new_text = NULL;
255 GtkCellRendererCombo *cell;
258 cell = GTK_CELL_RENDERER_COMBO (data);
260 if (cell->focus_out_id > 0)
262 g_signal_handler_disconnect (combo, cell->focus_out_id);
263 cell->focus_out_id = 0;
266 if (_gtk_combo_box_editing_canceled (GTK_COMBO_BOX (combo)))
268 gtk_cell_renderer_editing_canceled (GTK_CELL_RENDERER (data));
272 if (GTK_IS_COMBO_BOX_ENTRY (combo))
274 entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo)));
275 new_text = g_strdup (gtk_entry_get_text (entry));
279 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
280 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
281 gtk_tree_model_get (model, &iter, cell->text_column, &new_text, -1);
284 path = g_object_get_data (G_OBJECT (combo), GTK_CELL_RENDERER_COMBO_PATH);
285 g_signal_emit_by_name (cell, "edited", path, new_text);
291 gtk_cell_renderer_combo_focus_out_event (GtkWidget *widget,
296 gtk_cell_renderer_combo_editing_done (GTK_CELL_EDITABLE (widget), data);
303 GtkCellRendererCombo *cell;
309 find_text (GtkTreeModel *model,
314 SearchData *search_data = (SearchData *)data;
317 gtk_tree_model_get (model, iter, search_data->cell->text_column, &text, -1);
318 if (text && GTK_CELL_RENDERER_TEXT (search_data->cell)->text &&
319 strcmp (text, GTK_CELL_RENDERER_TEXT (search_data->cell)->text) == 0)
321 search_data->iter = *iter;
322 search_data->found = TRUE;
325 return search_data->found;
328 static GtkCellEditable *
329 gtk_cell_renderer_combo_start_editing (GtkCellRenderer *cell,
333 GdkRectangle *background_area,
334 GdkRectangle *cell_area,
335 GtkCellRendererState flags)
337 GtkCellRendererCombo *cell_combo;
338 GtkCellRendererText *cell_text;
340 SearchData search_data;
342 cell_text = GTK_CELL_RENDERER_TEXT (cell);
343 if (cell_text->editable == FALSE)
346 cell_combo = GTK_CELL_RENDERER_COMBO (cell);
347 if (cell_combo->model == NULL || cell_combo->text_column < 0)
350 if (cell_combo->has_entry)
352 combo = gtk_combo_box_entry_new_with_model (cell_combo->model, cell_combo->text_column);
355 gtk_entry_set_text (GTK_ENTRY (GTK_BIN (combo)->child),
360 cell = gtk_cell_renderer_text_new ();
361 combo = gtk_combo_box_new_with_model (cell_combo->model);
362 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
363 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo),
364 cell, "text", cell_combo->text_column,
367 /* determine the current value */
368 search_data.cell = cell_combo;
369 search_data.found = FALSE;
370 gtk_tree_model_foreach (cell_combo->model, find_text, &search_data);
371 if (search_data.found)
372 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo),
373 &(search_data.iter));
376 g_object_set (combo, "has_frame", FALSE, NULL);
377 g_object_set_data_full (G_OBJECT (combo),
378 GTK_CELL_RENDERER_COMBO_PATH,
379 g_strdup (path), g_free);
381 gtk_widget_show (combo);
383 g_signal_connect (GTK_CELL_EDITABLE (combo), "editing_done",
384 G_CALLBACK (gtk_cell_renderer_combo_editing_done),
386 cell_combo->focus_out_id =
387 g_signal_connect (combo, "focus_out_event",
388 G_CALLBACK (gtk_cell_renderer_combo_focus_out_event),
391 return GTK_CELL_EDITABLE (combo);