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