2012-07-07 [colin] 3.8.1cvs7
[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 (with_entry)
49                 combo = gtk_combo_box_entry_new_text();
50         else
51                 combo = gtk_combo_box_new_text();
52         gtk_widget_show(combo);
53
54         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), text);
55         va_start(args, text);
56         while ((string = va_arg(args, gchar*)) != NULL)
57                 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), string);
58         va_end(args);
59                 
60         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
61         
62         return combo;
63 }
64
65 static gboolean _select_by_data_func(GtkTreeModel *model,       GtkTreePath *path,
66                 GtkTreeIter *iter, ComboboxSelCtx *ctx)
67 {
68         GtkComboBox *combobox = ctx->combobox;
69         gint data = ctx->data;
70         gint curdata;
71
72         gtk_tree_model_get(GTK_TREE_MODEL(model), iter, COMBOBOX_DATA, &curdata, -1);
73         if (data == curdata) {
74                 gtk_combo_box_set_active_iter(combobox, iter);
75                 return TRUE;
76         }
77
78         return FALSE;
79 }
80
81 void combobox_select_by_data(GtkComboBox *combobox, gint data)
82 {
83         GtkTreeModel *model;
84         ComboboxSelCtx *ctx = NULL;
85         cm_return_if_fail(combobox != NULL);
86
87         model = gtk_combo_box_get_model(combobox);
88
89         ctx = g_new(ComboboxSelCtx,
90                         sizeof(ComboboxSelCtx));
91         ctx->combobox = combobox;
92         ctx->data = data;
93
94         gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)_select_by_data_func, ctx);
95         g_free(ctx);
96 }
97
98 static gboolean _select_by_text_func(GtkTreeModel *model,       GtkTreePath *path,
99                 GtkTreeIter *iter, ComboboxSelCtx *ctx)
100 {
101         GtkComboBox *combobox = ctx->combobox;
102         const gchar *data = ctx->cdata;
103         const gchar *curdata;
104
105         gtk_tree_model_get (GTK_TREE_MODEL(model), iter, 0, &curdata, -1);
106         if (!g_utf8_collate(data, curdata)) {
107                 gtk_combo_box_set_active_iter(combobox, iter);
108                 return TRUE;
109         }
110
111         return FALSE;
112 }
113
114 void combobox_select_by_text(GtkComboBox *combobox, const gchar *data)
115 {
116         GtkTreeModel *model;
117         ComboboxSelCtx *ctx = NULL;
118         GtkComboBoxClass *class;
119
120         cm_return_if_fail(combobox != NULL);
121         class = GTK_COMBO_BOX_GET_CLASS (combobox);
122
123         /* we can do that only with gtk_combo_box_new_text() combo boxes */
124         cm_return_if_fail(class->get_active_text != NULL);
125
126         model = gtk_combo_box_get_model(combobox);
127
128         ctx = g_new(ComboboxSelCtx,
129                         sizeof(ComboboxSelCtx));
130         ctx->combobox = combobox;
131         ctx->cdata = data;
132
133         gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)_select_by_text_func, ctx);
134         g_free(ctx);
135 }
136
137 gint combobox_get_active_data(GtkComboBox *combobox)
138 {
139         GtkTreeModel *model;
140         GtkTreeIter iter;
141         gint data;
142
143         cm_return_val_if_fail(combobox != NULL, -1);
144
145         cm_return_val_if_fail(gtk_combo_box_get_active_iter(combobox, &iter), -1);
146
147         model = gtk_combo_box_get_model(combobox);
148
149         gtk_tree_model_get(model, &iter, COMBOBOX_DATA, &data, -1);
150
151         return data;
152 }
153
154 void combobox_unset_popdown_strings(GtkComboBox *combobox)
155 {
156         GtkTreeModel *model;
157         gint count, i;
158
159         cm_return_if_fail(combobox != NULL);
160
161         model = gtk_combo_box_get_model(combobox);
162         count = gtk_tree_model_iter_n_children(model, NULL);
163         for (i = 0; i < count; i++)
164                 gtk_combo_box_remove_text(combobox, 0);
165 }
166
167 void combobox_set_popdown_strings(GtkComboBox *combobox,
168                                  GList       *list)
169 {
170         GList *cur;
171
172         cm_return_if_fail(combobox != NULL);
173
174         for (cur = list; cur != NULL; cur = g_list_next(cur))
175                 gtk_combo_box_append_text(combobox, (const gchar*) cur->data);
176 }
177
178 gboolean combobox_set_value_from_arrow_key(GtkComboBox *combobox,
179                                  guint keyval)
180 /* used from key_press events upon gtk_combo_box_entry with one text column 
181    (gtk_combo_box_new_text() and with GtkComboBoxEntry's for instance),
182    make sure that up and down arrow keys behave the same as old with old
183    gtk_combo widgets:
184     when pressing Up:
185           if the current text in entry widget is not found in combo list,
186             get last value from combo list
187           if the current text in entry widget exists in combo list,
188             get prev value from combo list
189     when pressing Down:
190           if the current text in entry widget is not found in combo list,
191             get first value from combo list
192           if the current text in entry widget exists in combo list,
193             get next value from combo list
194 */
195 {
196         gboolean valid = FALSE;
197
198         cm_return_val_if_fail(combobox != NULL, FALSE);
199
200         /* reproduce the behaviour of old gtk_combo_box */
201         GtkTreeModel *model = gtk_combo_box_get_model(combobox);
202         GtkTreeIter iter;
203
204         if (gtk_combo_box_get_active_iter(combobox, &iter)) {
205                 /* if current text is in list, get prev or next one */
206
207                 if (keyval == GDK_KEY_Up) {
208                         gchar *text = gtk_combo_box_get_active_text(combobox);
209                         if (!text)
210                                 text = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(combobox))),0,-1);
211                         valid = gtkut_tree_model_text_iter_prev(model, &iter, text);
212                         g_free(text);
213                 } else
214                 if (keyval == GDK_KEY_Down)
215                         valid = gtk_tree_model_iter_next(model, &iter);
216
217                 if (valid)
218                         gtk_combo_box_set_active_iter(combobox, &iter);
219
220         } else {
221                 /* current text is not in list, get first or next one */
222
223                 if (keyval == GDK_KEY_Up)
224                         valid = gtkut_tree_model_get_iter_last(model, &iter);
225                 else
226                 if (keyval == GDK_KEY_Down)
227                         valid = gtk_tree_model_get_iter_first(model, &iter);
228
229                 if (valid)
230                         gtk_combo_box_set_active_iter(combobox, &iter);
231         }
232
233         /* return TRUE if value could be set */
234         return valid;
235 }
236
237 static void store_set_sensitive(GtkTreeModel *model, GtkTreeIter *iter,
238                                 const gboolean sensitive)
239 {
240         if(GTK_IS_LIST_STORE(model)) {
241                 gtk_list_store_set(GTK_LIST_STORE(model), iter,
242                                    COMBOBOX_SENS, sensitive,
243                                    -1);
244         } else {
245                 gtk_tree_store_set(GTK_TREE_STORE(model), iter,
246                                    COMBOBOX_SENS, sensitive,
247                                    -1);
248         }
249 }
250
251 void combobox_set_sensitive(GtkComboBox *combobox, const guint index,
252                             const gboolean sensitive)
253 {
254         GtkTreeModel *model;
255         GtkTreeIter iter, child;
256         guint i;
257         
258         if((model = gtk_combo_box_get_model(combobox)) == NULL)
259                 return;
260         
261         gtk_tree_model_get_iter_first(model, &iter);
262         for(i=0; i<index; i++) {
263                 if(gtk_tree_model_iter_next(model, &iter) == FALSE)
264                         return;
265         }
266         
267         store_set_sensitive(model, &iter, sensitive);
268
269         if(gtk_tree_model_iter_children(model, &child, &iter) == FALSE)
270                 return;
271         
272         do {
273                 store_set_sensitive(model, &child, sensitive);
274         } while (gtk_tree_model_iter_next(model, &child) == TRUE);
275 }