810e02f59694cc6246f59b9f2b760136eadc5b26
[modest] / src / widgets / modest-combo-box.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <gtk/gtk.h>
31 #include "modest-combo-box.h"
32
33 /* 'private'/'protected' functions */
34 static void modest_combo_box_class_init (ModestComboBoxClass *klass);
35 static void modest_combo_box_init       (ModestComboBox *obj);
36 static void modest_combo_box_finalize   (GObject *obj);
37 /* list my signals  */
38 enum {
39         /* MY_SIGNAL_1, */
40         /* MY_SIGNAL_2, */
41         LAST_SIGNAL
42 };
43
44
45 enum {
46         COLUMN_ID,
47         COLUMN_DISPLAY_NAME,
48         COLUMN_NUM
49 };
50
51 typedef struct _ModestComboBoxPrivate ModestComboBoxPrivate;
52 struct _ModestComboBoxPrivate {
53         GEqualFunc id_equal_func;
54         
55 };
56 #define MODEST_COMBO_BOX_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
57                                               MODEST_TYPE_COMBO_BOX, \
58                                               ModestComboBoxPrivate))
59 /* globals */
60 static GObjectClass *parent_class = NULL;
61
62 /* uncomment the following if you have defined any signals */
63 /* static guint signals[LAST_SIGNAL] = {0}; */
64
65 GType
66 modest_combo_box_get_type (void)
67 {
68         static GType my_type = 0;
69         if (!my_type) {
70                 static const GTypeInfo my_info = {
71                         sizeof(ModestComboBoxClass),
72                         NULL,           /* base init */
73                         NULL,           /* base finalize */
74                         (GClassInitFunc) modest_combo_box_class_init,
75                         NULL,           /* class finalize */
76                         NULL,           /* class data */
77                         sizeof(ModestComboBox),
78                         1,              /* n_preallocs */
79                         (GInstanceInitFunc) modest_combo_box_init,
80                         NULL
81                 };
82                 my_type = g_type_register_static (GTK_TYPE_COMBO_BOX,
83                                                   "ModestComboBox",
84                                                   &my_info, 0);
85         }
86         return my_type;
87 }
88
89 static void
90 modest_combo_box_class_init (ModestComboBoxClass *klass)
91 {
92         GObjectClass *gobject_class;
93         gobject_class = (GObjectClass*) klass;
94
95         parent_class            = g_type_class_peek_parent (klass);
96         gobject_class->finalize = modest_combo_box_finalize;
97
98         g_type_class_add_private (gobject_class, sizeof(ModestComboBoxPrivate));
99
100         /* signal definitions go here, e.g.: */
101 /*      signals[MY_SIGNAL_1] = */
102 /*              g_signal_new ("my_signal_1",....); */
103 /*      signals[MY_SIGNAL_2] = */
104 /*              g_signal_new ("my_signal_2",....); */
105 /*      etc. */
106 }
107
108 static void
109 modest_combo_box_init (ModestComboBox *obj)
110 {
111 /* uncomment the following if you init any of the private data */
112 /*      ModestComboBoxPrivate *priv = MODEST_COMBO_BOX_GET_PRIVATE(obj); */
113
114 /*      initialize this object, eg.: */
115 /*      priv->frobnicate_mode = FALSE; */
116 }
117
118 static void
119 modest_combo_box_finalize (GObject *obj)
120 {
121 /*      free/unref instance resources here */
122         G_OBJECT_CLASS(parent_class)->finalize (obj);
123 }
124
125 static GtkTreeModel*
126 get_model (ModestPairList *pairs)
127 {
128         GtkTreeIter iter;
129         GtkListStore *store;
130         GSList *cursor;
131         
132         store = gtk_list_store_new (2,
133                                     G_TYPE_POINTER, /* the id */
134                                     G_TYPE_STRING); /* the display name */
135         cursor = pairs;
136         while (cursor) {
137                 ModestPair *pair = (ModestPair*)cursor->data;
138                 gtk_list_store_insert_with_values (store, &iter, G_MAXINT,
139                                                    COLUMN_ID,           pair->first,
140                                                    COLUMN_DISPLAY_NAME, pair->second,
141                                                    -1);
142                 cursor = cursor->next;
143         }
144         
145         return GTK_TREE_MODEL (store);
146 }
147
148 void
149 modest_combo_box_set_pair_list (ModestComboBox *combo, ModestPairList *pairs)
150 {
151         GtkTreeModel *model;
152
153         model = get_model (pairs);
154
155         gtk_combo_box_set_model (GTK_COMBO_BOX(combo), model);
156         g_object_unref (model);
157         
158         gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
159 }
160
161
162
163 GtkWidget*
164 modest_combo_box_new (ModestPairList *pairs, GEqualFunc id_equal_func)
165 {
166         GtkTreeModel *model;
167         GtkCellRenderer *renderer;
168         GObject *obj;
169         ModestComboBoxPrivate *priv;
170
171         obj  = G_OBJECT(g_object_new(MODEST_TYPE_COMBO_BOX, NULL));
172         priv = MODEST_COMBO_BOX_GET_PRIVATE(obj);
173         
174         model = get_model (pairs);
175         if (model) {
176                 gtk_combo_box_set_model (GTK_COMBO_BOX(obj), model);
177                 g_object_unref (model);
178                 gtk_cell_layout_clear (GTK_CELL_LAYOUT(obj));
179                 
180                 renderer = gtk_cell_renderer_text_new ();
181                 g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
182                 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(obj),
183                                             renderer, TRUE);  
184                 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(obj),
185                                                 renderer, "text",
186                                                 COLUMN_DISPLAY_NAME, NULL); 
187         }
188
189         gtk_combo_box_set_active (GTK_COMBO_BOX(obj), 0);
190
191         if (id_equal_func)
192                 priv->id_equal_func = id_equal_func;
193         else
194                 priv->id_equal_func = g_direct_equal; /* compare the ptr values */
195         
196         return GTK_WIDGET(obj);
197 }
198
199
200
201 static void
202 get_active (ModestComboBox *self, GValue *val, gint column)
203 {
204         GtkTreeIter iter;
205         g_return_if_fail (self);
206
207         if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(self), &iter)) {
208                 GtkTreeModel *model;
209                 
210                 model = gtk_combo_box_get_model (GTK_COMBO_BOX(self));
211                 gtk_tree_model_get_value (model, &iter, column, val);
212         }
213 }
214
215 gpointer
216 modest_combo_box_get_active_id (ModestComboBox *self)
217 {
218         GValue val = {0,};
219
220         g_return_val_if_fail (self, NULL);
221         
222         /* Do not unset the GValue */
223         get_active (self, &val, COLUMN_ID);
224
225         return g_value_get_pointer (&val);
226 }
227
228
229 void
230 modest_combo_box_set_active_id (ModestComboBox *self, gpointer id)
231 {
232         GtkTreeModel *model;
233         GtkTreeIter iter;
234         ModestComboBoxPrivate *priv;
235         gboolean found = FALSE;
236         
237         g_return_if_fail (self);
238
239         priv = MODEST_COMBO_BOX_GET_PRIVATE(self);
240         
241         model = gtk_combo_box_get_model (GTK_COMBO_BOX(self));
242         if (!gtk_tree_model_get_iter_first (model, &iter))
243                 return; /* empty list */
244
245         do {
246                 gpointer row_id;
247                 gtk_tree_model_get (model, &iter, COLUMN_ID, &row_id, -1);
248                 if ((priv->id_equal_func)(id, row_id)) {
249                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX(self), &iter);
250                         found = TRUE;
251                 }
252         } while (!found && gtk_tree_model_iter_next (model, &iter));
253
254         if (!found)
255                 g_printerr ("modest: could not set the active id\n"); 
256 }
257
258
259
260 const gchar*
261 modest_combo_box_get_active_display_name (ModestComboBox *self)
262 {
263         const GValue val = {0,};
264         const gchar *retval;
265
266         g_return_val_if_fail (self, NULL);
267
268         /* Do not unset the GValue */
269         get_active (self, (GValue *)&val, COLUMN_DISPLAY_NAME);
270         retval = g_value_get_string (&val);
271
272         return retval;
273 }