Fix warning
[claws.git] / src / gtk / combobox.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2006-2012 Andrej Kacian and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #include "claws-features.h"
23 #endif
24
25 #include <glib.h>
26 #include <glib/gi18n.h>
27 #include <gdk/gdkkeysyms.h>
28 #include <gtk/gtk.h>
29 #include "gtkutils.h"
30 #include "combobox.h"
31 #include "utils.h"
32
33 typedef struct _combobox_sel_by_data_ctx {
34         GtkComboBox *combobox;
35         gint data;
36         const gchar *cdata;
37 } ComboboxSelCtx;
38
39 GtkWidget *combobox_text_new(const gboolean with_entry, const gchar *text, ...)
40 {
41         GtkWidget *combo;
42         va_list args;
43         gchar *string;
44         
45         if(text == NULL)
46                 return NULL;
47         
48 #if !GTK_CHECK_VERSION(2, 24, 0)
49         if (with_entry)
50                 combo = gtk_combo_box_entry_new_text();
51         else
52                 combo = gtk_combo_box_new_text();
53 #else
54         if (with_entry)
55                 combo = gtk_combo_box_text_new_with_entry();
56         else
57                 combo = gtk_combo_box_text_new();
58 #endif
59         gtk_widget_show(combo);
60
61 #if !GTK_CHECK_VERSION(2, 24, 0)
62         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), text);
63 #else
64         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), text);
65 #endif
66         va_start(args, text);
67         while ((string = va_arg(args, gchar*)) != NULL)
68 #if !GTK_CHECK_VERSION(2, 24, 0)
69                 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), string);
70 #else
71                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), string);
72 #endif
73         va_end(args);
74                 
75         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
76         
77         return combo;
78 }
79
80 static gboolean _select_by_data_func(GtkTreeModel *model,       GtkTreePath *path,
81                 GtkTreeIter *iter, ComboboxSelCtx *ctx)
82 {
83         GtkComboBox *combobox = ctx->combobox;
84         gint data = ctx->data;
85         gint curdata;
86
87         gtk_tree_model_get(GTK_TREE_MODEL(model), iter, COMBOBOX_DATA, &curdata, -1);
88         if (data == curdata) {
89                 gtk_combo_box_set_active_iter(combobox, iter);
90                 return TRUE;
91         }
92
93         return FALSE;
94 }
95
96 void combobox_select_by_data(GtkComboBox *combobox, gint data)
97 {
98         GtkTreeModel *model;
99         ComboboxSelCtx *ctx = NULL;
100
101         cm_return_if_fail(combobox != NULL);
102         cm_return_if_fail(GTK_IS_COMBO_BOX (combobox));
103
104         model = gtk_combo_box_get_model(combobox);
105
106         ctx = g_new(ComboboxSelCtx,
107                         sizeof(ComboboxSelCtx));
108         ctx->combobox = combobox;
109         ctx->data = data;
110
111         gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)_select_by_data_func, ctx);
112         g_free(ctx);
113 }
114
115 static gboolean _select_by_text_func(GtkTreeModel *model,       GtkTreePath *path,
116                 GtkTreeIter *iter, ComboboxSelCtx *ctx)
117 {
118         GtkComboBox *combobox = ctx->combobox;
119         const gchar *data = ctx->cdata;
120         gchar *curdata;
121
122         cm_return_val_if_fail(combobox != NULL, FALSE);
123         cm_return_val_if_fail(GTK_IS_COMBO_BOX (combobox), FALSE);
124
125         gtk_tree_model_get (GTK_TREE_MODEL(model), iter, 0, &curdata, -1);
126         if (!g_utf8_collate(data, curdata)) {
127                 gtk_combo_box_set_active_iter(combobox, iter);
128                 g_free(curdata);
129                 return TRUE;
130         } else {
131                 g_free(curdata);
132         }
133
134         return FALSE;
135 }
136
137 void combobox_select_by_text(GtkComboBox *combobox, const gchar *data)
138 {
139         GtkTreeModel *model;
140         ComboboxSelCtx *ctx = NULL;
141 #if !GTK_CHECK_VERSION(2, 24, 0)
142         GtkComboBoxClass *class;
143 #endif
144
145         cm_return_if_fail(combobox != NULL);
146 #if !GTK_CHECK_VERSION(2, 24, 0)
147         class = GTK_COMBO_BOX_GET_CLASS (combobox);
148
149         /* we can do that only with gtk_combo_box_new_text() combo boxes */
150         cm_return_if_fail(class->get_active_text != NULL);
151 #else
152         cm_return_if_fail(GTK_IS_COMBO_BOX (combobox));
153 #endif
154
155         model = gtk_combo_box_get_model(combobox);
156
157         ctx = g_new(ComboboxSelCtx,
158                         sizeof(ComboboxSelCtx));
159         ctx->combobox = combobox;
160         ctx->cdata = data;
161
162         gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)_select_by_text_func, ctx);
163         g_free(ctx);
164 }
165
166 gint combobox_get_active_data(GtkComboBox *combobox)
167 {
168         GtkTreeModel *model;
169         GtkTreeIter iter;
170         gint data;
171
172         cm_return_val_if_fail(combobox != NULL, -1);
173         cm_return_val_if_fail(GTK_IS_COMBO_BOX (combobox), -1);
174         cm_return_val_if_fail(gtk_combo_box_get_active_iter(combobox, &iter), -1);
175
176         model = gtk_combo_box_get_model(combobox);
177
178         gtk_tree_model_get(model, &iter, COMBOBOX_DATA, &data, -1);
179
180         return data;
181 }
182
183 #if !GTK_CHECK_VERSION(2, 24, 0)
184 void combobox_unset_popdown_strings(GtkComboBox *combobox)
185 #else
186 void combobox_unset_popdown_strings(GtkComboBoxText *combobox)
187 #endif
188 {
189         GtkTreeModel *model;
190         gint count, i;
191
192         cm_return_if_fail(combobox != NULL);
193 #if GTK_CHECK_VERSION(2, 24, 0)
194         cm_return_if_fail(GTK_IS_COMBO_BOX_TEXT (combobox));
195 #endif
196
197         model = gtk_combo_box_get_model(GTK_COMBO_BOX(combobox));
198         count = gtk_tree_model_iter_n_children(model, NULL);
199         for (i = 0; i < count; i++)
200 #if !GTK_CHECK_VERSION(2, 24, 0)
201                 gtk_combo_box_remove_text(combobox, 0);
202 #else
203                 gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(combobox), 0);
204 #endif
205 }
206
207 #if !GTK_CHECK_VERSION(2, 24, 0)
208 void combobox_set_popdown_strings(GtkComboBox *combobox,
209 #else
210 void combobox_set_popdown_strings(GtkComboBoxText *combobox,
211 #endif
212                                  GList       *list)
213 {
214         GList *cur;
215
216         cm_return_if_fail(combobox != NULL);
217 #if GTK_CHECK_VERSION(2, 24, 0)
218         cm_return_if_fail(GTK_IS_COMBO_BOX_TEXT (combobox));
219 #endif
220
221         for (cur = list; cur != NULL; cur = g_list_next(cur))
222 #if !GTK_CHECK_VERSION(2, 24, 0)
223                 gtk_combo_box_append_text(combobox, (const gchar*) cur->data);
224 #else
225                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combobox),
226                                                 (const gchar*) cur->data);
227 #endif
228 }
229
230 gboolean combobox_set_value_from_arrow_key(GtkComboBox *combobox,
231                                  guint keyval)
232 /* used from key_press events upon gtk_combo_box_entry with one text column 
233    (gtk_combo_box_new_text() and with GtkComboBoxEntry's for instance),
234    make sure that up and down arrow keys behave the same as old with old
235    gtk_combo widgets:
236     when pressing Up:
237           if the current text in entry widget is not found in combo list,
238             get last value from combo list
239           if the current text in entry widget exists in combo list,
240             get prev value from combo list
241     when pressing Down:
242           if the current text in entry widget is not found in combo list,
243             get first value from combo list
244           if the current text in entry widget exists in combo list,
245             get next value from combo list
246 */
247 {
248         gboolean valid = FALSE;
249
250         cm_return_val_if_fail(combobox != NULL, FALSE);
251
252         /* reproduce the behaviour of old gtk_combo_box */
253         GtkTreeModel *model = gtk_combo_box_get_model(combobox);
254         GtkTreeIter iter;
255
256         if (gtk_combo_box_get_active_iter(combobox, &iter)) {
257                 /* if current text is in list, get prev or next one */
258
259                 if (keyval == GDK_KEY_Up) {
260 #if !GTK_CHECK_VERSION(2, 24, 0)
261                         gchar *text = gtk_combo_box_get_active_text(combobox);
262                         if (!text)
263                                 text = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(combobox))),0,-1);
264 #else
265                         gchar *text = NULL;
266                         gtk_tree_model_get(model, &iter, 0, &text, -1);
267 #endif
268                         valid = gtkut_tree_model_text_iter_prev(model, &iter, text);
269                         g_free(text);
270                 } else
271                 if (keyval == GDK_KEY_Down)
272                         valid = gtk_tree_model_iter_next(model, &iter);
273
274                 if (valid)
275                         gtk_combo_box_set_active_iter(combobox, &iter);
276
277         } else {
278                 /* current text is not in list, get first or next one */
279
280                 if (keyval == GDK_KEY_Up)
281                         valid = gtkut_tree_model_get_iter_last(model, &iter);
282                 else
283                 if (keyval == GDK_KEY_Down)
284                         valid = gtk_tree_model_get_iter_first(model, &iter);
285
286                 if (valid)
287                         gtk_combo_box_set_active_iter(combobox, &iter);
288         }
289
290         /* return TRUE if value could be set */
291         return valid;
292 }
293
294 static void store_set_sensitive(GtkTreeModel *model, GtkTreeIter *iter,
295                                 const gboolean sensitive)
296 {
297         if(GTK_IS_LIST_STORE(model)) {
298                 gtk_list_store_set(GTK_LIST_STORE(model), iter,
299                                    COMBOBOX_SENS, sensitive,
300                                    -1);
301         } else {
302                 gtk_tree_store_set(GTK_TREE_STORE(model), iter,
303                                    COMBOBOX_SENS, sensitive,
304                                    -1);
305         }
306 }
307
308 void combobox_set_sensitive(GtkComboBox *combobox, const guint index,
309                             const gboolean sensitive)
310 {
311         GtkTreeModel *model;
312         GtkTreeIter iter, child;
313         guint i;
314         
315         if((model = gtk_combo_box_get_model(combobox)) == NULL)
316                 return;
317         
318         gtk_tree_model_get_iter_first(model, &iter);
319         for(i=0; i<index; i++) {
320                 if(gtk_tree_model_iter_next(model, &iter) == FALSE)
321                         return;
322         }
323         
324         store_set_sensitive(model, &iter, sensitive);
325
326         if(gtk_tree_model_iter_children(model, &child, &iter) == FALSE)
327                 return;
328         
329         do {
330                 store_set_sensitive(model, &child, sensitive);
331         } while (gtk_tree_model_iter_next(model, &child) == TRUE);
332 }