]> Pileus Git - ~andy/gtk/blob - gtk/gtkcomboboxentry.c
Fixes #124373, Murray Cumming.
[~andy/gtk] / gtk / gtkcomboboxentry.c
1 /* gtkcomboboxentry.c
2  * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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.
8  *
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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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.
18  */
19
20 #include "gtkcomboboxentry.h"
21 #include "gtkcelllayout.h"
22
23 #include "gtkentry.h"
24 #include "gtkcellrenderertext.h"
25
26 #include "gtkintl.h"
27
28 #define GTK_COMBO_BOX_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX_ENTRY, GtkComboBoxEntryPrivate))
29
30 struct _GtkComboBoxEntryPrivate
31 {
32   GtkWidget *entry;
33
34   GtkCellRenderer *text_renderer;
35   gint text_column;
36 };
37
38 static void gtk_combo_box_entry_class_init       (GtkComboBoxEntryClass *klass);
39 static void gtk_combo_box_entry_init             (GtkComboBoxEntry      *entry_box);
40
41 static void gtk_combo_box_entry_set_property     (GObject               *object,
42                                                   guint                  prop_id,
43                                                   const GValue          *value,
44                                                   GParamSpec            *pspec);
45 static void gtk_combo_box_entry_get_property     (GObject               *object,
46                                                   guint                  prop_id,
47                                                   GValue                *value,
48                                                   GParamSpec            *pspec);
49
50 static void gtk_combo_box_entry_active_changed   (GtkComboBox           *combo_box,
51                                                   gpointer               user_data);
52 static void gtk_combo_box_entry_contents_changed (GtkEntry              *entry,
53                                                   gpointer               user_data);
54
55
56 enum
57 {
58   PROP_0,
59   PROP_TEXT_COLUMN
60 };
61
62
63 GType
64 gtk_combo_box_entry_get_type (void)
65 {
66   static GType combo_box_entry_type = 0;
67
68   if (!combo_box_entry_type)
69     {
70       static const GTypeInfo combo_box_entry_info =
71         {
72           sizeof (GtkComboBoxEntryClass),
73           NULL, /* base_init */
74           NULL, /* base_finalize */
75           (GClassInitFunc) gtk_combo_box_entry_class_init,
76           NULL, /* class_finalize */
77           NULL, /* class_data */
78           sizeof (GtkComboBoxEntry),
79           0,
80           (GInstanceInitFunc) gtk_combo_box_entry_init
81         };
82
83       combo_box_entry_type = g_type_register_static (GTK_TYPE_COMBO_BOX,
84                                                      "GtkComboBoxEntry",
85                                                      &combo_box_entry_info,
86                                                      0);
87     }
88
89   return combo_box_entry_type;
90 }
91
92 static void
93 gtk_combo_box_entry_class_init (GtkComboBoxEntryClass *klass)
94 {
95   GObjectClass *object_class;
96
97   object_class = (GObjectClass *)klass;
98   object_class->set_property = gtk_combo_box_entry_set_property;
99   object_class->get_property = gtk_combo_box_entry_get_property;
100
101   g_object_class_install_property (object_class,
102                                    PROP_TEXT_COLUMN,
103                                    g_param_spec_int ("text_column",
104                                                      _("Text Column"),
105                                                      _("A column in the data source model to get the strings from"),
106                                                      -1,
107                                                      G_MAXINT,
108                                                      -1,
109                                                      G_PARAM_READWRITE));
110
111   g_type_class_add_private ((GObjectClass *) klass,
112                             sizeof (GtkComboBoxEntryPrivate));
113 }
114
115 static void
116 gtk_combo_box_entry_init (GtkComboBoxEntry *entry_box)
117 {
118   entry_box->priv = GTK_COMBO_BOX_ENTRY_GET_PRIVATE (entry_box);
119   entry_box->priv->text_column = -1;
120
121   entry_box->priv->entry = gtk_entry_new ();
122   gtk_container_add (GTK_CONTAINER (entry_box), entry_box->priv->entry);
123   gtk_widget_show (entry_box->priv->entry);
124
125   entry_box->priv->text_renderer = gtk_cell_renderer_text_new ();
126   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry_box),
127                               entry_box->priv->text_renderer, TRUE);
128
129   gtk_combo_box_set_active (GTK_COMBO_BOX (entry_box), -1);
130
131   g_signal_connect (entry_box->priv->entry, "changed",
132                     G_CALLBACK (gtk_combo_box_entry_contents_changed),
133                     entry_box);
134   g_signal_connect (entry_box, "changed",
135                     G_CALLBACK (gtk_combo_box_entry_active_changed), NULL);
136 }
137
138 static void
139 gtk_combo_box_entry_set_property (GObject      *object,
140                                   guint         prop_id,
141                                   const GValue *value,
142                                   GParamSpec   *pspec)
143 {
144   GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (object);
145
146   switch (prop_id)
147     {
148       case PROP_TEXT_COLUMN:
149         gtk_combo_box_entry_set_text_column (entry_box,
150                                              g_value_get_int (value));
151         break;
152
153       default:
154         break;
155     }
156 }
157
158 static void
159 gtk_combo_box_entry_get_property (GObject    *object,
160                                   guint       prop_id,
161                                   GValue     *value,
162                                   GParamSpec *pspec)
163 {
164   GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (object);
165
166   switch (prop_id)
167     {
168       case PROP_TEXT_COLUMN:
169         g_value_set_int (value, entry_box->priv->text_column);
170         break;
171
172       default:
173         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174         break;
175     }
176 }
177
178 static void
179 gtk_combo_box_entry_active_changed (GtkComboBox *combo_box,
180                                     gpointer     user_data)
181 {
182   gint index;
183   GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (combo_box);
184
185   index = gtk_combo_box_get_active (combo_box);
186
187   g_signal_handlers_block_by_func (entry_box->priv->entry,
188                                    gtk_combo_box_entry_contents_changed,
189                                    combo_box);
190
191   if (index >= 0)
192     {
193       gchar *str = NULL;
194       GtkTreeIter iter;
195       GtkTreeModel *model;
196
197       model = gtk_combo_box_get_model (combo_box);
198
199       gtk_tree_model_iter_nth_child (model, &iter, NULL, index);
200       gtk_tree_model_get (model, &iter,
201                           entry_box->priv->text_column, &str,
202                           -1);
203
204       gtk_entry_set_text (GTK_ENTRY (entry_box->priv->entry), str);
205
206       g_free (str);
207     }
208
209   g_signal_handlers_unblock_by_func (entry_box->priv->entry,
210                                      gtk_combo_box_entry_contents_changed,
211                                      combo_box);
212 }
213
214 static void
215 gtk_combo_box_entry_contents_changed (GtkEntry *entry,
216                                       gpointer  user_data)
217 {
218   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
219
220   g_signal_handlers_block_by_func (combo_box,
221                                    gtk_combo_box_entry_active_changed,
222                                    NULL);
223   gtk_combo_box_set_active (combo_box, -1);
224   g_signal_handlers_unblock_by_func (combo_box,
225                                      gtk_combo_box_entry_active_changed,
226                                      NULL);
227 }
228
229 /* public API */
230
231 /**
232  * gtk_combo_box_entry_new:
233  *
234  * Creates a new #GtkComboBoxEntry which has a #GtkEntry as child. After
235  * construction, you should set a model using gtk_combo_box_set_model() and a
236  * text_column * using gtk_combo_box_entry_set_text_column().
237  *
238  * Return value: A new #GtkComboBoxEntry.
239  *
240  * Since: 2.4
241  */
242 GtkWidget *
243 gtk_combo_box_entry_new (void)
244 {
245   return GTK_WIDGET (g_object_new (gtk_combo_box_entry_get_type (), NULL));
246 }
247
248 /**
249  * gtk_combo_box_entry_new_with_model:
250  * @model: A #GtkTreeModel.
251  * @text_column: A column in @model to get the strings from.
252  *
253  * Creates a new #GtkComboBoxEntry which has a #GtkEntry as child and a list
254  * of strings as popup. You can get the #GtkEntry from a #GtkComboBoxEntry
255  * using GTK_ENTRY (GTK_BIN (combo_box_entry)->child). To add and remove
256  * strings from the list, just modify @model using its data manipulation
257  * API.
258  *
259  * Return value: A new #GtkComboBoxEntry.
260  *
261  * Since: 2.4
262  */
263 GtkWidget *
264 gtk_combo_box_entry_new_with_model (GtkTreeModel *model,
265                                     gint          text_column)
266 {
267   GtkWidget *ret;
268
269   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
270   g_return_val_if_fail (text_column >= 0, NULL);
271   g_return_val_if_fail (text_column < gtk_tree_model_get_n_columns (model), NULL);
272
273   ret = g_object_new (gtk_combo_box_entry_get_type (),
274                       "model", model,
275                       "text_column", text_column,
276                       NULL);
277
278   return ret;
279 }
280
281 /**
282  * gtk_combo_box_entry_set_text_column:
283  * @entry_box: A #GtkComboBoxEntry.
284  * @text_column: A column in @model to get the strings from.
285  *
286  * Sets the model column which @entry_box should use to get strings from
287  * to be @text_column.
288  *
289  * Since: 2.4.
290  */
291 void
292 gtk_combo_box_entry_set_text_column (GtkComboBoxEntry *entry_box,
293                                      gint              text_column)
294 {
295   g_return_if_fail (text_column >= 0);
296   g_return_if_fail (text_column < gtk_tree_model_get_n_columns (gtk_combo_box_get_model (GTK_COMBO_BOX (entry_box))));
297   g_return_if_fail (entry_box->priv->text_column == -1);
298
299   entry_box->priv->text_column = text_column;
300
301   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (entry_box),
302                                   entry_box->priv->text_renderer,
303                                   "text", text_column,
304                                   NULL);
305 }
306
307 /**
308  * gtk_combo_box_entry_get_text_column:
309  * @entry_box: A #GtkComboBoxEntry.
310  *
311  * Returns the column which @entry_box is using to get the strings from.
312  *
313  * Return value: A column in the data source model of @entry_box.
314  *
315  * Since: 2.4
316  */
317 gint
318 gtk_combo_box_entry_get_text_column (GtkComboBoxEntry *entry_box)
319 {
320   g_return_val_if_fail (GTK_IS_COMBO_BOX_ENTRY (entry_box), 0);
321
322   return entry_box->priv->text_column;
323 }