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"
31 #include "gtkprivate.h"
34 static void gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass);
35 static void gtk_cell_renderer_combo_init (GtkCellRendererCombo *self);
36 static void gtk_cell_renderer_combo_finalize (GObject *object);
37 static void gtk_cell_renderer_combo_get_property (GObject *object,
42 static void gtk_cell_renderer_combo_set_property (GObject *object,
47 static GtkCellEditable *gtk_cell_renderer_combo_start_editing (GtkCellRenderer *cell,
51 GdkRectangle *background_area,
52 GdkRectangle *cell_area,
53 GtkCellRendererState flags);
62 #define GTK_CELL_RENDERER_COMBO_PATH "gtk-cell-renderer-combo-path"
64 G_DEFINE_TYPE (GtkCellRendererCombo, gtk_cell_renderer_combo, GTK_TYPE_CELL_RENDERER_TEXT);
67 gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass)
69 GObjectClass *object_class = G_OBJECT_CLASS (klass);
70 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
72 object_class->finalize = gtk_cell_renderer_combo_finalize;
73 object_class->get_property = gtk_cell_renderer_combo_get_property;
74 object_class->set_property = gtk_cell_renderer_combo_set_property;
76 cell_class->start_editing = gtk_cell_renderer_combo_start_editing;
79 * GtkCellRendererCombo:model:
81 * Holds a tree model containing the possible values for the combo box.
82 * Use the text_column property to specify 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"),
92 GTK_PARAM_READWRITE));
95 * GtkCellRendererCombo:text-column:
97 * Specifies the model column which holds the possible values for the combo box.
98 * Note that this refers to the model specified in the model property,
99 * <emphasis>not</emphasis> the model backing the tree view to which this cell
100 * renderer is attached.
102 * #GtkCellRendererCombo automatically adds a text cell renderer for this column
107 g_object_class_install_property (object_class,
109 g_param_spec_int ("text-column",
111 P_("A column in the data source model to get the strings from"),
115 GTK_PARAM_READWRITE));
118 * GtkCellRendererCombo:has-entry:
120 * If %TRUE, the cell renderer will include an entry and allow to enter values
121 * other than the ones in the popup list.
125 g_object_class_install_property (object_class,
127 g_param_spec_boolean ("has-entry",
129 P_("If FALSE, don't allow to enter strings other than the chosen ones"),
131 GTK_PARAM_READWRITE));
136 gtk_cell_renderer_combo_init (GtkCellRendererCombo *self)
139 self->text_column = -1;
140 self->has_entry = TRUE;
141 self->focus_out_id = 0;
145 * gtk_cell_renderer_combo_new:
147 * Creates a new #GtkCellRendererCombo.
148 * Adjust how text is drawn using object properties.
149 * Object properties can be set globally (with g_object_set()).
150 * Also, with #GtkTreeViewColumn, you can bind a property to a value
151 * in a #GtkTreeModel. For example, you can bind the "text" property
152 * on the cell renderer to a string value in the model, thus rendering
153 * a different string in each row of the #GtkTreeView.
155 * Returns: the new cell renderer
160 gtk_cell_renderer_combo_new (void)
162 return g_object_new (GTK_TYPE_CELL_RENDERER_COMBO, NULL);
166 gtk_cell_renderer_combo_finalize (GObject *object)
168 GtkCellRendererCombo *cell = GTK_CELL_RENDERER_COMBO (object);
172 g_object_unref (cell->model);
176 G_OBJECT_CLASS (gtk_cell_renderer_combo_parent_class)->finalize (object);
180 gtk_cell_renderer_combo_get_property (GObject *object,
185 GtkCellRendererCombo *cell;
187 g_return_if_fail (GTK_IS_CELL_RENDERER_COMBO (object));
189 cell = GTK_CELL_RENDERER_COMBO (object);
194 g_value_set_object (value, cell->model);
196 case PROP_TEXT_COLUMN:
197 g_value_set_int (value, cell->text_column);
200 g_value_set_boolean (value, cell->has_entry);
203 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
208 gtk_cell_renderer_combo_set_property (GObject *object,
213 GtkCellRendererCombo *cell;
215 g_return_if_fail (GTK_IS_CELL_RENDERER_COMBO (object));
217 cell = GTK_CELL_RENDERER_COMBO (object);
225 object = g_value_get_object (value);
226 g_return_if_fail (GTK_IS_TREE_MODEL (object));
227 g_object_ref (object);
231 g_object_unref (cell->model);
234 cell->model = GTK_TREE_MODEL (object);
237 case PROP_TEXT_COLUMN:
238 cell->text_column = g_value_get_int (value);
241 cell->has_entry = g_value_get_boolean (value);
244 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
249 gtk_cell_renderer_combo_editing_done (GtkCellEditable *combo,
253 gchar *new_text = NULL;
256 GtkCellRendererCombo *cell;
260 cell = GTK_CELL_RENDERER_COMBO (data);
262 if (cell->focus_out_id > 0)
264 g_signal_handler_disconnect (combo, cell->focus_out_id);
265 cell->focus_out_id = 0;
268 canceled = _gtk_combo_box_editing_canceled (GTK_COMBO_BOX (combo));
269 gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), canceled);
273 if (GTK_IS_COMBO_BOX_ENTRY (combo))
275 entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo)));
276 new_text = g_strdup (gtk_entry_get_text (entry));
280 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
281 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
282 gtk_tree_model_get (model, &iter, cell->text_column, &new_text, -1);
285 path = g_object_get_data (G_OBJECT (combo), GTK_CELL_RENDERER_COMBO_PATH);
286 g_signal_emit_by_name (cell, "edited", path, new_text);
292 gtk_cell_renderer_combo_focus_out_event (GtkWidget *widget,
297 gtk_cell_renderer_combo_editing_done (GTK_CELL_EDITABLE (widget), data);
304 GtkCellRendererCombo *cell;
310 find_text (GtkTreeModel *model,
315 SearchData *search_data = (SearchData *)data;
318 gtk_tree_model_get (model, iter, search_data->cell->text_column, &text, -1);
319 if (text && GTK_CELL_RENDERER_TEXT (search_data->cell)->text &&
320 strcmp (text, GTK_CELL_RENDERER_TEXT (search_data->cell)->text) == 0)
322 search_data->iter = *iter;
323 search_data->found = TRUE;
328 return search_data->found;
331 static GtkCellEditable *
332 gtk_cell_renderer_combo_start_editing (GtkCellRenderer *cell,
336 GdkRectangle *background_area,
337 GdkRectangle *cell_area,
338 GtkCellRendererState flags)
340 GtkCellRendererCombo *cell_combo;
341 GtkCellRendererText *cell_text;
343 SearchData search_data;
345 cell_text = GTK_CELL_RENDERER_TEXT (cell);
346 if (cell_text->editable == FALSE)
349 cell_combo = GTK_CELL_RENDERER_COMBO (cell);
350 if (cell_combo->model == NULL || cell_combo->text_column < 0)
353 if (cell_combo->has_entry)
355 combo = gtk_combo_box_entry_new_with_model (cell_combo->model, cell_combo->text_column);
358 gtk_entry_set_text (GTK_ENTRY (GTK_BIN (combo)->child),
363 cell = gtk_cell_renderer_text_new ();
364 combo = gtk_combo_box_new_with_model (cell_combo->model);
365 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
366 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo),
367 cell, "text", cell_combo->text_column,
370 /* determine the current value */
371 search_data.cell = cell_combo;
372 search_data.found = FALSE;
373 gtk_tree_model_foreach (cell_combo->model, find_text, &search_data);
374 if (search_data.found)
375 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo),
376 &(search_data.iter));
379 g_object_set (combo, "has_frame", FALSE, NULL);
380 g_object_set_data_full (G_OBJECT (combo),
381 GTK_CELL_RENDERER_COMBO_PATH,
382 g_strdup (path), g_free);
384 gtk_widget_show (combo);
386 g_signal_connect (GTK_CELL_EDITABLE (combo), "editing_done",
387 G_CALLBACK (gtk_cell_renderer_combo_editing_done),
389 cell_combo->focus_out_id =
390 g_signal_connect (combo, "focus_out_event",
391 G_CALLBACK (gtk_cell_renderer_combo_focus_out_event),
394 return GTK_CELL_EDITABLE (combo);
397 #define __GTK_CELL_RENDERER_COMBO_C__
398 #include "gtkaliasdef.c"