comparison gtk/gtkrequest.c @ 14191:009db0b357b5

This is a hand-crafted commit to migrate across subversion revisions 16854:16861, due to some vagaries of the way the original renames were done. Witness that monotone can do in one revision what svn had to spread across several.
author Ethan Blanton <elb@pidgin.im>
date Sat, 16 Dec 2006 04:59:55 +0000
parents
children 50f5099daab1
comparison
equal deleted inserted replaced
14190:366be2ce35a7 14191:009db0b357b5
1 /**
2 * @file gtkrequest.c GTK+ Request API
3 * @ingroup gtkui
4 *
5 * gaim
6 *
7 * Gaim is the legal property of its developers, whose names are too numerous
8 * to list here. Please refer to the COPYRIGHT file distributed with this
9 * source distribution.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25 #include "internal.h"
26 #include "gtkgaim.h"
27
28 #include "prefs.h"
29 #include "util.h"
30
31 #include "gtkimhtml.h"
32 #include "gtkimhtmltoolbar.h"
33 #include "gtkrequest.h"
34 #include "gtkutils.h"
35 #include "gaimstock.h"
36
37 #include <gdk/gdkkeysyms.h>
38
39 static GtkWidget * create_account_field(GaimRequestField *field);
40
41 typedef struct
42 {
43 GaimRequestType type;
44
45 void *user_data;
46 GtkWidget *dialog;
47
48 GtkWidget *ok_button;
49
50 size_t cb_count;
51 GCallback *cbs;
52
53 union
54 {
55 struct
56 {
57 GtkWidget *entry;
58
59 gboolean multiline;
60 gchar *hint;
61
62 } input;
63
64 struct
65 {
66 GaimRequestFields *fields;
67
68 } multifield;
69
70 struct
71 {
72 gboolean savedialog;
73 gchar *name;
74
75 } file;
76
77 } u;
78
79 } GaimGtkRequestData;
80
81 static void
82 generic_response_start(GaimGtkRequestData *data)
83 {
84 g_return_if_fail(data != NULL);
85
86 /* Tell the user we're doing something. */
87 gaim_gtk_set_cursor(GTK_WIDGET(data->dialog), GDK_WATCH);
88 }
89
90 static void
91 input_response_cb(GtkDialog *dialog, gint id, GaimGtkRequestData *data)
92 {
93 const char *value;
94 char *multiline_value = NULL;
95
96 generic_response_start(data);
97
98 if (data->u.input.multiline) {
99 GtkTextIter start_iter, end_iter;
100 GtkTextBuffer *buffer =
101 gtk_text_view_get_buffer(GTK_TEXT_VIEW(data->u.input.entry));
102
103 gtk_text_buffer_get_start_iter(buffer, &start_iter);
104 gtk_text_buffer_get_end_iter(buffer, &end_iter);
105
106 if ((data->u.input.hint != NULL) && (!strcmp(data->u.input.hint, "html")))
107 multiline_value = gtk_imhtml_get_markup(GTK_IMHTML(data->u.input.entry));
108 else
109 multiline_value = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter,
110 FALSE);
111
112 value = multiline_value;
113 }
114 else
115 value = gtk_entry_get_text(GTK_ENTRY(data->u.input.entry));
116
117 if (id < data->cb_count && data->cbs[id] != NULL)
118 ((GaimRequestInputCb)data->cbs[id])(data->user_data, value);
119 else if (data->cbs[1] != NULL)
120 ((GaimRequestInputCb)data->cbs[1])(data->user_data, value);
121
122 if (data->u.input.multiline)
123 g_free(multiline_value);
124
125 gaim_request_close(GAIM_REQUEST_INPUT, data);
126 }
127
128 static void
129 action_response_cb(GtkDialog *dialog, gint id, GaimGtkRequestData *data)
130 {
131 generic_response_start(data);
132
133 if (id < data->cb_count && data->cbs[id] != NULL)
134 ((GaimRequestActionCb)data->cbs[id])(data->user_data, id);
135
136 gaim_request_close(GAIM_REQUEST_INPUT, data);
137 }
138
139
140 static void
141 choice_response_cb(GtkDialog *dialog, gint id, GaimGtkRequestData *data)
142 {
143 GtkWidget *radio = g_object_get_data(G_OBJECT(dialog), "radio");
144 GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
145
146 generic_response_start(data);
147
148 if (id < data->cb_count && data->cbs[id] != NULL)
149 while (group) {
150 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group->data))) {
151 ((GaimRequestChoiceCb)data->cbs[id])(data->user_data, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(group->data), "choice_id")));
152 break;
153 }
154 group = group->next;
155 }
156 gaim_request_close(GAIM_REQUEST_INPUT, data);
157 }
158
159 static gboolean
160 field_string_focus_out_cb(GtkWidget *entry, GdkEventFocus *event,
161 GaimRequestField *field)
162 {
163 const char *value;
164
165 if (gaim_request_field_string_is_multiline(field))
166 {
167 GtkTextBuffer *buffer;
168 GtkTextIter start_iter, end_iter;
169
170 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry));
171
172 gtk_text_buffer_get_start_iter(buffer, &start_iter);
173 gtk_text_buffer_get_end_iter(buffer, &end_iter);
174
175 value = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, FALSE);
176 }
177 else
178 value = gtk_entry_get_text(GTK_ENTRY(entry));
179
180 gaim_request_field_string_set_value(field,
181 (*value == '\0' ? NULL : value));
182
183 return FALSE;
184 }
185
186 static gboolean
187 field_int_focus_out_cb(GtkEntry *entry, GdkEventFocus *event,
188 GaimRequestField *field)
189 {
190 gaim_request_field_int_set_value(field,
191 atoi(gtk_entry_get_text(entry)));
192
193 return FALSE;
194 }
195
196 static void
197 field_bool_cb(GtkToggleButton *button, GaimRequestField *field)
198 {
199 gaim_request_field_bool_set_value(field,
200 gtk_toggle_button_get_active(button));
201 }
202
203 static void
204 field_choice_menu_cb(GtkOptionMenu *menu, GaimRequestField *field)
205 {
206 gaim_request_field_choice_set_value(field,
207 gtk_option_menu_get_history(menu));
208 }
209
210 static void
211 field_choice_option_cb(GtkRadioButton *button, GaimRequestField *field)
212 {
213 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
214 gaim_request_field_choice_set_value(field,
215 (g_slist_length(gtk_radio_button_get_group(button)) -
216 g_slist_index(gtk_radio_button_get_group(button), button)) - 1);
217 }
218
219 static void
220 field_account_cb(GObject *w, GaimAccount *account, GaimRequestField *field)
221 {
222 gaim_request_field_account_set_value(field, account);
223 }
224
225 static void
226 multifield_ok_cb(GtkWidget *button, GaimGtkRequestData *data)
227 {
228 generic_response_start(data);
229
230 if (!GTK_WIDGET_HAS_FOCUS(button))
231 gtk_widget_grab_focus(button);
232
233 if (data->cbs[0] != NULL)
234 ((GaimRequestFieldsCb)data->cbs[0])(data->user_data,
235 data->u.multifield.fields);
236
237 gaim_request_close(GAIM_REQUEST_FIELDS, data);
238 }
239
240 static void
241 multifield_cancel_cb(GtkWidget *button, GaimGtkRequestData *data)
242 {
243 generic_response_start(data);
244
245 if (data->cbs[1] != NULL)
246 ((GaimRequestFieldsCb)data->cbs[1])(data->user_data,
247 data->u.multifield.fields);
248
249 gaim_request_close(GAIM_REQUEST_FIELDS, data);
250 }
251
252 static void
253 destroy_multifield_cb(GtkWidget *dialog, GdkEvent *event,
254 GaimGtkRequestData *data)
255 {
256 multifield_cancel_cb(NULL, data);
257 }
258
259
260 #define STOCK_ITEMIZE(r, l) \
261 if (!strcmp((r), text)) \
262 return (l);
263
264 static const char *
265 text_to_stock(const char *text)
266 {
267 STOCK_ITEMIZE(_("Yes"), GTK_STOCK_YES);
268 STOCK_ITEMIZE(_("No"), GTK_STOCK_NO);
269 STOCK_ITEMIZE(_("OK"), GTK_STOCK_OK);
270 STOCK_ITEMIZE(_("Cancel"), GTK_STOCK_CANCEL);
271 STOCK_ITEMIZE(_("Apply"), GTK_STOCK_APPLY);
272 STOCK_ITEMIZE(_("Close"), GTK_STOCK_CLOSE);
273 STOCK_ITEMIZE(_("Delete"), GTK_STOCK_DELETE);
274 STOCK_ITEMIZE(_("Add"), GTK_STOCK_ADD);
275 STOCK_ITEMIZE(_("Remove"), GTK_STOCK_REMOVE);
276 STOCK_ITEMIZE(_("Save"), GTK_STOCK_SAVE);
277 STOCK_ITEMIZE(_("Alias"), GAIM_STOCK_ALIAS);
278
279 return text;
280 }
281
282 static void *
283 gaim_gtk_request_input(const char *title, const char *primary,
284 const char *secondary, const char *default_value,
285 gboolean multiline, gboolean masked, gchar *hint,
286 const char *ok_text, GCallback ok_cb,
287 const char *cancel_text, GCallback cancel_cb,
288 void *user_data)
289 {
290 GaimGtkRequestData *data;
291 GtkWidget *dialog;
292 GtkWidget *vbox;
293 GtkWidget *hbox;
294 GtkWidget *label;
295 GtkWidget *entry;
296 GtkWidget *img;
297 GtkWidget *toolbar;
298 char *label_text;
299 char *primary_esc, *secondary_esc;
300
301 data = g_new0(GaimGtkRequestData, 1);
302 data->type = GAIM_REQUEST_INPUT;
303 data->user_data = user_data;
304
305 data->cb_count = 2;
306 data->cbs = g_new0(GCallback, 2);
307
308 data->cbs[0] = ok_cb;
309 data->cbs[1] = cancel_cb;
310
311 /* Create the dialog. */
312 dialog = gtk_dialog_new_with_buttons(title ? title : GAIM_ALERT_TITLE,
313 NULL, 0,
314 text_to_stock(cancel_text), 1,
315 text_to_stock(ok_text), 0,
316 NULL);
317 data->dialog = dialog;
318
319 g_signal_connect(G_OBJECT(dialog), "response",
320 G_CALLBACK(input_response_cb), data);
321
322 /* Setup the dialog */
323 gtk_container_set_border_width(GTK_CONTAINER(dialog), GAIM_HIG_BORDER/2);
324 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER/2);
325 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
326 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
327 gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0);
328 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER);
329
330 /* Setup the main horizontal box */
331 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER);
332 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
333
334 /* Dialog icon. */
335 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
336 GTK_ICON_SIZE_DIALOG);
337 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
338 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
339
340 /* Vertical box */
341 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
342
343 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
344
345 /* Descriptive label */
346 primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL;
347 secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL;
348 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">"
349 "%s</span>%s%s" : "%s%s%s"),
350 (primary ? primary_esc : ""),
351 ((primary && secondary) ? "\n\n" : ""),
352 (secondary ? secondary_esc : ""));
353 g_free(primary_esc);
354 g_free(secondary_esc);
355
356 label = gtk_label_new(NULL);
357
358 gtk_label_set_markup(GTK_LABEL(label), label_text);
359 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
360 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
361 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
362
363 g_free(label_text);
364
365 /* Entry field. */
366 data->u.input.multiline = multiline;
367 data->u.input.hint = g_strdup(hint);
368
369 if ((data->u.input.hint != NULL) && (!strcmp(data->u.input.hint, "html"))) {
370 GtkWidget *frame;
371
372 /* imhtml */
373 frame = gaim_gtk_create_imhtml(TRUE, &entry, &toolbar, NULL);
374 gtk_widget_set_size_request(entry, 320, 130);
375 gtk_widget_set_name(entry, "gaim_gtkrequest_imhtml");
376 if (default_value != NULL)
377 gtk_imhtml_append_text(GTK_IMHTML(entry), default_value, GTK_IMHTML_NO_SCROLL);
378 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
379 gtk_widget_show(frame);
380 }
381 else {
382 if (multiline) {
383 GtkWidget *sw;
384
385 sw = gtk_scrolled_window_new(NULL, NULL);
386 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
387 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
388 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
389 GTK_SHADOW_IN);
390
391 gtk_widget_set_size_request(sw, 320, 130);
392
393 /* GtkTextView */
394 entry = gtk_text_view_new();
395 gtk_text_view_set_editable(GTK_TEXT_VIEW(entry), TRUE);
396
397 if (default_value != NULL) {
398 GtkTextBuffer *buffer;
399
400 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry));
401 gtk_text_buffer_set_text(buffer, default_value, -1);
402 }
403
404 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(entry), GTK_WRAP_WORD_CHAR);
405
406 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
407
408 if (gaim_prefs_get_bool("/gaim/gtk/conversations/spellcheck"))
409 gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(entry));
410
411 gtk_container_add(GTK_CONTAINER(sw), entry);
412 }
413 else {
414 entry = gtk_entry_new();
415
416 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
417
418 gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0);
419
420 if (default_value != NULL)
421 gtk_entry_set_text(GTK_ENTRY(entry), default_value);
422
423 if (masked)
424 {
425 gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
426 gtk_entry_set_invisible_char(GTK_ENTRY(entry), GAIM_INVISIBLE_CHAR);
427 }
428 }
429 }
430
431 gaim_set_accessible_label (entry, label);
432 data->u.input.entry = entry;
433
434 /* Show everything. */
435 gtk_widget_show_all(dialog);
436
437 return data;
438 }
439
440 static void *
441 gaim_gtk_request_choice(const char *title, const char *primary,
442 const char *secondary, unsigned int default_value,
443 const char *ok_text, GCallback ok_cb,
444 const char *cancel_text, GCallback cancel_cb,
445 void *user_data, va_list args)
446 {
447 GaimGtkRequestData *data;
448 GtkWidget *dialog;
449 GtkWidget *vbox, *vbox2;
450 GtkWidget *hbox;
451 GtkWidget *label;
452 GtkWidget *img;
453 GtkWidget *radio = NULL;
454 char *label_text;
455 char *radio_text;
456 char *primary_esc, *secondary_esc;
457
458 data = g_new0(GaimGtkRequestData, 1);
459 data->type = GAIM_REQUEST_ACTION;
460 data->user_data = user_data;
461
462 data->cb_count = 2;
463 data->cbs = g_new0(GCallback, 2);
464 data->cbs[0] = cancel_cb;
465 data->cbs[1] = ok_cb;
466
467 /* Create the dialog. */
468 data->dialog = dialog = gtk_dialog_new();
469
470 if (title != NULL)
471 gtk_window_set_title(GTK_WINDOW(dialog), title);
472
473
474 gtk_dialog_add_button(GTK_DIALOG(dialog),
475 text_to_stock(cancel_text), 0);
476
477 gtk_dialog_add_button(GTK_DIALOG(dialog),
478 text_to_stock(ok_text), 1);
479
480 g_signal_connect(G_OBJECT(dialog), "response",
481 G_CALLBACK(choice_response_cb), data);
482
483 /* Setup the dialog */
484 gtk_container_set_border_width(GTK_CONTAINER(dialog), GAIM_HIG_BORDER/2);
485 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER/2);
486 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
487 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
488 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER);
489
490 /* Setup the main horizontal box */
491 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER);
492 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
493
494 /* Dialog icon. */
495 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
496 GTK_ICON_SIZE_DIALOG);
497 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
498 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
499
500 /* Vertical box */
501 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
502 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
503
504 /* Descriptive label */
505 primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL;
506 secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL;
507 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">"
508 "%s</span>%s%s" : "%s%s%s"),
509 (primary ? primary_esc : ""),
510 ((primary && secondary) ? "\n\n" : ""),
511 (secondary ? secondary_esc : ""));
512 g_free(primary_esc);
513 g_free(secondary_esc);
514
515 label = gtk_label_new(NULL);
516
517 gtk_label_set_markup(GTK_LABEL(label), label_text);
518 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
519 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
520 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
521
522 g_free(label_text);
523
524 vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
525 gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0);
526 while ((radio_text = va_arg(args, char*))) {
527 int resp = va_arg(args, int);
528 radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), radio_text);
529 gtk_box_pack_start(GTK_BOX(vbox2), radio, FALSE, FALSE, 0);
530 g_object_set_data(G_OBJECT(radio), "choice_id", GINT_TO_POINTER(resp));
531 if (resp == default_value)
532 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
533 }
534
535 g_object_set_data(G_OBJECT(dialog), "radio", radio);
536
537 /* Show everything. */
538 gtk_widget_show_all(dialog);
539
540 return data;
541 }
542
543 static void *
544 gaim_gtk_request_action(const char *title, const char *primary,
545 const char *secondary, unsigned int default_action,
546 void *user_data, size_t action_count, va_list actions)
547 {
548 GaimGtkRequestData *data;
549 GtkWidget *dialog;
550 GtkWidget *vbox;
551 GtkWidget *hbox;
552 GtkWidget *label;
553 GtkWidget *img;
554 void **buttons;
555 char *label_text;
556 char *primary_esc, *secondary_esc;
557 int i;
558
559 data = g_new0(GaimGtkRequestData, 1);
560 data->type = GAIM_REQUEST_ACTION;
561 data->user_data = user_data;
562
563 data->cb_count = action_count;
564 data->cbs = g_new0(GCallback, action_count);
565
566 /* Reverse the buttons */
567 buttons = g_new0(void *, action_count * 2);
568
569 for (i = 0; i < action_count * 2; i += 2) {
570 buttons[(action_count * 2) - i - 2] = va_arg(actions, char *);
571 buttons[(action_count * 2) - i - 1] = va_arg(actions, GCallback);
572 }
573
574 /* Create the dialog. */
575 data->dialog = dialog = gtk_dialog_new();
576
577 if (title != NULL)
578 gtk_window_set_title(GTK_WINDOW(dialog), title);
579
580 for (i = 0; i < action_count; i++) {
581 gtk_dialog_add_button(GTK_DIALOG(dialog),
582 text_to_stock(buttons[2 * i]), i);
583
584 data->cbs[i] = buttons[2 * i + 1];
585 }
586
587 g_free(buttons);
588
589 g_signal_connect(G_OBJECT(dialog), "response",
590 G_CALLBACK(action_response_cb), data);
591
592 /* Setup the dialog */
593 gtk_container_set_border_width(GTK_CONTAINER(dialog), GAIM_HIG_BORDER/2);
594 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER/2);
595 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
596 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
597 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER);
598
599 /* Setup the main horizontal box */
600 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER);
601 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
602
603 /* Dialog icon. */
604 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
605 GTK_ICON_SIZE_DIALOG);
606 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
607 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
608
609 /* Vertical box */
610 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
611 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
612
613 /* Descriptive label */
614 primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL;
615 secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL;
616 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">"
617 "%s</span>%s%s" : "%s%s%s"),
618 (primary ? primary_esc : ""),
619 ((primary && secondary) ? "\n\n" : ""),
620 (secondary ? secondary_esc : ""));
621 g_free(primary_esc);
622 g_free(secondary_esc);
623
624 label = gtk_label_new(NULL);
625
626 gtk_label_set_markup(GTK_LABEL(label), label_text);
627 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
628 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
629 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
630
631 g_free(label_text);
632
633
634 if (default_action == GAIM_DEFAULT_ACTION_NONE) {
635 GTK_WIDGET_SET_FLAGS(img, GTK_CAN_DEFAULT);
636 GTK_WIDGET_SET_FLAGS(img, GTK_CAN_FOCUS);
637 gtk_widget_grab_focus(img);
638 gtk_widget_grab_default(img);
639 } else
640 gtk_dialog_set_default_response(GTK_DIALOG(dialog), default_action);
641
642 /* Show everything. */
643 gtk_widget_show_all(dialog);
644
645 return data;
646 }
647
648 static void
649 req_entry_field_changed_cb(GtkWidget *entry, GaimRequestField *field)
650 {
651 GaimGtkRequestData *req_data;
652 const char *text = gtk_entry_get_text(GTK_ENTRY(entry));
653
654 gaim_request_field_string_set_value(field, (*text == '\0' ? NULL : text));
655
656 req_data = (GaimGtkRequestData *)field->group->fields_list->ui_data;
657
658 gtk_widget_set_sensitive(req_data->ok_button,
659 gaim_request_fields_all_required_filled(field->group->fields_list));
660 }
661
662 static void
663 setup_entry_field(GtkWidget *entry, GaimRequestField *field)
664 {
665 const char *type_hint;
666
667 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
668
669 if (gaim_request_field_is_required(field))
670 {
671 g_signal_connect(G_OBJECT(entry), "changed",
672 G_CALLBACK(req_entry_field_changed_cb), field);
673 }
674
675 if ((type_hint = gaim_request_field_get_type_hint(field)) != NULL)
676 {
677 if (gaim_str_has_prefix(type_hint, "screenname"))
678 {
679 GtkWidget *optmenu = NULL;
680 GList *fields = field->group->fields;
681 while (fields)
682 {
683 GaimRequestField *fld = fields->data;
684 fields = fields->next;
685
686 if (gaim_request_field_get_type(fld) == GAIM_REQUEST_FIELD_ACCOUNT)
687 {
688 const char *type_hint = gaim_request_field_get_type_hint(fld);
689 if (type_hint != NULL && strcmp(type_hint, "account") == 0)
690 {
691 if (fld->ui_data == NULL)
692 fld->ui_data = create_account_field(fld);
693 optmenu = GTK_WIDGET(fld->ui_data);
694 break;
695 }
696 }
697 }
698 gaim_gtk_setup_screenname_autocomplete(entry, optmenu, !strcmp(type_hint, "screenname-all"));
699 }
700 }
701 }
702
703 static GtkWidget *
704 create_string_field(GaimRequestField *field)
705 {
706 const char *value;
707 GtkWidget *widget;
708
709 value = gaim_request_field_string_get_default_value(field);
710
711 if (gaim_request_field_string_is_multiline(field))
712 {
713 GtkWidget *textview;
714
715 widget = gtk_scrolled_window_new(NULL, NULL);
716 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget),
717 GTK_SHADOW_IN);
718 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
719 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
720
721 textview = gtk_text_view_new();
722 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview),
723 TRUE);
724 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview),
725 GTK_WRAP_WORD_CHAR);
726
727 if (gaim_prefs_get_bool("/gaim/gtk/conversations/spellcheck"))
728 gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(textview));
729
730 gtk_container_add(GTK_CONTAINER(widget), textview);
731 gtk_widget_show(textview);
732
733 gtk_widget_set_size_request(widget, -1, 75);
734
735 if (value != NULL)
736 {
737 GtkTextBuffer *buffer;
738
739 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
740
741 gtk_text_buffer_set_text(buffer, value, -1);
742 }
743
744 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview),
745 gaim_request_field_string_is_editable(field));
746
747 g_signal_connect(G_OBJECT(textview), "focus-out-event",
748 G_CALLBACK(field_string_focus_out_cb), field);
749 }
750 else
751 {
752 widget = gtk_entry_new();
753
754 setup_entry_field(widget, field);
755
756 if (value != NULL)
757 gtk_entry_set_text(GTK_ENTRY(widget), value);
758
759 if (gaim_request_field_string_is_masked(field))
760 {
761 gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
762 gtk_entry_set_invisible_char(GTK_ENTRY(widget), GAIM_INVISIBLE_CHAR);
763 }
764
765 gtk_editable_set_editable(GTK_EDITABLE(widget),
766 gaim_request_field_string_is_editable(field));
767
768 g_signal_connect(G_OBJECT(widget), "focus-out-event",
769 G_CALLBACK(field_string_focus_out_cb), field);
770 }
771
772 return widget;
773 }
774
775 static GtkWidget *
776 create_int_field(GaimRequestField *field)
777 {
778 int value;
779 GtkWidget *widget;
780
781 widget = gtk_entry_new();
782
783 setup_entry_field(widget, field);
784
785 value = gaim_request_field_int_get_default_value(field);
786
787 if (value != 0)
788 {
789 char buf[32];
790
791 g_snprintf(buf, sizeof(buf), "%d", value);
792
793 gtk_entry_set_text(GTK_ENTRY(widget), buf);
794 }
795
796 g_signal_connect(G_OBJECT(widget), "focus-out-event",
797 G_CALLBACK(field_int_focus_out_cb), field);
798
799 return widget;
800 }
801
802 static GtkWidget *
803 create_bool_field(GaimRequestField *field)
804 {
805 GtkWidget *widget;
806
807 widget = gtk_check_button_new_with_label(
808 gaim_request_field_get_label(field));
809
810 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
811 gaim_request_field_bool_get_default_value(field));
812
813 g_signal_connect(G_OBJECT(widget), "toggled",
814 G_CALLBACK(field_bool_cb), field);
815
816 return widget;
817 }
818
819 static GtkWidget *
820 create_choice_field(GaimRequestField *field)
821 {
822 GtkWidget *widget;
823 GList *labels;
824 GList *l;
825
826 labels = gaim_request_field_choice_get_labels(field);
827
828 if (g_list_length(labels) > 5)
829 {
830 GtkWidget *menu;
831 GtkWidget *item;
832
833 widget = gtk_option_menu_new();
834
835 menu = gtk_menu_new();
836
837 for (l = labels; l != NULL; l = l->next)
838 {
839 const char *text = l->data;
840
841 item = gtk_menu_item_new_with_label(text);
842 gtk_widget_show(item);
843
844 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
845 }
846
847 gtk_widget_show(menu);
848 gtk_option_menu_set_menu(GTK_OPTION_MENU(widget), menu);
849 gtk_option_menu_set_history(GTK_OPTION_MENU(widget),
850 gaim_request_field_choice_get_default_value(field));
851
852 g_signal_connect(G_OBJECT(widget), "changed",
853 G_CALLBACK(field_choice_menu_cb), field);
854 }
855 else
856 {
857 GtkWidget *box;
858 GtkWidget *first_radio = NULL;
859 GtkWidget *radio;
860 gint i;
861
862 if (g_list_length(labels) == 2)
863 box = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
864 else
865 box = gtk_vbox_new(FALSE, 0);
866
867 widget = box;
868
869 for (l = labels, i = 0; l != NULL; l = l->next, i++)
870 {
871 const char *text = l->data;
872
873 radio = gtk_radio_button_new_with_label_from_widget(
874 GTK_RADIO_BUTTON(first_radio), text);
875
876 if (first_radio == NULL)
877 first_radio = radio;
878
879 if (i == gaim_request_field_choice_get_default_value(field))
880 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
881
882 gtk_box_pack_start(GTK_BOX(box), radio, TRUE, TRUE, 0);
883 gtk_widget_show(radio);
884
885 g_signal_connect(G_OBJECT(radio), "toggled",
886 G_CALLBACK(field_choice_option_cb), field);
887 }
888 }
889
890 return widget;
891 }
892
893 static GtkWidget *
894 create_image_field(GaimRequestField *field)
895 {
896 GtkWidget *widget;
897 GdkPixbuf *buf, *scale;
898 GdkPixbufLoader *loader;
899
900 loader = gdk_pixbuf_loader_new();
901 gdk_pixbuf_loader_write(loader,
902 (const guchar *)gaim_request_field_image_get_buffer(field),
903 gaim_request_field_image_get_size(field),
904 NULL);
905 gdk_pixbuf_loader_close(loader, NULL);
906 buf = gdk_pixbuf_loader_get_pixbuf(loader);
907
908 scale = gdk_pixbuf_scale_simple(buf,
909 gaim_request_field_image_get_scale_x(field) * gdk_pixbuf_get_width(buf),
910 gaim_request_field_image_get_scale_y(field) * gdk_pixbuf_get_height(buf),
911 GDK_INTERP_BILINEAR);
912 widget = gtk_image_new_from_pixbuf(scale);
913 g_object_unref(G_OBJECT(buf));
914 g_object_unref(G_OBJECT(scale));
915
916 return widget;
917 }
918
919 static GtkWidget *
920 create_account_field(GaimRequestField *field)
921 {
922 GtkWidget *widget;
923
924 widget = gaim_gtk_account_option_menu_new(
925 gaim_request_field_account_get_default_value(field),
926 gaim_request_field_account_get_show_all(field),
927 G_CALLBACK(field_account_cb),
928 gaim_request_field_account_get_filter(field),
929 field);
930
931 return widget;
932 }
933
934 static void
935 select_field_list_item(GtkTreeModel *model, GtkTreePath *path,
936 GtkTreeIter *iter, gpointer data)
937 {
938 GaimRequestField *field = (GaimRequestField *)data;
939 char *text;
940
941 gtk_tree_model_get(model, iter, 1, &text, -1);
942
943 gaim_request_field_list_add_selected(field, text);
944 g_free(text);
945 }
946
947 static void
948 list_field_select_changed_cb(GtkTreeSelection *sel, GaimRequestField *field)
949 {
950 gaim_request_field_list_clear_selected(field);
951
952 gtk_tree_selection_selected_foreach(sel, select_field_list_item, field);
953 }
954
955 static GtkWidget *
956 create_list_field(GaimRequestField *field)
957 {
958 GtkWidget *sw;
959 GtkWidget *treeview;
960 GtkListStore *store;
961 GtkCellRenderer *renderer;
962 GtkTreeSelection *sel;
963 GtkTreeViewColumn *column;
964 GtkTreeIter iter;
965 const GList *l;
966
967 /* Create the scrolled window */
968 sw = gtk_scrolled_window_new(NULL, NULL);
969 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
970 GTK_POLICY_AUTOMATIC,
971 GTK_POLICY_AUTOMATIC);
972 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
973 GTK_SHADOW_IN);
974 gtk_widget_show(sw);
975
976 /* Create the list store */
977 store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING);
978
979 /* Create the tree view */
980 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
981 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
982 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
983
984 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
985
986 if (gaim_request_field_list_get_multi_select(field))
987 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
988
989 g_signal_connect(G_OBJECT(sel), "changed",
990 G_CALLBACK(list_field_select_changed_cb), field);
991
992 column = gtk_tree_view_column_new();
993 gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1);
994
995 renderer = gtk_cell_renderer_text_new();
996 gtk_tree_view_column_pack_start(column, renderer, TRUE);
997 gtk_tree_view_column_add_attribute(column, renderer, "text", 1);
998
999 for (l = gaim_request_field_list_get_items(field); l != NULL; l = l->next)
1000 {
1001 const char *text = (const char *)l->data;
1002
1003 gtk_list_store_append(store, &iter);
1004
1005 gtk_list_store_set(store, &iter,
1006 0, gaim_request_field_list_get_data(field, text),
1007 1, text,
1008 -1);
1009
1010 if (gaim_request_field_list_is_selected(field, text))
1011 gtk_tree_selection_select_iter(sel, &iter);
1012 }
1013
1014 gtk_container_add(GTK_CONTAINER(sw), treeview);
1015 gtk_widget_show(treeview);
1016
1017 return sw;
1018 }
1019
1020 static void *
1021 gaim_gtk_request_fields(const char *title, const char *primary,
1022 const char *secondary, GaimRequestFields *fields,
1023 const char *ok_text, GCallback ok_cb,
1024 const char *cancel_text, GCallback cancel_cb,
1025 void *user_data)
1026 {
1027 GaimGtkRequestData *data;
1028 GtkWidget *win;
1029 GtkWidget *vbox;
1030 GtkWidget *vbox2;
1031 GtkWidget *hbox;
1032 GtkWidget *bbox;
1033 GtkWidget *frame;
1034 GtkWidget *label;
1035 GtkWidget *table;
1036 GtkWidget *button;
1037 GtkWidget *img;
1038 GtkWidget *sw;
1039 GtkSizeGroup *sg;
1040 GList *gl, *fl;
1041 GaimRequestFieldGroup *group;
1042 GaimRequestField *field;
1043 char *label_text;
1044 char *primary_esc, *secondary_esc;
1045 int total_fields = 0;
1046
1047 data = g_new0(GaimGtkRequestData, 1);
1048 data->type = GAIM_REQUEST_FIELDS;
1049 data->user_data = user_data;
1050 data->u.multifield.fields = fields;
1051
1052 fields->ui_data = data;
1053
1054 data->cb_count = 2;
1055 data->cbs = g_new0(GCallback, 2);
1056
1057 data->cbs[0] = ok_cb;
1058 data->cbs[1] = cancel_cb;
1059
1060 data->dialog = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1061
1062 if (title != NULL)
1063 gtk_window_set_title(GTK_WINDOW(win), title);
1064
1065 gtk_window_set_role(GTK_WINDOW(win), "multifield");
1066 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER);
1067 gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
1068
1069 g_signal_connect(G_OBJECT(win), "delete_event",
1070 G_CALLBACK(destroy_multifield_cb), data);
1071
1072 /* Setup the main horizontal box */
1073 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER);
1074 gtk_container_add(GTK_CONTAINER(win), hbox);
1075 gtk_widget_show(hbox);
1076
1077 /* Dialog icon. */
1078 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
1079 GTK_ICON_SIZE_DIALOG);
1080 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
1081 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
1082 gtk_widget_show(img);
1083
1084 /* Setup the vbox */
1085 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
1086 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
1087 gtk_widget_show(vbox);
1088
1089 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1090
1091 if(primary) {
1092 primary_esc = g_markup_escape_text(primary, -1);
1093 label_text = g_strdup_printf(
1094 "<span weight=\"bold\" size=\"larger\">%s</span>", primary_esc);
1095 g_free(primary_esc);
1096 label = gtk_label_new(NULL);
1097
1098 gtk_label_set_markup(GTK_LABEL(label), label_text);
1099 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1100 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1101 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
1102 gtk_widget_show(label);
1103 g_free(label_text);
1104 }
1105
1106 for (gl = gaim_request_fields_get_groups(fields); gl != NULL;
1107 gl = gl->next)
1108 total_fields += g_list_length(gaim_request_field_group_get_fields(gl->data));
1109
1110 if(total_fields > 9) {
1111 sw = gtk_scrolled_window_new(NULL, NULL);
1112 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1113 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1114 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1115 GTK_SHADOW_NONE);
1116 gtk_widget_set_size_request(sw, -1, 200);
1117 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
1118 gtk_widget_show(sw);
1119
1120 vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
1121 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), vbox2);
1122 gtk_widget_show(vbox2);
1123 } else {
1124 vbox2 = vbox;
1125 }
1126
1127 if (secondary) {
1128 secondary_esc = g_markup_escape_text(secondary, -1);
1129 label = gtk_label_new(NULL);
1130
1131 gtk_label_set_markup(GTK_LABEL(label), secondary_esc);
1132 g_free(secondary_esc);
1133 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1134 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1135 gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0);
1136 gtk_widget_show(label);
1137 }
1138
1139 for (gl = gaim_request_fields_get_groups(fields);
1140 gl != NULL;
1141 gl = gl->next)
1142 {
1143 GList *field_list;
1144 size_t field_count = 0;
1145 size_t cols = 1;
1146 size_t rows;
1147 size_t col_num;
1148 size_t row_num = 0;
1149
1150 group = gl->data;
1151 field_list = gaim_request_field_group_get_fields(group);
1152
1153 if (gaim_request_field_group_get_title(group) != NULL)
1154 {
1155 frame = gaim_gtk_make_frame(vbox2,
1156 gaim_request_field_group_get_title(group));
1157 }
1158 else
1159 frame = vbox2;
1160
1161 field_count = g_list_length(field_list);
1162 /*
1163 if (field_count > 9)
1164 {
1165 rows = field_count / 2;
1166 cols++;
1167 }
1168 else
1169 */
1170 rows = field_count;
1171
1172 col_num = 0;
1173
1174 for (fl = field_list; fl != NULL; fl = fl->next)
1175 {
1176 GaimRequestFieldType type;
1177
1178 field = (GaimRequestField *)fl->data;
1179
1180 type = gaim_request_field_get_type(field);
1181
1182 if (type == GAIM_REQUEST_FIELD_LABEL)
1183 {
1184 if (col_num > 0)
1185 rows++;
1186
1187 rows++;
1188 }
1189 else if ((type == GAIM_REQUEST_FIELD_LIST) ||
1190 (type == GAIM_REQUEST_FIELD_STRING &&
1191 gaim_request_field_string_is_multiline(field)))
1192 {
1193 if (col_num > 0)
1194 rows++;
1195
1196 rows += 2;
1197 }
1198
1199 col_num++;
1200
1201 if (col_num >= cols)
1202 col_num = 0;
1203 }
1204
1205 table = gtk_table_new(rows, 2 * cols, FALSE);
1206 gtk_table_set_row_spacings(GTK_TABLE(table), GAIM_HIG_BOX_SPACE);
1207 gtk_table_set_col_spacings(GTK_TABLE(table), GAIM_HIG_BOX_SPACE);
1208
1209 gtk_container_add(GTK_CONTAINER(frame), table);
1210 gtk_widget_show(table);
1211
1212 for (row_num = 0, fl = field_list;
1213 row_num < rows && fl != NULL;
1214 row_num++)
1215 {
1216 for (col_num = 0;
1217 col_num < cols && fl != NULL;
1218 col_num++, fl = fl->next)
1219 {
1220 size_t col_offset = col_num * 2;
1221 GaimRequestFieldType type;
1222 GtkWidget *widget = NULL;
1223
1224 label = NULL;
1225 field = fl->data;
1226
1227 if (!gaim_request_field_is_visible(field)) {
1228 col_num--;
1229 continue;
1230 }
1231
1232 type = gaim_request_field_get_type(field);
1233
1234 if (type != GAIM_REQUEST_FIELD_BOOLEAN &&
1235 gaim_request_field_get_label(field))
1236 {
1237 char *text;
1238
1239 text = g_strdup_printf("%s:",
1240 gaim_request_field_get_label(field));
1241
1242 label = gtk_label_new(NULL);
1243 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), text);
1244 g_free(text);
1245
1246 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1247
1248 gtk_size_group_add_widget(sg, label);
1249
1250 if (type == GAIM_REQUEST_FIELD_LABEL ||
1251 type == GAIM_REQUEST_FIELD_LIST ||
1252 (type == GAIM_REQUEST_FIELD_STRING &&
1253 gaim_request_field_string_is_multiline(field)))
1254 {
1255 if(col_num > 0)
1256 row_num++;
1257
1258 gtk_table_attach_defaults(GTK_TABLE(table), label,
1259 0, 2 * cols,
1260 row_num, row_num + 1);
1261
1262 row_num++;
1263 col_num=cols;
1264 }
1265 else
1266 {
1267 gtk_table_attach_defaults(GTK_TABLE(table), label,
1268 col_offset, col_offset + 1,
1269 row_num, row_num + 1);
1270 }
1271
1272 gtk_widget_show(label);
1273 }
1274
1275 if (field->ui_data != NULL)
1276 widget = GTK_WIDGET(field->ui_data);
1277 else if (type == GAIM_REQUEST_FIELD_STRING)
1278 widget = create_string_field(field);
1279 else if (type == GAIM_REQUEST_FIELD_INTEGER)
1280 widget = create_int_field(field);
1281 else if (type == GAIM_REQUEST_FIELD_BOOLEAN)
1282 widget = create_bool_field(field);
1283 else if (type == GAIM_REQUEST_FIELD_CHOICE)
1284 widget = create_choice_field(field);
1285 else if (type == GAIM_REQUEST_FIELD_LIST)
1286 widget = create_list_field(field);
1287 else if (type == GAIM_REQUEST_FIELD_IMAGE)
1288 widget = create_image_field(field);
1289 else if (type == GAIM_REQUEST_FIELD_ACCOUNT)
1290 widget = create_account_field(field);
1291 else
1292 continue;
1293
1294 if (label)
1295 gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget);
1296
1297 if (type == GAIM_REQUEST_FIELD_STRING &&
1298 gaim_request_field_string_is_multiline(field))
1299 {
1300 gtk_table_attach(GTK_TABLE(table), widget,
1301 0, 2 * cols,
1302 row_num, row_num + 1,
1303 GTK_FILL | GTK_EXPAND,
1304 GTK_FILL | GTK_EXPAND,
1305 5, 0);
1306 }
1307 else if (type == GAIM_REQUEST_FIELD_LIST)
1308 {
1309 gtk_table_attach(GTK_TABLE(table), widget,
1310 0, 2 * cols,
1311 row_num, row_num + 1,
1312 GTK_FILL | GTK_EXPAND,
1313 GTK_FILL | GTK_EXPAND,
1314 5, 0);
1315 }
1316 else if (type == GAIM_REQUEST_FIELD_BOOLEAN)
1317 {
1318 gtk_table_attach(GTK_TABLE(table), widget,
1319 col_offset, col_offset + 1,
1320 row_num, row_num + 1,
1321 GTK_FILL | GTK_EXPAND,
1322 GTK_FILL | GTK_EXPAND,
1323 5, 0);
1324 }
1325 else
1326 {
1327 gtk_table_attach(GTK_TABLE(table), widget,
1328 1, 2 * cols,
1329 row_num, row_num + 1,
1330 GTK_FILL | GTK_EXPAND,
1331 GTK_FILL | GTK_EXPAND,
1332 5, 0);
1333 }
1334
1335 gtk_widget_show(widget);
1336
1337 field->ui_data = widget;
1338 }
1339 }
1340 }
1341
1342 g_object_unref(sg);
1343
1344 /* Button box. */
1345 bbox = gtk_hbutton_box_new();
1346 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE);
1347 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1348 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
1349 gtk_widget_show(bbox);
1350
1351 /* Cancel button */
1352 button = gtk_button_new_from_stock(text_to_stock(cancel_text));
1353 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1354 gtk_widget_show(button);
1355
1356 g_signal_connect(G_OBJECT(button), "clicked",
1357 G_CALLBACK(multifield_cancel_cb), data);
1358
1359 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1360
1361 /* OK button */
1362 button = gtk_button_new_from_stock(text_to_stock(ok_text));
1363 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1364 gtk_widget_show(button);
1365
1366 data->ok_button = button;
1367
1368 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1369 gtk_window_set_default(GTK_WINDOW(win), button);
1370
1371 g_signal_connect(G_OBJECT(button), "clicked",
1372 G_CALLBACK(multifield_ok_cb), data);
1373
1374 if (!gaim_request_fields_all_required_filled(fields))
1375 gtk_widget_set_sensitive(button, FALSE);
1376
1377 gtk_widget_show(win);
1378
1379 return data;
1380 }
1381
1382 static void
1383 file_yes_no_cb(GaimGtkRequestData *data, gint id)
1384 {
1385 /* Only call the callback if yes was selected, otherwise the request
1386 * (eg. file transfer) will be cancelled, then when a new filename is chosen
1387 * things go BOOM */
1388 if (id == 1) {
1389 if (data->cbs[1] != NULL)
1390 ((GaimRequestFileCb)data->cbs[1])(data->user_data, data->u.file.name);
1391 gaim_request_close(data->type, data);
1392 } else {
1393 gaim_gtk_clear_cursor(GTK_WIDGET(data->dialog));
1394 }
1395 }
1396
1397 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
1398 static void
1399 file_ok_check_if_exists_cb(GtkWidget *widget, gint response, GaimGtkRequestData *data)
1400 {
1401 gchar *current_folder;
1402
1403 generic_response_start(data);
1404
1405 if (response != GTK_RESPONSE_ACCEPT) {
1406 if (data->cbs[0] != NULL)
1407 ((GaimRequestFileCb)data->cbs[0])(data->user_data, NULL);
1408 gaim_request_close(data->type, data);
1409 return;
1410 }
1411
1412 data->u.file.name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data->dialog));
1413 current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(data->dialog));
1414 if (current_folder != NULL) {
1415 if (data->u.file.savedialog) {
1416 gaim_prefs_set_string("/gaim/gtk/filelocations/last_save_folder", current_folder);
1417 } else {
1418 gaim_prefs_set_string("/gaim/gtk/filelocations/last_open_folder", current_folder);
1419 }
1420 g_free(current_folder);
1421 }
1422
1423 #else /* FILECHOOSER */
1424
1425 static void
1426 file_ok_check_if_exists_cb(GtkWidget *button, GaimGtkRequestData *data)
1427 {
1428 const gchar *name;
1429 gchar *current_folder;
1430
1431 generic_response_start(data);
1432
1433 name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(data->dialog));
1434
1435 /* If name is a directory then change directories */
1436 if (data->type == GAIM_REQUEST_FILE) {
1437 if (gaim_gtk_check_if_dir(name, GTK_FILE_SELECTION(data->dialog)))
1438 return;
1439 }
1440
1441 current_folder = g_path_get_dirname(name);
1442
1443 g_free(data->u.file.name);
1444 if (data->type == GAIM_REQUEST_FILE)
1445 data->u.file.name = g_strdup(name);
1446 else
1447 {
1448 if (g_file_test(name, G_FILE_TEST_IS_DIR))
1449 data->u.file.name = g_strdup(name);
1450 else
1451 data->u.file.name = g_strdup(current_folder);
1452 }
1453
1454 if (current_folder != NULL) {
1455 if (data->u.file.savedialog) {
1456 gaim_prefs_set_string("/gaim/gtk/filelocations/last_save_folder", current_folder);
1457 } else {
1458 gaim_prefs_set_string("/gaim/gtk/filelocations/last_open_folder", current_folder);
1459 }
1460 g_free(current_folder);
1461 }
1462
1463 #endif /* FILECHOOSER */
1464
1465 if ((data->u.file.savedialog == TRUE) &&
1466 (g_file_test(data->u.file.name, G_FILE_TEST_EXISTS))) {
1467 gaim_request_action(data, NULL, _("That file already exists"),
1468 _("Would you like to overwrite it?"), 0, data, 2,
1469 _("Overwrite"), G_CALLBACK(file_yes_no_cb),
1470 _("Choose New Name"), G_CALLBACK(file_yes_no_cb));
1471 } else
1472 file_yes_no_cb(data, 1);
1473 }
1474
1475 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
1476 static void
1477 file_cancel_cb(GaimGtkRequestData *data)
1478 {
1479 generic_response_start(data);
1480
1481 if (data->cbs[0] != NULL)
1482 ((GaimRequestFileCb)data->cbs[0])(data->user_data, NULL);
1483
1484 gaim_request_close(data->type, data);
1485 }
1486 #endif /* FILECHOOSER */
1487
1488 static void *
1489 gaim_gtk_request_file(const char *title, const char *filename,
1490 gboolean savedialog,
1491 GCallback ok_cb, GCallback cancel_cb,
1492 void *user_data)
1493 {
1494 GaimGtkRequestData *data;
1495 GtkWidget *filesel;
1496 const gchar *current_folder;
1497 #if GTK_CHECK_VERSION(2,4,0)
1498 gboolean folder_set = FALSE;
1499 #endif
1500
1501 data = g_new0(GaimGtkRequestData, 1);
1502 data->type = GAIM_REQUEST_FILE;
1503 data->user_data = user_data;
1504 data->cb_count = 2;
1505 data->cbs = g_new0(GCallback, 2);
1506 data->cbs[0] = cancel_cb;
1507 data->cbs[1] = ok_cb;
1508 data->u.file.savedialog = savedialog;
1509
1510 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
1511 filesel = gtk_file_chooser_dialog_new(
1512 title ? title : (savedialog ? _("Save File...")
1513 : _("Open File...")),
1514 NULL,
1515 savedialog ? GTK_FILE_CHOOSER_ACTION_SAVE
1516 : GTK_FILE_CHOOSER_ACTION_OPEN,
1517 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1518 savedialog ? GTK_STOCK_SAVE
1519 : GTK_STOCK_OPEN,
1520 GTK_RESPONSE_ACCEPT,
1521 NULL);
1522 gtk_dialog_set_default_response(GTK_DIALOG(filesel), GTK_RESPONSE_ACCEPT);
1523
1524 if (savedialog) {
1525 current_folder = gaim_prefs_get_string("/gaim/gtk/filelocations/last_save_folder");
1526 } else {
1527 current_folder = gaim_prefs_get_string("/gaim/gtk/filelocations/last_open_folder");
1528 }
1529
1530 if (filename != NULL)
1531 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filesel), filename);
1532 if ((current_folder != NULL) && (*current_folder != '\0')) {
1533 folder_set = gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filesel), current_folder);
1534 }
1535
1536 #ifdef _WIN32
1537 if (!folder_set) {
1538 char *my_documents = wgaim_get_special_folder(CSIDL_PERSONAL);
1539
1540 if (my_documents != NULL) {
1541 gtk_file_chooser_set_current_folder(
1542 GTK_FILE_CHOOSER(filesel), my_documents);
1543
1544 g_free(my_documents);
1545 }
1546 }
1547
1548 #endif
1549 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(filesel)), "response",
1550 G_CALLBACK(file_ok_check_if_exists_cb), data);
1551 #else /* FILECHOOSER */
1552 filesel = gtk_file_selection_new(
1553 title ? title : (savedialog ? _("Save File...")
1554 : _("Open File...")));
1555 if (savedialog) {
1556 current_folder = gaim_prefs_get_string("/gaim/gtk/filelocations/last_save_folder");
1557 } else {
1558 current_folder = gaim_prefs_get_string("/gaim/gtk/filelocations/last_open_folder");
1559 }
1560 if (current_folder != NULL) {
1561 gchar *path = g_strdup_printf("%s%s", current_folder, G_DIR_SEPARATOR_S);
1562 gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), path);
1563 g_free(path);
1564 }
1565 if (filename != NULL)
1566 gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), filename);
1567
1568 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)), "delete_event",
1569 G_CALLBACK(file_cancel_cb), data);
1570 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button),
1571 "clicked", G_CALLBACK(file_cancel_cb), data);
1572 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
1573 G_CALLBACK(file_ok_check_if_exists_cb), data);
1574 #endif /* FILECHOOSER */
1575
1576 data->dialog = filesel;
1577 gtk_widget_show(filesel);
1578
1579 return (void *)data;
1580 }
1581
1582 static void *
1583 gaim_gtk_request_folder(const char *title, const char *dirname,
1584 GCallback ok_cb, GCallback cancel_cb,
1585 void *user_data)
1586 {
1587 GaimGtkRequestData *data;
1588 GtkWidget *dirsel;
1589
1590 data = g_new0(GaimGtkRequestData, 1);
1591 data->type = GAIM_REQUEST_FOLDER;
1592 data->user_data = user_data;
1593 data->cb_count = 2;
1594 data->cbs = g_new0(GCallback, 2);
1595 data->cbs[0] = cancel_cb;
1596 data->cbs[1] = ok_cb;
1597 data->u.file.savedialog = FALSE;
1598
1599 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
1600 dirsel = gtk_file_chooser_dialog_new(
1601 title ? title : _("Select Folder..."),
1602 NULL,
1603 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
1604 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1605 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1606 NULL);
1607 gtk_dialog_set_default_response(GTK_DIALOG(dirsel), GTK_RESPONSE_ACCEPT);
1608
1609 if ((dirname != NULL) && (*dirname != '\0'))
1610 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirsel), dirname);
1611
1612 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(dirsel)), "response",
1613 G_CALLBACK(file_ok_check_if_exists_cb), data);
1614 #else
1615 dirsel = gtk_file_selection_new(title ? title : _("Select Folder..."));
1616
1617 g_signal_connect_swapped(G_OBJECT(dirsel), "delete_event",
1618 G_CALLBACK(file_cancel_cb), data);
1619 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(dirsel)->cancel_button),
1620 "clicked", G_CALLBACK(file_cancel_cb), data);
1621 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dirsel)->ok_button), "clicked",
1622 G_CALLBACK(file_ok_check_if_exists_cb), data);
1623 #endif
1624
1625 data->dialog = dirsel;
1626 gtk_widget_show(dirsel);
1627
1628 return (void *)data;
1629 }
1630
1631 static void
1632 gaim_gtk_close_request(GaimRequestType type, void *ui_handle)
1633 {
1634 GaimGtkRequestData *data = (GaimGtkRequestData *)ui_handle;
1635
1636 g_free(data->cbs);
1637
1638 gtk_widget_destroy(data->dialog);
1639
1640 if (type == GAIM_REQUEST_FIELDS)
1641 gaim_request_fields_destroy(data->u.multifield.fields);
1642 else if (type == GAIM_REQUEST_FILE)
1643 g_free(data->u.file.name);
1644
1645 g_free(data);
1646 }
1647
1648 static GaimRequestUiOps ops =
1649 {
1650 gaim_gtk_request_input,
1651 gaim_gtk_request_choice,
1652 gaim_gtk_request_action,
1653 gaim_gtk_request_fields,
1654 gaim_gtk_request_file,
1655 gaim_gtk_close_request,
1656 gaim_gtk_request_folder
1657 };
1658
1659 GaimRequestUiOps *
1660 gaim_gtk_request_get_ui_ops(void)
1661 {
1662 return &ops;
1663 }