2011-04-10 [colin] 3.7.9cvs9
[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_new_with_entry();
49         else
50                 combo = gtk_combo_box_text_new();
51         gtk_widget_show(combo);
52
53         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), text);
54         va_start(args, text);
55         while ((string = va_arg(args, gchar*)) != NULL)
56                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(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_text_remove(GTK_COMBO_BOX_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_text_append_text(GTK_COMBO_BOX_TEXT(combobox),
175                                                 (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_Up) {
208                         gchar *text = gtk_combo_box_text_get_active_text(
209                                         GTK_COMBO_BOX_TEXT(combobox));
210                         if (!text)
211                                 text = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(combobox))),0,-1);
212                         valid = gtkut_tree_model_text_iter_prev(model, &iter, text);
213                         g_free(text);
214                 } else
215                 if (keyval == GDK_Down)
216                         valid = gtk_tree_model_iter_next(model, &iter);
217
218                 if (valid)
219                         gtk_combo_box_set_active_iter(combobox, &iter);
220
221         } else {
222                 /* current text is not in list, get first or next one */
223
224                 if (keyval == GDK_Up)
225                         valid = gtkut_tree_model_get_iter_last(model, &iter);
226                 else
227                 if (keyval == GDK_Down)
228                         valid = gtk_tree_model_get_iter_first(model, &iter);
229
230                 if (valid)
231                         gtk_combo_box_set_active_iter(combobox, &iter);
232         }
233
234         /* return TRUE if value could be set */
235         return valid;
236 }
237
238 static void store_set_sensitive(GtkTreeModel *model, GtkTreeIter *iter,
239                                 const gboolean sensitive)
240 {
241         if(GTK_IS_LIST_STORE(model)) {
242                 gtk_list_store_set(GTK_LIST_STORE(model), iter,
243                                    COMBOBOX_SENS, sensitive,
244                                    -1);
245         } else {
246                 gtk_tree_store_set(GTK_TREE_STORE(model), iter,
247                                    COMBOBOX_SENS, sensitive,
248                                    -1);
249         }
250 }
251
252 void combobox_set_sensitive(GtkComboBox *combobox, const guint index,
253                             const gboolean sensitive)
254 {
255         GtkTreeModel *model;
256         GtkTreeIter iter, child;
257         guint i;
258         
259         if((model = gtk_combo_box_get_model(combobox)) == NULL)
260                 return;
261         
262         gtk_tree_model_get_iter_first(model, &iter);
263         for(i=0; i<index; i++) {
264                 if(gtk_tree_model_iter_next(model, &iter) == FALSE)
265                         return;
266         }
267         
268         store_set_sensitive(model, &iter, sensitive);
269
270         if(gtk_tree_model_iter_children(model, &child, &iter) == FALSE)
271                 return;
272         
273         do {
274                 store_set_sensitive(model, &child, sensitive);
275         } while (gtk_tree_model_iter_next(model, &child) == TRUE);
276 }