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