]> Pileus Git - ~andy/gtk/blob - gtk/gtkcomboboxentry.c
Silently return NULL if the widget is not realized. (#316023, Guillaume
[~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 <config.h>
21 #include "gtkcomboboxentry.h"
22 #include "gtkcelllayout.h"
23
24 #include "gtkentry.h"
25 #include "gtkcellrenderertext.h"
26
27 #include "gtkprivate.h"
28 #include "gtkintl.h"
29 #include "gtkalias.h"
30
31 #define GTK_COMBO_BOX_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX_ENTRY, GtkComboBoxEntryPrivate))
32
33 struct _GtkComboBoxEntryPrivate
34 {
35   GtkWidget *entry;
36
37   GtkCellRenderer *text_renderer;
38   gint text_column;
39 };
40
41 static void gtk_combo_box_entry_class_init       (GtkComboBoxEntryClass *klass);
42 static void gtk_combo_box_entry_init             (GtkComboBoxEntry      *entry_box);
43
44 static void gtk_combo_box_entry_set_property     (GObject               *object,
45                                                   guint                  prop_id,
46                                                   const GValue          *value,
47                                                   GParamSpec            *pspec);
48 static void gtk_combo_box_entry_get_property     (GObject               *object,
49                                                   guint                  prop_id,
50                                                   GValue                *value,
51                                                   GParamSpec            *pspec);
52
53 static gchar *gtk_combo_box_entry_get_active_text (GtkComboBox *combo_box);
54 static void gtk_combo_box_entry_active_changed   (GtkComboBox           *combo_box,
55                                                   gpointer               user_data);
56 static void gtk_combo_box_entry_contents_changed (GtkEntry              *entry,
57                                                   gpointer               user_data);
58 static gboolean gtk_combo_box_entry_mnemonic_activate (GtkWidget        *entry,
59                                                        gboolean          group_cycling);
60 static void gtk_combo_box_entry_grab_focus       (GtkWidget *widget);
61 static void has_frame_changed                    (GtkComboBoxEntry      *entry_box,
62                                                   GParamSpec            *pspec,
63                                                   gpointer               data);
64
65 enum
66 {
67   PROP_0,
68   PROP_TEXT_COLUMN
69 };
70
71
72 GType
73 gtk_combo_box_entry_get_type (void)
74 {
75   static GType combo_box_entry_type = 0;
76
77   if (!combo_box_entry_type)
78     {
79       static const GTypeInfo combo_box_entry_info =
80         {
81           sizeof (GtkComboBoxEntryClass),
82           NULL, /* base_init */
83           NULL, /* base_finalize */
84           (GClassInitFunc) gtk_combo_box_entry_class_init,
85           NULL, /* class_finalize */
86           NULL, /* class_data */
87           sizeof (GtkComboBoxEntry),
88           0,
89           (GInstanceInitFunc) gtk_combo_box_entry_init
90         };
91
92       combo_box_entry_type = g_type_register_static (GTK_TYPE_COMBO_BOX,
93                                                      I_("GtkComboBoxEntry"),
94                                                      &combo_box_entry_info,
95                                                      0);
96     }
97
98   return combo_box_entry_type;
99 }
100
101 static void
102 gtk_combo_box_entry_class_init (GtkComboBoxEntryClass *klass)
103 {
104   GObjectClass *object_class;
105   GtkWidgetClass *widget_class;
106   GtkComboBoxClass *combo_class;
107   
108   object_class = (GObjectClass *)klass;
109   object_class->set_property = gtk_combo_box_entry_set_property;
110   object_class->get_property = gtk_combo_box_entry_get_property;
111
112   widget_class = (GtkWidgetClass *)klass;
113   widget_class->mnemonic_activate = gtk_combo_box_entry_mnemonic_activate;
114   widget_class->grab_focus = gtk_combo_box_entry_grab_focus;
115
116   combo_class = (GtkComboBoxClass *)klass;
117   combo_class->get_active_text = gtk_combo_box_entry_get_active_text;
118   
119   g_object_class_install_property (object_class,
120                                    PROP_TEXT_COLUMN,
121                                    g_param_spec_int ("text-column",
122                                                      P_("Text Column"),
123                                                      P_("A column in the data source model to get the strings from"),
124                                                      -1,
125                                                      G_MAXINT,
126                                                      -1,
127                                                      GTK_PARAM_READWRITE));
128
129   g_type_class_add_private ((GObjectClass *) klass,
130                             sizeof (GtkComboBoxEntryPrivate));
131 }
132
133 static void
134 gtk_combo_box_entry_init (GtkComboBoxEntry *entry_box)
135 {
136   entry_box->priv = GTK_COMBO_BOX_ENTRY_GET_PRIVATE (entry_box);
137   entry_box->priv->text_column = -1;
138
139   entry_box->priv->entry = gtk_entry_new ();
140   /* this flag is a hack to tell the entry to fill its allocation.
141    */
142   GTK_ENTRY (entry_box->priv->entry)->is_cell_renderer = TRUE;
143   gtk_container_add (GTK_CONTAINER (entry_box), entry_box->priv->entry);
144   gtk_widget_show (entry_box->priv->entry);
145
146   entry_box->priv->text_renderer = gtk_cell_renderer_text_new ();
147   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry_box),
148                               entry_box->priv->text_renderer, TRUE);
149
150   gtk_combo_box_set_active (GTK_COMBO_BOX (entry_box), -1);
151
152   g_signal_connect (entry_box->priv->entry, "changed",
153                     G_CALLBACK (gtk_combo_box_entry_contents_changed),
154                     entry_box);
155   g_signal_connect (entry_box, "changed",
156                     G_CALLBACK (gtk_combo_box_entry_active_changed), NULL);
157   has_frame_changed (entry_box, NULL, NULL);
158   g_signal_connect (entry_box, "notify::has-frame", G_CALLBACK (has_frame_changed), NULL);
159 }
160
161 static void
162 gtk_combo_box_entry_set_property (GObject      *object,
163                                   guint         prop_id,
164                                   const GValue *value,
165                                   GParamSpec   *pspec)
166 {
167   GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (object);
168
169   switch (prop_id)
170     {
171       case PROP_TEXT_COLUMN:
172         gtk_combo_box_entry_set_text_column (entry_box,
173                                              g_value_get_int (value));
174         break;
175
176       default:
177         break;
178     }
179 }
180
181 static void
182 gtk_combo_box_entry_get_property (GObject    *object,
183                                   guint       prop_id,
184                                   GValue     *value,
185                                   GParamSpec *pspec)
186 {
187   GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (object);
188
189   switch (prop_id)
190     {
191       case PROP_TEXT_COLUMN:
192         g_value_set_int (value, entry_box->priv->text_column);
193         break;
194
195       default:
196         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
197         break;
198     }
199 }
200
201 static void
202 gtk_combo_box_entry_active_changed (GtkComboBox *combo_box,
203                                     gpointer     user_data)
204 {
205   GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (combo_box);
206   GtkTreeModel *model;
207   GtkTreeIter iter;
208   gchar *str = NULL;
209
210   if (gtk_combo_box_get_active_iter (combo_box, &iter))
211     {
212       g_signal_handlers_block_by_func (entry_box->priv->entry,
213                                        gtk_combo_box_entry_contents_changed,
214                                        combo_box);
215
216       model = gtk_combo_box_get_model (combo_box);
217
218       gtk_tree_model_get (model, &iter, 
219                           entry_box->priv->text_column, &str, 
220                           -1);
221       gtk_entry_set_text (GTK_ENTRY (entry_box->priv->entry), str);
222       g_free (str);
223
224       g_signal_handlers_unblock_by_func (entry_box->priv->entry,
225                                          gtk_combo_box_entry_contents_changed,
226                                          combo_box);
227     }
228 }
229
230 static void 
231 has_frame_changed (GtkComboBoxEntry *entry_box,
232                    GParamSpec       *pspec,
233                    gpointer          data)
234 {
235   gboolean has_frame;
236   
237   g_object_get (entry_box, "has-frame", &has_frame, NULL);
238
239   gtk_entry_set_has_frame (GTK_ENTRY (entry_box->priv->entry), has_frame);
240 }
241
242 static void
243 gtk_combo_box_entry_contents_changed (GtkEntry *entry,
244                                       gpointer  user_data)
245 {
246   GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
247
248   g_signal_handlers_block_by_func (combo_box,
249                                    gtk_combo_box_entry_active_changed,
250                                    NULL);
251   gtk_combo_box_set_active (combo_box, -1);
252   g_signal_handlers_unblock_by_func (combo_box,
253                                      gtk_combo_box_entry_active_changed,
254                                      NULL);
255 }
256
257 /* public API */
258
259 /**
260  * gtk_combo_box_entry_new:
261  *
262  * Creates a new #GtkComboBoxEntry which has a #GtkEntry as child. After
263  * construction, you should set a model using gtk_combo_box_set_model() and a
264  * text_column * using gtk_combo_box_entry_set_text_column().
265  *
266  * Return value: A new #GtkComboBoxEntry.
267  *
268  * Since: 2.4
269  */
270 GtkWidget *
271 gtk_combo_box_entry_new (void)
272 {
273   return g_object_new (gtk_combo_box_entry_get_type (), NULL);
274 }
275
276 /**
277  * gtk_combo_box_entry_new_with_model:
278  * @model: A #GtkTreeModel.
279  * @text_column: A column in @model to get the strings from.
280  *
281  * Creates a new #GtkComboBoxEntry which has a #GtkEntry as child and a list
282  * of strings as popup. You can get the #GtkEntry from a #GtkComboBoxEntry
283  * using GTK_ENTRY (GTK_BIN (combo_box_entry)->child). To add and remove
284  * strings from the list, just modify @model using its data manipulation
285  * API.
286  *
287  * Return value: A new #GtkComboBoxEntry.
288  *
289  * Since: 2.4
290  */
291 GtkWidget *
292 gtk_combo_box_entry_new_with_model (GtkTreeModel *model,
293                                     gint          text_column)
294 {
295   GtkWidget *ret;
296
297   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
298   g_return_val_if_fail (text_column >= 0, NULL);
299   g_return_val_if_fail (text_column < gtk_tree_model_get_n_columns (model), NULL);
300
301   ret = g_object_new (gtk_combo_box_entry_get_type (),
302                       "model", model,
303                       "text-column", text_column,
304                       NULL);
305
306   return ret;
307 }
308
309 /**
310  * gtk_combo_box_entry_set_text_column:
311  * @entry_box: A #GtkComboBoxEntry.
312  * @text_column: A column in @model to get the strings from.
313  *
314  * Sets the model column which @entry_box should use to get strings from
315  * to be @text_column.
316  *
317  * Since: 2.4.
318  */
319 void
320 gtk_combo_box_entry_set_text_column (GtkComboBoxEntry *entry_box,
321                                      gint              text_column)
322 {
323   g_return_if_fail (text_column >= 0);
324   g_return_if_fail (text_column < gtk_tree_model_get_n_columns (gtk_combo_box_get_model (GTK_COMBO_BOX (entry_box))));
325   g_return_if_fail (entry_box->priv->text_column == -1);
326
327   entry_box->priv->text_column = text_column;
328
329   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (entry_box),
330                                   entry_box->priv->text_renderer,
331                                   "text", text_column,
332                                   NULL);
333 }
334
335 /**
336  * gtk_combo_box_entry_get_text_column:
337  * @entry_box: A #GtkComboBoxEntry.
338  *
339  * Returns the column which @entry_box is using to get the strings from.
340  *
341  * Return value: A column in the data source model of @entry_box.
342  *
343  * Since: 2.4
344  */
345 gint
346 gtk_combo_box_entry_get_text_column (GtkComboBoxEntry *entry_box)
347 {
348   g_return_val_if_fail (GTK_IS_COMBO_BOX_ENTRY (entry_box), 0);
349
350   return entry_box->priv->text_column;
351 }
352
353 static gboolean
354 gtk_combo_box_entry_mnemonic_activate (GtkWidget *widget,
355                                        gboolean   group_cycling)
356 {
357   GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (widget);
358
359   gtk_widget_grab_focus (entry_box->priv->entry);
360
361   return TRUE;
362 }
363
364 static void
365 gtk_combo_box_entry_grab_focus (GtkWidget *widget)
366 {
367   GtkComboBoxEntry *entry_box = GTK_COMBO_BOX_ENTRY (widget);
368
369   gtk_widget_grab_focus (entry_box->priv->entry);
370 }
371
372
373
374 /* convenience API for simple text combos */
375
376 /**
377  * gtk_combo_box_entry_new_text:
378  *
379  * Convenience function which constructs a new editable text combo box, which 
380  * is a #GtkComboBoxEntry just displaying strings. If you use this function to
381  * create a text combo box, you should only manipulate its data source with
382  * the following convenience functions: gtk_combo_box_append_text(),
383  * gtk_combo_box_insert_text(), gtk_combo_box_prepend_text() and
384  * gtk_combo_box_remove_text().
385  *
386  * Return value: A new text #GtkComboBoxEntry.
387  *
388  * Since: 2.4
389  */
390 GtkWidget *
391 gtk_combo_box_entry_new_text (void)
392 {
393   GtkWidget *entry_box;
394   GtkListStore *store;
395
396   store = gtk_list_store_new (1, G_TYPE_STRING);
397   entry_box = gtk_combo_box_entry_new_with_model (GTK_TREE_MODEL (store), 0);
398   g_object_unref (store);
399
400   return entry_box;
401 }
402
403 static gchar *
404 gtk_combo_box_entry_get_active_text (GtkComboBox *combo_box)
405 {
406   GtkComboBoxEntry *combo = GTK_COMBO_BOX_ENTRY (combo_box);
407
408   if (combo->priv->entry)
409     return g_strdup (gtk_entry_get_text (GTK_ENTRY (combo->priv->entry)));
410
411   return NULL;
412 }
413
414 #define __GTK_COMBO_BOX_ENTRY_C__
415 #include "gtkaliasdef.c"