X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcellrenderercombo.c;h=0518d1430727d06c01c2e2c641ff1fb56d5f0c72;hb=e4c2ef108cc66210af015b679ce3542ca6decfec;hp=1f027468d03df0315f877460bda8d970eb1bca11;hpb=788bec83843059493bd6f3adac26cf8e2f323559;p=~andy%2Fgtk diff --git a/gtk/gtkcellrenderercombo.c b/gtk/gtkcellrenderercombo.c index 1f027468d..0518d1430 100644 --- a/gtk/gtkcellrenderercombo.c +++ b/gtk/gtkcellrenderercombo.c @@ -12,15 +12,12 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ -#include +#include "config.h" #include -#include "gtkalias.h" #include "gtkintl.h" #include "gtkbin.h" #include "gtkentry.h" @@ -28,7 +25,43 @@ #include "gtkcellrenderercombo.h" #include "gtkcellrenderertext.h" #include "gtkcombobox.h" -#include "gtkcomboboxentry.h" +#include "gtkmarshalers.h" +#include "gtkprivate.h" + + +/** + * SECTION:gtkcellrenderercombo + * @Short_description: Renders a combobox in a cell + * @Title: GtkCellRendererCombo + * + * #GtkCellRendererCombo renders text in a cell like #GtkCellRendererText from + * which it is derived. But while #GtkCellRendererText offers a simple entry to + * edit the text, #GtkCellRendererCombo offers a #GtkComboBox + * widget to edit the text. The values to display in the combo box are taken from + * the tree model specified in the #GtkCellRendererCombo:model property. + * + * The combo cell renderer takes care of adding a text cell renderer to the combo + * box and sets it to display the column specified by its + * #GtkCellRendererCombo:text-column property. Further properties of the combo box + * can be set in a handler for the #GtkCellRenderer::editing-started signal. + * + * The #GtkCellRendererCombo cell renderer was added in GTK+ 2.6. + */ + + +struct _GtkCellRendererComboPrivate +{ + GtkTreeModel *model; + + GtkWidget *combo; + + gboolean has_entry; + + gint text_column; + + gulong focus_out_id; +}; + static void gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass); static void gtk_cell_renderer_combo_init (GtkCellRendererCombo *self); @@ -44,12 +77,12 @@ static void gtk_cell_renderer_combo_set_property (GObject *object, GParamSpec *pspec); static GtkCellEditable *gtk_cell_renderer_combo_start_editing (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkCellRendererState flags); + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags); enum { PROP_0, @@ -58,9 +91,16 @@ enum { PROP_HAS_ENTRY }; +enum { + CHANGED, + LAST_SIGNAL +}; + +static guint cell_renderer_combo_signals[LAST_SIGNAL] = { 0, }; + #define GTK_CELL_RENDERER_COMBO_PATH "gtk-cell-renderer-combo-path" -G_DEFINE_TYPE (GtkCellRendererCombo, gtk_cell_renderer_combo, GTK_TYPE_CELL_RENDERER_TEXT); +G_DEFINE_TYPE (GtkCellRendererCombo, gtk_cell_renderer_combo, GTK_TYPE_CELL_RENDERER_TEXT) static void gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass) @@ -88,56 +128,100 @@ gtk_cell_renderer_combo_class_init (GtkCellRendererComboClass *klass) P_("Model"), P_("The model containing the possible values for the combo box"), GTK_TYPE_TREE_MODEL, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkCellRendererCombo:text-column: * - * Specifies the model column which holds the possible values for the combo box. + * Specifies the model column which holds the possible values for the + * combo box. + * * Note that this refers to the model specified in the model property, - * not the model backing the tree view to which this cell - * renderer is attached. + * not the model backing the tree view to which + * this cell renderer is attached. * - * #GtkCellRendererCombo automatically adds a text cell renderer for this column - * to its combo box. + * #GtkCellRendererCombo automatically adds a text cell renderer for + * this column to its combo box. * * Since: 2.6 */ g_object_class_install_property (object_class, PROP_TEXT_COLUMN, - g_param_spec_int ("text_column", + g_param_spec_int ("text-column", P_("Text Column"), P_("A column in the data source model to get the strings from"), -1, G_MAXINT, -1, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkCellRendererCombo:has-entry: * - * If %TRUE, the cell renderer will include an entry and allow to enter values - * other than the ones in the popup list. + * If %TRUE, the cell renderer will include an entry and allow to enter + * values other than the ones in the popup list. * * Since: 2.6 */ g_object_class_install_property (object_class, PROP_HAS_ENTRY, - g_param_spec_boolean ("has_entry", + g_param_spec_boolean ("has-entry", P_("Has Entry"), P_("If FALSE, don't allow to enter strings other than the chosen ones"), TRUE, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); + + /** + * GtkCellRendererCombo::changed: + * @combo: the object on which the signal is emitted + * @path_string: a string of the path identifying the edited cell + * (relative to the tree view model) + * @new_iter: the new iter selected in the combo box + * (relative to the combo box model) + * + * This signal is emitted each time after the user selected an item in + * the combo box, either by using the mouse or the arrow keys. Contrary + * to GtkComboBox, GtkCellRendererCombo::changed is not emitted for + * changes made to a selected item in the entry. The argument @new_iter + * corresponds to the newly selected item in the combo box and it is relative + * to the GtkTreeModel set via the model property on GtkCellRendererCombo. + * + * Note that as soon as you change the model displayed in the tree view, + * the tree view will immediately cease the editing operating. This + * means that you most probably want to refrain from changing the model + * until the combo cell renderer emits the edited or editing_canceled signal. + * + * Since: 2.14 + */ + cell_renderer_combo_signals[CHANGED] = + g_signal_new (I_("changed"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _gtk_marshal_VOID__STRING_BOXED, + G_TYPE_NONE, 2, + G_TYPE_STRING, + GTK_TYPE_TREE_ITER); + + g_type_class_add_private (klass, sizeof (GtkCellRendererComboPrivate)); } static void gtk_cell_renderer_combo_init (GtkCellRendererCombo *self) { - self->model = NULL; - self->text_column = -1; - self->has_entry = TRUE; - self->focus_out_id = 0; + GtkCellRendererComboPrivate *priv; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + GTK_TYPE_CELL_RENDERER_COMBO, + GtkCellRendererComboPrivate); + priv = self->priv; + + priv->model = NULL; + priv->text_column = -1; + priv->has_entry = TRUE; + priv->focus_out_id = 0; } /** @@ -165,11 +249,12 @@ static void gtk_cell_renderer_combo_finalize (GObject *object) { GtkCellRendererCombo *cell = GTK_CELL_RENDERER_COMBO (object); + GtkCellRendererComboPrivate *priv = cell->priv; - if (cell->model) + if (priv->model) { - g_object_unref (cell->model); - cell->model = NULL; + g_object_unref (priv->model); + priv->model = NULL; } G_OBJECT_CLASS (gtk_cell_renderer_combo_parent_class)->finalize (object); @@ -181,25 +266,23 @@ gtk_cell_renderer_combo_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - GtkCellRendererCombo *cell; - - g_return_if_fail (GTK_IS_CELL_RENDERER_COMBO (object)); - - cell = GTK_CELL_RENDERER_COMBO (object); + GtkCellRendererCombo *cell = GTK_CELL_RENDERER_COMBO (object); + GtkCellRendererComboPrivate *priv = cell->priv; switch (prop_id) { case PROP_MODEL: - g_value_set_object (value, cell->model); + g_value_set_object (value, priv->model); break; case PROP_TEXT_COLUMN: - g_value_set_int (value, cell->text_column); + g_value_set_int (value, priv->text_column); break; case PROP_HAS_ENTRY: - g_value_set_boolean (value, cell->has_entry); + g_value_set_boolean (value, priv->has_entry); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } @@ -209,38 +292,48 @@ gtk_cell_renderer_combo_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - GtkCellRendererCombo *cell; - - g_return_if_fail (GTK_IS_CELL_RENDERER_COMBO (object)); - - cell = GTK_CELL_RENDERER_COMBO (object); + GtkCellRendererCombo *cell = GTK_CELL_RENDERER_COMBO (object); + GtkCellRendererComboPrivate *priv = cell->priv; switch (prop_id) { case PROP_MODEL: { - GObject *object; - - object = g_value_get_object (value); - g_return_if_fail (GTK_IS_TREE_MODEL (object)); - g_object_ref (object); - - if (cell->model) - { - g_object_unref (cell->model); - cell->model = NULL; - } - cell->model = GTK_TREE_MODEL (object); - break; + if (priv->model) + g_object_unref (priv->model); + priv->model = GTK_TREE_MODEL (g_value_get_object (value)); + if (priv->model) + g_object_ref (priv->model); + break; } case PROP_TEXT_COLUMN: - cell->text_column = g_value_get_int (value); + priv->text_column = g_value_get_int (value); break; case PROP_HAS_ENTRY: - cell->has_entry = g_value_get_boolean (value); + priv->has_entry = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_cell_renderer_combo_changed (GtkComboBox *combo, + gpointer data) +{ + GtkTreeIter iter; + GtkCellRendererCombo *cell; + + cell = GTK_CELL_RENDERER_COMBO (data); + + if (gtk_combo_box_get_active_iter (combo, &iter)) + { + const char *path; + + path = g_object_get_data (G_OBJECT (combo), GTK_CELL_RENDERER_COMBO_PATH); + g_signal_emit (cell, cell_renderer_combo_signals[CHANGED], 0, + path, &iter); } } @@ -255,21 +348,28 @@ gtk_cell_renderer_combo_editing_done (GtkCellEditable *combo, GtkCellRendererCombo *cell; GtkEntry *entry; gboolean canceled; + GtkCellRendererComboPrivate *priv; cell = GTK_CELL_RENDERER_COMBO (data); + priv = cell->priv; - if (cell->focus_out_id > 0) + if (priv->focus_out_id > 0) { - g_signal_handler_disconnect (combo, cell->focus_out_id); - cell->focus_out_id = 0; + g_signal_handler_disconnect (combo, priv->focus_out_id); + priv->focus_out_id = 0; } - - canceled = _gtk_combo_box_editing_canceled (GTK_COMBO_BOX (combo)); + + g_object_get (combo, + "editing-canceled", &canceled, + NULL); gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), canceled); if (canceled) - return; + { + priv->combo = NULL; + return; + } - if (GTK_IS_COMBO_BOX_ENTRY (combo)) + if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (combo))) { entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo))); new_text = g_strdup (gtk_entry_get_text (entry)); @@ -277,13 +377,17 @@ gtk_cell_renderer_combo_editing_done (GtkCellEditable *combo, else { model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); - if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) - gtk_tree_model_get (model, &iter, cell->text_column, &new_text, -1); + + if (model + && gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) + gtk_tree_model_get (model, &iter, priv->text_column, &new_text, -1); } path = g_object_get_data (G_OBJECT (combo), GTK_CELL_RENDERER_COMBO_PATH); g_signal_emit_by_name (cell, "edited", path, new_text); + priv->combo = NULL; + g_free (new_text); } @@ -311,17 +415,23 @@ find_text (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { + GtkCellRendererComboPrivate *priv; SearchData *search_data = (SearchData *)data; - gchar *text; + gchar *text, *cell_text; + + priv = search_data->cell->priv; - gtk_tree_model_get (model, iter, search_data->cell->text_column, &text, -1); - if (text && GTK_CELL_RENDERER_TEXT (search_data->cell)->text && - strcmp (text, GTK_CELL_RENDERER_TEXT (search_data->cell)->text) == 0) + gtk_tree_model_get (model, iter, priv->text_column, &text, -1); + g_object_get (GTK_CELL_RENDERER_TEXT (search_data->cell), + "text", &cell_text, + NULL); + if (text && cell_text && g_strcmp0 (text, cell_text) == 0) { search_data->iter = *iter; search_data->found = TRUE; } + g_free (cell_text); g_free (text); return search_data->found; @@ -329,66 +439,90 @@ find_text (GtkTreeModel *model, static GtkCellEditable * gtk_cell_renderer_combo_start_editing (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkCellRendererState flags) + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags) { GtkCellRendererCombo *cell_combo; GtkCellRendererText *cell_text; GtkWidget *combo; SearchData search_data; + GtkCellRendererComboPrivate *priv; + gboolean editable; + gchar *text; cell_text = GTK_CELL_RENDERER_TEXT (cell); - if (cell_text->editable == FALSE) + g_object_get (cell_text, "editable", &editable, NULL); + if (editable == FALSE) return NULL; cell_combo = GTK_CELL_RENDERER_COMBO (cell); - if (cell_combo->model == NULL || cell_combo->text_column < 0) + priv = cell_combo->priv; + + if (priv->text_column < 0) return NULL; - if (cell_combo->has_entry) + if (priv->has_entry) { - combo = gtk_combo_box_entry_new_with_model (cell_combo->model, cell_combo->text_column); - - if (cell_text->text) - gtk_entry_set_text (GTK_ENTRY (GTK_BIN (combo)->child), - cell_text->text); + combo = g_object_new (GTK_TYPE_COMBO_BOX, "has-entry", TRUE, NULL); + + if (priv->model) + gtk_combo_box_set_model (GTK_COMBO_BOX (combo), priv->model); + gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (combo), + priv->text_column); + + g_object_get (cell_text, "text", &text, NULL); + if (text) + gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo))), + text); + g_free (text); } else { cell = gtk_cell_renderer_text_new (); - combo = gtk_combo_box_new_with_model (cell_combo->model); + + combo = gtk_combo_box_new (); + if (priv->model) + gtk_combo_box_set_model (GTK_COMBO_BOX (combo), priv->model); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), - cell, "text", cell_combo->text_column, + cell, "text", priv->text_column, NULL); /* determine the current value */ - search_data.cell = cell_combo; - search_data.found = FALSE; - gtk_tree_model_foreach (cell_combo->model, find_text, &search_data); - if (search_data.found) - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), - &(search_data.iter)); + if (priv->model) + { + search_data.cell = cell_combo; + search_data.found = FALSE; + gtk_tree_model_foreach (priv->model, find_text, &search_data); + if (search_data.found) + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), + &(search_data.iter)); + } } - g_object_set (combo, "has_frame", FALSE, NULL); + g_object_set (combo, "has-frame", FALSE, NULL); g_object_set_data_full (G_OBJECT (combo), - GTK_CELL_RENDERER_COMBO_PATH, + I_(GTK_CELL_RENDERER_COMBO_PATH), g_strdup (path), g_free); gtk_widget_show (combo); - g_signal_connect (GTK_CELL_EDITABLE (combo), "editing_done", + g_signal_connect (GTK_CELL_EDITABLE (combo), "editing-done", G_CALLBACK (gtk_cell_renderer_combo_editing_done), cell_combo); - cell_combo->focus_out_id = - g_signal_connect (combo, "focus_out_event", - G_CALLBACK (gtk_cell_renderer_combo_focus_out_event), - cell_combo); + g_signal_connect (GTK_CELL_EDITABLE (combo), "changed", + G_CALLBACK (gtk_cell_renderer_combo_changed), + cell_combo); + priv->focus_out_id = g_signal_connect (combo, "focus-out-event", + G_CALLBACK (gtk_cell_renderer_combo_focus_out_event), + cell_combo); + + priv->combo = combo; return GTK_CELL_EDITABLE (combo); }