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