1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* This file is part of the GtkHTML library.
3 *
4 * Copyright (C) 2000 Jonas Borgstr�m <jonas_b@bitsmart.com>.
5 * Copyright (C) 2000, 2001, 2002 Ximian, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <config.h>
24
25 #include "htmlselect.h"
26 #include <string.h>
27
28 HTMLSelectClass html_select_class;
29 static HTMLEmbeddedClass *parent_class = NULL;
30
31 static void
clear_paths(HTMLSelect * select)32 clear_paths (HTMLSelect *select)
33 {
34 g_list_foreach (select->paths, (GFunc) gtk_tree_path_free, NULL);
35 g_list_free (select->paths);
36 select->paths = NULL;
37 }
38
39 static void
destroy(HTMLObject * o)40 destroy (HTMLObject *o)
41 {
42 clear_paths (HTML_SELECT (o));
43
44 HTML_OBJECT_CLASS (parent_class)->destroy (o);
45 }
46
47 static void
copy(HTMLObject * self,HTMLObject * dest)48 copy (HTMLObject *self,
49 HTMLObject *dest)
50 {
51 /* FIXME TODO */
52 HTMLSelect *s = HTML_SELECT (self);
53 HTMLSelect *d = HTML_SELECT (dest);
54
55 (* HTML_OBJECT_CLASS (parent_class)->copy) (self,dest);
56
57 /* FIXME g_warning ("HTMLSelect::copy() is not complete."); */
58 d->size = s->size;
59 d->multi = s->multi;
60
61 d->paths = NULL;
62
63 d->view = NULL;
64 }
65
66 static void
reset(HTMLEmbedded * e)67 reset (HTMLEmbedded *e)
68 {
69 HTMLSelect *s = HTML_SELECT (e);
70
71 if (s->multi || s->size > 1) {
72 GtkTreeView *tree_view;
73 GtkTreeSelection *selection;
74 GList *iter;
75
76 tree_view = GTK_TREE_VIEW (s->view);
77 selection = gtk_tree_view_get_selection (tree_view);
78 gtk_tree_selection_unselect_all (selection);
79 for (iter = s->paths; iter != NULL; iter = iter->next) {
80 GtkTreePath *path = iter->data;
81 gtk_tree_selection_select_path (selection, path);
82 }
83
84 } else if (s->paths != NULL) {
85 GtkTreePath *path = s->paths->data;
86 GtkComboBox *combo_box;
87 GtkTreeIter iter;
88
89 combo_box = GTK_COMBO_BOX (e->widget);
90 if (gtk_tree_model_get_iter (s->model, &iter, path))
91 gtk_combo_box_set_active_iter (combo_box, &iter);
92 }
93 }
94
95 struct EmbeddedSelectionInfo {
96 HTMLEmbedded *embedded;
97 GString *string;
98 };
99
100 static void
add_selected(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,struct EmbeddedSelectionInfo * info,const gchar * codepage)101 add_selected (GtkTreeModel *model,
102 GtkTreePath *path,
103 GtkTreeIter *iter,
104 struct EmbeddedSelectionInfo *info,
105 const gchar *codepage)
106 {
107 gchar *value, *encoded;
108
109 gtk_tree_model_get (model, iter, 0, &value, -1);
110
111 if (info->string->len)
112 g_string_append_c (info->string, '&');
113
114 encoded = html_embedded_encode_string (info->embedded->name, codepage);
115 g_string_append (info->string, encoded);
116 g_free (encoded);
117
118 g_string_append_c (info->string, '=');
119
120 encoded = html_embedded_encode_string (value, codepage);
121 g_string_append (info->string, encoded);
122 g_free (encoded);
123
124 g_free (value);
125 }
126
127 static gchar *
encode(HTMLEmbedded * e,const gchar * codepage)128 encode (HTMLEmbedded *e,
129 const gchar *codepage)
130 {
131 struct EmbeddedSelectionInfo info;
132 HTMLSelect *s = HTML_SELECT (e);
133 GtkTreeIter iter;
134
135 info.embedded = e;
136 info.string = g_string_sized_new (128);
137
138 if (e->name != NULL && *e->name != '\0') {
139 if (s->size > 1) {
140 gtk_tree_selection_selected_foreach (
141 gtk_tree_view_get_selection (
142 GTK_TREE_VIEW (s->view)),
143 (GtkTreeSelectionForeachFunc)
144 add_selected, &info);
145 } else {
146 GtkComboBox *combo_box;
147
148 combo_box = GTK_COMBO_BOX (e->widget);
149 if (gtk_combo_box_get_active_iter (combo_box, &iter))
150 add_selected (s->model, NULL, &iter, &info, codepage);
151 }
152 }
153
154 return g_string_free (info.string, FALSE);
155 }
156
157 void
html_select_type_init(void)158 html_select_type_init (void)
159 {
160 html_select_class_init (
161 &html_select_class, HTML_TYPE_SELECT, sizeof (HTMLSelect));
162 }
163
164 void
html_select_class_init(HTMLSelectClass * klass,HTMLType type,guint object_size)165 html_select_class_init (HTMLSelectClass *klass,
166 HTMLType type,
167 guint object_size)
168 {
169 HTMLEmbeddedClass *element_class;
170 HTMLObjectClass *object_class;
171
172 element_class = HTML_EMBEDDED_CLASS (klass);
173 object_class = HTML_OBJECT_CLASS (klass);
174
175 html_embedded_class_init (element_class, type, object_size);
176
177 /* HTMLEmbedded methods. */
178 element_class->reset = reset;
179 element_class->encode = encode;
180
181 /* HTMLObject methods. */
182 object_class->destroy = destroy;
183 object_class->copy = copy;
184
185 parent_class = &html_embedded_class;
186 }
187
188 void
html_select_init(HTMLSelect * select,HTMLSelectClass * klass,GtkWidget * parent,gchar * name,gint size,gboolean multi)189 html_select_init (HTMLSelect *select,
190 HTMLSelectClass *klass,
191 GtkWidget *parent,
192 gchar *name,
193 gint size,
194 gboolean multi)
195 {
196 HTMLEmbedded *element = HTML_EMBEDDED (select);
197 GtkCellRenderer *renderer;
198 GtkListStore *store;
199 GtkWidget *widget;
200
201 html_embedded_init (
202 element, HTML_EMBEDDED_CLASS (klass), parent, name, NULL);
203
204 store = gtk_list_store_new (1, G_TYPE_STRING);
205 renderer = gtk_cell_renderer_text_new ();
206 select->model = GTK_TREE_MODEL (store);
207
208 if (size > 1 || multi) {
209 GtkTreeViewColumn *column;
210 GtkRequisition req;
211 GtkTreeIter iter;
212
213 select->view = gtk_tree_view_new_with_model (select->model);
214 gtk_tree_view_set_headers_visible (
215 GTK_TREE_VIEW (select->view), FALSE);
216 gtk_tree_selection_set_mode (
217 gtk_tree_view_get_selection (
218 GTK_TREE_VIEW (select->view)),
219 multi ? GTK_SELECTION_MULTIPLE :
220 GTK_SELECTION_SINGLE);
221
222 column = gtk_tree_view_column_new ();
223 gtk_tree_view_column_pack_start (
224 column, renderer, FALSE);
225 gtk_tree_view_column_add_attribute (
226 column, renderer, "text", 0);
227 gtk_tree_view_append_column (
228 GTK_TREE_VIEW (select->view), column);
229
230 widget = gtk_scrolled_window_new (NULL, NULL);
231 gtk_scrolled_window_set_shadow_type (
232 GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
233 gtk_scrolled_window_set_policy (
234 GTK_SCROLLED_WINDOW (widget),
235 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
236 gtk_container_add (GTK_CONTAINER (widget), select->view);
237 gtk_widget_show_all (widget);
238
239 gtk_list_store_append (store, &iter);
240 gtk_list_store_set (store, &iter, 0, "height", -1);
241 gtk_widget_get_preferred_size (select->view, &req, NULL);
242 gtk_widget_set_size_request (
243 select->view, 120, req.height * size);
244 gtk_list_store_remove (store, &iter);
245 } else {
246 widget = gtk_combo_box_new_with_model_and_entry (select->model);
247 gtk_widget_set_size_request (widget, 120, -1);
248 }
249
250 html_embedded_set_widget (element, widget);
251
252 select->size = size;
253 select->multi = multi;
254 select->longest = 0;
255 select->paths = NULL;
256 }
257
258 HTMLObject *
html_select_new(GtkWidget * parent,gchar * name,gint size,gboolean multi)259 html_select_new (GtkWidget *parent,
260 gchar *name,
261 gint size,
262 gboolean multi)
263 {
264 HTMLSelect *ti;
265
266 ti = g_new0 (HTMLSelect, 1);
267 html_select_init (
268 ti, &html_select_class, parent, name, size, multi);
269
270 return HTML_OBJECT (ti);
271 }
272
273 void
html_select_add_option(HTMLSelect * select,const gchar * value,gboolean selected)274 html_select_add_option (HTMLSelect *select,
275 const gchar *value,
276 gboolean selected)
277 {
278 GtkListStore *store;
279 GtkTreeIter iter;
280
281 if (value == NULL)
282 value = "";
283
284 store = GTK_LIST_STORE (select->model);
285 gtk_list_store_append (store, &iter);
286 gtk_list_store_set (store, &iter, 0, value, -1);
287 select->longest = MAX (select->longest, strlen (value));
288
289 if (select->size > 1 || select->multi) {
290 if (selected) {
291 GtkTreeSelection *selection;
292 GtkTreeView *tree_view;
293
294 clear_paths (select);
295 tree_view = GTK_TREE_VIEW (select->view);
296 selection = gtk_tree_view_get_selection (tree_view);
297 gtk_tree_selection_select_iter (selection, &iter);
298 select->paths =
299 gtk_tree_selection_get_selected_rows (
300 selection, NULL);
301 }
302 } else {
303 GtkComboBox *combo_box;
304
305 combo_box = GTK_COMBO_BOX (HTML_EMBEDDED (select)->widget);
306 selected |= (gtk_combo_box_get_active (combo_box) < 0);
307
308 if (selected) {
309 GtkTreePath *path;
310
311 clear_paths (select);
312 gtk_combo_box_set_active_iter (combo_box, &iter);
313 path = gtk_tree_model_get_path (select->model, &iter);
314 select->paths = g_list_prepend (NULL, path);
315 }
316 }
317 }
318
319 void
html_select_set_text(HTMLSelect * select,const gchar * text)320 html_select_set_text (HTMLSelect *select,
321 const gchar *text)
322 {
323 GtkWidget *w = GTK_WIDGET (HTML_EMBEDDED (select)->widget);
324 GtkListStore *store;
325 GtkTreePath *path;
326 GtkTreeIter iter;
327 gint n_children;
328
329 if (text == NULL)
330 text = "";
331
332 store = GTK_LIST_STORE (select->model);
333 n_children = gtk_tree_model_iter_n_children (select->model, NULL);
334 if (n_children > 0) {
335 path = gtk_tree_path_new_from_indices (n_children - 1, -1);
336 gtk_tree_model_get_iter (select->model, &iter, path);
337 gtk_tree_path_free (path);
338 } else
339 gtk_list_store_append (store, &iter);
340 gtk_list_store_set (store, &iter, 0, text, -1);
341 select->longest = MAX (select->longest, strlen (text));
342
343 if (select->size > 1 || select->multi) {
344 GtkRequisition req;
345 GtkWidget *scrollbar;
346 gint width;
347
348 scrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (w));
349 gtk_widget_get_preferred_size (select->view, &req, NULL);
350 width = req.width;
351
352 if (n_children > select->size && scrollbar != NULL) {
353 gtk_widget_get_preferred_size (scrollbar, &req, NULL);
354 width += req.width + 8;
355 }
356
357 gtk_widget_set_size_request (w, width, -1);
358 HTML_OBJECT (select)->width = width;
359 } else {
360 w = HTML_EMBEDDED (select)->widget;
361 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (w), &iter);
362
363 gtk_entry_set_width_chars (
364 GTK_ENTRY (gtk_bin_get_child (GTK_BIN (w))),
365 select->longest);
366 gtk_widget_set_size_request (w, -1, -1);
367 }
368 }
369