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.
26 #include "gtkcelllayout.h"
27 #include "gtkcellrenderercombo.h"
28 #include "gtkcellrenderertext.h"
29 #include "gtkcombobox.h"
30 #include "gtkcomboboxentry.h"
32 static void gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass);
33 static void gtk_cell_renderer_combo_init (GtkCellRendererCombo *self);
34 static void gtk_cell_renderer_combo_get_property (GObject *object,
39 static void gtk_cell_renderer_combo_set_property (GObject *object,
44 static GtkCellEditable *gtk_cell_renderer_combo_start_editing (GtkCellRenderer *cell,
48 GdkRectangle *background_area,
49 GdkRectangle *cell_area,
50 GtkCellRendererState flags);
59 static GObjectClass *parent_class = NULL;
61 #define GTK_CELL_RENDERER_COMBO_PATH "gtk-cell-renderer-combo-path"
64 gtk_cell_renderer_combo_get_type (void)
66 static GType gtk_cell_renderer_combo_type = 0;
68 if (!gtk_cell_renderer_combo_type)
70 static const GTypeInfo gtk_cell_renderer_combo_info =
72 sizeof (GtkCellRendererComboClass),
74 (GBaseFinalizeFunc) NULL,
75 (GClassInitFunc) gtk_cell_renderer_combo_class_init,
78 sizeof (GtkCellRendererCombo),
80 (GInstanceInitFunc) gtk_cell_renderer_combo_init
82 gtk_cell_renderer_combo_type =
83 g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT,
84 "GtkCellRendererCombo",
85 >k_cell_renderer_combo_info,
88 return gtk_cell_renderer_combo_type;
92 gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass)
94 GObjectClass *object_class = G_OBJECT_CLASS (klass);
95 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
97 parent_class = g_type_class_peek_parent (klass);
99 object_class->get_property = gtk_cell_renderer_combo_get_property;
100 object_class->set_property = gtk_cell_renderer_combo_set_property;
102 cell_class->start_editing = gtk_cell_renderer_combo_start_editing;
105 * GtkCellRendererCombo:model:
107 * The :model property holds a tree model containing the possible
108 * values for the combo box. Use the :text_column property to specify
109 * the column holding the values.
113 g_object_class_install_property (object_class,
115 g_param_spec_object ("model",
117 P_("The model containing the possible values for the combo box"),
122 * GtkCellRendererCombo:text_column:
124 * The :text_column property specifies the model column which
125 * holds the possible values for the combo box. Note that this
126 * refers to the model specified in the :model property,
127 * <emphasis>not</emphasis> the model backing the tree view to
128 * which this cell renderer is attached.
132 g_object_class_install_property (object_class,
134 g_param_spec_int ("text_column",
136 P_("A column in the data source model to get the strings from"),
143 * GtkCellRendererCombo:has_entry:
145 * If the :has_entry property is %TRUe, the cell renderer will
146 * include an entry and allow to enter values other than the ones
151 g_object_class_install_property (object_class,
153 g_param_spec_boolean ("has_entry",
155 P_("If %FALSE, don't allow to enter strings other than the chosen ones"),
162 gtk_cell_renderer_combo_init (GtkCellRendererCombo *self)
165 self->text_column = -1;
166 self->focus_out_id = 0;
170 * gtk_cell_renderer_combo_new:
172 * Creates a new #GtkCellRendererCombo
173 * Adjust how text is drawn using object properties.
174 * Object properties can be set globally (with g_object_set()).
175 * Also, with #GtkTreeViewColumn, you can bind a property to a value
176 * in a #GtkTreeModel. For example, you can bind the "text" property
177 * on the cell renderer to a string value in the model, thus rendering
178 * a different string in each row of the #GtkTreeView.
180 * Returns: the new cell renderer
185 gtk_cell_renderer_combo_new (void)
187 return g_object_new (GTK_TYPE_CELL_RENDERER_COMBO, NULL);
191 gtk_cell_renderer_combo_get_property (GObject *object,
196 GtkCellRendererCombo *cell;
198 g_return_if_fail (GTK_IS_CELL_RENDERER_COMBO (object));
200 cell = GTK_CELL_RENDERER_COMBO (object);
205 g_value_set_object (value, cell->model);
207 case PROP_TEXT_COLUMN:
208 g_value_set_int (value, cell->text_column);
211 g_value_set_boolean (value, cell->has_entry);
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219 gtk_cell_renderer_combo_set_property (GObject *object,
224 GtkCellRendererCombo *cell;
226 g_return_if_fail (GTK_IS_CELL_RENDERER_COMBO (object));
228 cell = GTK_CELL_RENDERER_COMBO (object);
233 cell->model = g_value_get_object (value);
235 case PROP_TEXT_COLUMN:
236 cell->text_column = g_value_get_int (value);
239 cell->has_entry = g_value_get_boolean (value);
242 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
247 gtk_cell_renderer_combo_editing_done (GtkCellEditable *combo,
251 gchar *new_text = NULL;
254 GtkCellRendererCombo *cell;
257 cell = GTK_CELL_RENDERER_COMBO (data);
259 if (cell->focus_out_id > 0)
261 g_signal_handler_disconnect (combo, cell->focus_out_id);
262 cell->focus_out_id = 0;
265 if (_gtk_combo_box_editing_canceled (GTK_COMBO_BOX (combo)))
267 gtk_cell_renderer_editing_canceled (GTK_CELL_RENDERER (data));
271 if (GTK_IS_COMBO_BOX_ENTRY (combo))
273 entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo)));
274 new_text = g_strdup (gtk_entry_get_text (entry));
278 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
279 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
280 gtk_tree_model_get (model, &iter, cell->text_column, &new_text, -1);
283 path = g_object_get_data (G_OBJECT (combo), GTK_CELL_RENDERER_COMBO_PATH);
284 g_signal_emit_by_name (cell, "edited", path, new_text);
290 gtk_cell_renderer_combo_focus_out_event (GtkWidget *widget,
295 gtk_cell_renderer_combo_editing_done (GTK_CELL_EDITABLE (widget), data);
302 GtkCellRendererCombo *cell;
308 find_text (GtkTreeModel *model,
313 SearchData *search_data = (SearchData *)data;
316 gtk_tree_model_get (model, iter, search_data->cell->text_column, &text, -1);
317 if (text && GTK_CELL_RENDERER_TEXT (search_data->cell)->text &&
318 strcmp (text, GTK_CELL_RENDERER_TEXT (search_data->cell)->text) == 0)
320 search_data->iter = *iter;
321 search_data->found = TRUE;
324 return search_data->found;
327 static GtkCellEditable *
328 gtk_cell_renderer_combo_start_editing (GtkCellRenderer *cell,
332 GdkRectangle *background_area,
333 GdkRectangle *cell_area,
334 GtkCellRendererState flags)
336 GtkCellRendererCombo *cell_combo;
337 GtkCellRendererText *cell_text;
339 SearchData search_data;
341 cell_text = GTK_CELL_RENDERER_TEXT (cell);
342 if (cell_text->editable == FALSE)
345 cell_combo = GTK_CELL_RENDERER_COMBO (cell);
346 if (cell_combo->model == NULL || cell_combo->text_column < 0)
349 if (cell_combo->has_entry)
351 combo = gtk_combo_box_entry_new_with_model (cell_combo->model, cell_combo->text_column);
354 gtk_entry_set_text (GTK_ENTRY (GTK_BIN (combo)->child),
359 cell = gtk_cell_renderer_text_new ();
360 combo = gtk_combo_box_new_with_model (cell_combo->model);
361 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
362 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo),
363 cell, "text", cell_combo->text_column,
366 /* determine the current value */
367 search_data.cell = cell_combo;
368 search_data.found = FALSE;
369 gtk_tree_model_foreach (cell_combo->model, find_text, &search_data);
370 if (search_data.found)
371 gtk_combo_box_set_active_iter (combo, &(search_data.iter));
374 g_object_set (combo, "has_frame", FALSE, NULL);
375 g_object_set_data_full (G_OBJECT (combo),
376 GTK_CELL_RENDERER_COMBO_PATH,
377 g_strdup (path), g_free);
379 gtk_widget_show (combo);
381 g_signal_connect (GTK_CELL_EDITABLE (combo), "editing_done",
382 G_CALLBACK (gtk_cell_renderer_combo_editing_done),
384 cell_combo->focus_out_id =
385 g_signal_connect (combo, "focus_out_event",
386 G_CALLBACK (gtk_cell_renderer_combo_focus_out_event),
389 return GTK_CELL_EDITABLE (combo);