comparison pidgin/gtkrequest.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 9c0cf4db1f4d
comparison
equal deleted inserted replaced
15373:f79e0f4df793 15374:5fe8042783c1
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 if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*')
427 gtk_entry_set_invisible_char(GTK_ENTRY(entry), GAIM_INVISIBLE_CHAR);
428 }
429 }
430 }
431
432 gaim_set_accessible_label (entry, label);
433 data->u.input.entry = entry;
434
435 /* Show everything. */
436 gtk_widget_show_all(dialog);
437
438 return data;
439 }
440
441 static void *
442 gaim_gtk_request_choice(const char *title, const char *primary,
443 const char *secondary, unsigned int default_value,
444 const char *ok_text, GCallback ok_cb,
445 const char *cancel_text, GCallback cancel_cb,
446 void *user_data, va_list args)
447 {
448 GaimGtkRequestData *data;
449 GtkWidget *dialog;
450 GtkWidget *vbox, *vbox2;
451 GtkWidget *hbox;
452 GtkWidget *label;
453 GtkWidget *img;
454 GtkWidget *radio = NULL;
455 char *label_text;
456 char *radio_text;
457 char *primary_esc, *secondary_esc;
458
459 data = g_new0(GaimGtkRequestData, 1);
460 data->type = GAIM_REQUEST_ACTION;
461 data->user_data = user_data;
462
463 data->cb_count = 2;
464 data->cbs = g_new0(GCallback, 2);
465 data->cbs[0] = cancel_cb;
466 data->cbs[1] = ok_cb;
467
468 /* Create the dialog. */
469 data->dialog = dialog = gtk_dialog_new();
470
471 if (title != NULL)
472 gtk_window_set_title(GTK_WINDOW(dialog), title);
473
474
475 gtk_dialog_add_button(GTK_DIALOG(dialog),
476 text_to_stock(cancel_text), 0);
477
478 gtk_dialog_add_button(GTK_DIALOG(dialog),
479 text_to_stock(ok_text), 1);
480
481 g_signal_connect(G_OBJECT(dialog), "response",
482 G_CALLBACK(choice_response_cb), data);
483
484 /* Setup the dialog */
485 gtk_container_set_border_width(GTK_CONTAINER(dialog), GAIM_HIG_BORDER/2);
486 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER/2);
487 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
488 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
489 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER);
490
491 /* Setup the main horizontal box */
492 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER);
493 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
494
495 /* Dialog icon. */
496 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
497 GTK_ICON_SIZE_DIALOG);
498 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
499 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
500
501 /* Vertical box */
502 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
503 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
504
505 /* Descriptive label */
506 primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL;
507 secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL;
508 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">"
509 "%s</span>%s%s" : "%s%s%s"),
510 (primary ? primary_esc : ""),
511 ((primary && secondary) ? "\n\n" : ""),
512 (secondary ? secondary_esc : ""));
513 g_free(primary_esc);
514 g_free(secondary_esc);
515
516 label = gtk_label_new(NULL);
517
518 gtk_label_set_markup(GTK_LABEL(label), label_text);
519 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
520 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
521 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
522
523 g_free(label_text);
524
525 vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
526 gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0);
527 while ((radio_text = va_arg(args, char*))) {
528 int resp = va_arg(args, int);
529 radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), radio_text);
530 gtk_box_pack_start(GTK_BOX(vbox2), radio, FALSE, FALSE, 0);
531 g_object_set_data(G_OBJECT(radio), "choice_id", GINT_TO_POINTER(resp));
532 if (resp == default_value)
533 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
534 }
535
536 g_object_set_data(G_OBJECT(dialog), "radio", radio);
537
538 /* Show everything. */
539 gtk_widget_show_all(dialog);
540
541 return data;
542 }
543
544 static void *
545 gaim_gtk_request_action(const char *title, const char *primary,
546 const char *secondary, unsigned int default_action,
547 void *user_data, size_t action_count, va_list actions)
548 {
549 GaimGtkRequestData *data;
550 GtkWidget *dialog;
551 GtkWidget *vbox;
552 GtkWidget *hbox;
553 GtkWidget *label;
554 GtkWidget *img;
555 void **buttons;
556 char *label_text;
557 char *primary_esc, *secondary_esc;
558 int i;
559
560 data = g_new0(GaimGtkRequestData, 1);
561 data->type = GAIM_REQUEST_ACTION;
562 data->user_data = user_data;
563
564 data->cb_count = action_count;
565 data->cbs = g_new0(GCallback, action_count);
566
567 /* Reverse the buttons */
568 buttons = g_new0(void *, action_count * 2);
569
570 for (i = 0; i < action_count * 2; i += 2) {
571 buttons[(action_count * 2) - i - 2] = va_arg(actions, char *);
572 buttons[(action_count * 2) - i - 1] = va_arg(actions, GCallback);
573 }
574
575 /* Create the dialog. */
576 data->dialog = dialog = gtk_dialog_new();
577
578 if (title != NULL)
579 gtk_window_set_title(GTK_WINDOW(dialog), title);
580
581 for (i = 0; i < action_count; i++) {
582 gtk_dialog_add_button(GTK_DIALOG(dialog),
583 text_to_stock(buttons[2 * i]), i);
584
585 data->cbs[i] = buttons[2 * i + 1];
586 }
587
588 g_free(buttons);
589
590 g_signal_connect(G_OBJECT(dialog), "response",
591 G_CALLBACK(action_response_cb), data);
592
593 /* Setup the dialog */
594 gtk_container_set_border_width(GTK_CONTAINER(dialog), GAIM_HIG_BORDER/2);
595 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER/2);
596 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
597 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
598 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER);
599
600 /* Setup the main horizontal box */
601 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER);
602 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
603
604 /* Dialog icon. */
605 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
606 GTK_ICON_SIZE_DIALOG);
607 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
608 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
609
610 /* Vertical box */
611 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
612 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
613
614 /* Descriptive label */
615 primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL;
616 secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL;
617 label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">"
618 "%s</span>%s%s" : "%s%s%s"),
619 (primary ? primary_esc : ""),
620 ((primary && secondary) ? "\n\n" : ""),
621 (secondary ? secondary_esc : ""));
622 g_free(primary_esc);
623 g_free(secondary_esc);
624
625 label = gtk_label_new(NULL);
626
627 gtk_label_set_markup(GTK_LABEL(label), label_text);
628 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
629 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
630 gtk_label_set_selectable(GTK_LABEL(label), TRUE);
631 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
632
633 g_free(label_text);
634
635
636 if (default_action == GAIM_DEFAULT_ACTION_NONE) {
637 GTK_WIDGET_SET_FLAGS(img, GTK_CAN_DEFAULT);
638 GTK_WIDGET_SET_FLAGS(img, GTK_CAN_FOCUS);
639 gtk_widget_grab_focus(img);
640 gtk_widget_grab_default(img);
641 } else
642 gtk_dialog_set_default_response(GTK_DIALOG(dialog), default_action);
643
644 /* Show everything. */
645 gtk_widget_show_all(dialog);
646
647 return data;
648 }
649
650 static void
651 req_entry_field_changed_cb(GtkWidget *entry, GaimRequestField *field)
652 {
653 GaimGtkRequestData *req_data;
654 const char *text = gtk_entry_get_text(GTK_ENTRY(entry));
655
656 gaim_request_field_string_set_value(field, (*text == '\0' ? NULL : text));
657
658 req_data = (GaimGtkRequestData *)field->group->fields_list->ui_data;
659
660 gtk_widget_set_sensitive(req_data->ok_button,
661 gaim_request_fields_all_required_filled(field->group->fields_list));
662 }
663
664 static void
665 setup_entry_field(GtkWidget *entry, GaimRequestField *field)
666 {
667 const char *type_hint;
668
669 gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
670
671 if (gaim_request_field_is_required(field))
672 {
673 g_signal_connect(G_OBJECT(entry), "changed",
674 G_CALLBACK(req_entry_field_changed_cb), field);
675 }
676
677 if ((type_hint = gaim_request_field_get_type_hint(field)) != NULL)
678 {
679 if (gaim_str_has_prefix(type_hint, "screenname"))
680 {
681 GtkWidget *optmenu = NULL;
682 GList *fields = field->group->fields;
683 while (fields)
684 {
685 GaimRequestField *fld = fields->data;
686 fields = fields->next;
687
688 if (gaim_request_field_get_type(fld) == GAIM_REQUEST_FIELD_ACCOUNT)
689 {
690 const char *type_hint = gaim_request_field_get_type_hint(fld);
691 if (type_hint != NULL && strcmp(type_hint, "account") == 0)
692 {
693 if (fld->ui_data == NULL)
694 fld->ui_data = create_account_field(fld);
695 optmenu = GTK_WIDGET(fld->ui_data);
696 break;
697 }
698 }
699 }
700 gaim_gtk_setup_screenname_autocomplete(entry, optmenu, !strcmp(type_hint, "screenname-all"));
701 }
702 }
703 }
704
705 static GtkWidget *
706 create_string_field(GaimRequestField *field)
707 {
708 const char *value;
709 GtkWidget *widget;
710
711 value = gaim_request_field_string_get_default_value(field);
712
713 if (gaim_request_field_string_is_multiline(field))
714 {
715 GtkWidget *textview;
716
717 widget = gtk_scrolled_window_new(NULL, NULL);
718 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget),
719 GTK_SHADOW_IN);
720 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
721 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
722
723 textview = gtk_text_view_new();
724 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview),
725 TRUE);
726 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview),
727 GTK_WRAP_WORD_CHAR);
728
729 if (gaim_prefs_get_bool("/gaim/gtk/conversations/spellcheck"))
730 gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(textview));
731
732 gtk_container_add(GTK_CONTAINER(widget), textview);
733 gtk_widget_show(textview);
734
735 gtk_widget_set_size_request(widget, -1, 75);
736
737 if (value != NULL)
738 {
739 GtkTextBuffer *buffer;
740
741 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
742
743 gtk_text_buffer_set_text(buffer, value, -1);
744 }
745
746 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview),
747 gaim_request_field_string_is_editable(field));
748
749 g_signal_connect(G_OBJECT(textview), "focus-out-event",
750 G_CALLBACK(field_string_focus_out_cb), field);
751 }
752 else
753 {
754 widget = gtk_entry_new();
755
756 setup_entry_field(widget, field);
757
758 if (value != NULL)
759 gtk_entry_set_text(GTK_ENTRY(widget), value);
760
761 if (gaim_request_field_string_is_masked(field))
762 {
763 gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
764 if (gtk_entry_get_invisible_char(GTK_ENTRY(widget)) == '*')
765 gtk_entry_set_invisible_char(GTK_ENTRY(widget), GAIM_INVISIBLE_CHAR);
766 }
767
768 gtk_editable_set_editable(GTK_EDITABLE(widget),
769 gaim_request_field_string_is_editable(field));
770
771 g_signal_connect(G_OBJECT(widget), "focus-out-event",
772 G_CALLBACK(field_string_focus_out_cb), field);
773 }
774
775 return widget;
776 }
777
778 static GtkWidget *
779 create_int_field(GaimRequestField *field)
780 {
781 int value;
782 GtkWidget *widget;
783
784 widget = gtk_entry_new();
785
786 setup_entry_field(widget, field);
787
788 value = gaim_request_field_int_get_default_value(field);
789
790 if (value != 0)
791 {
792 char buf[32];
793
794 g_snprintf(buf, sizeof(buf), "%d", value);
795
796 gtk_entry_set_text(GTK_ENTRY(widget), buf);
797 }
798
799 g_signal_connect(G_OBJECT(widget), "focus-out-event",
800 G_CALLBACK(field_int_focus_out_cb), field);
801
802 return widget;
803 }
804
805 static GtkWidget *
806 create_bool_field(GaimRequestField *field)
807 {
808 GtkWidget *widget;
809
810 widget = gtk_check_button_new_with_label(
811 gaim_request_field_get_label(field));
812
813 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
814 gaim_request_field_bool_get_default_value(field));
815
816 g_signal_connect(G_OBJECT(widget), "toggled",
817 G_CALLBACK(field_bool_cb), field);
818
819 return widget;
820 }
821
822 static GtkWidget *
823 create_choice_field(GaimRequestField *field)
824 {
825 GtkWidget *widget;
826 GList *labels;
827 GList *l;
828
829 labels = gaim_request_field_choice_get_labels(field);
830
831 if (g_list_length(labels) > 5)
832 {
833 GtkWidget *menu;
834 GtkWidget *item;
835
836 widget = gtk_option_menu_new();
837
838 menu = gtk_menu_new();
839
840 for (l = labels; l != NULL; l = l->next)
841 {
842 const char *text = l->data;
843
844 item = gtk_menu_item_new_with_label(text);
845 gtk_widget_show(item);
846
847 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
848 }
849
850 gtk_widget_show(menu);
851 gtk_option_menu_set_menu(GTK_OPTION_MENU(widget), menu);
852 gtk_option_menu_set_history(GTK_OPTION_MENU(widget),
853 gaim_request_field_choice_get_default_value(field));
854
855 g_signal_connect(G_OBJECT(widget), "changed",
856 G_CALLBACK(field_choice_menu_cb), field);
857 }
858 else
859 {
860 GtkWidget *box;
861 GtkWidget *first_radio = NULL;
862 GtkWidget *radio;
863 gint i;
864
865 if (g_list_length(labels) == 2)
866 box = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
867 else
868 box = gtk_vbox_new(FALSE, 0);
869
870 widget = box;
871
872 for (l = labels, i = 0; l != NULL; l = l->next, i++)
873 {
874 const char *text = l->data;
875
876 radio = gtk_radio_button_new_with_label_from_widget(
877 GTK_RADIO_BUTTON(first_radio), text);
878
879 if (first_radio == NULL)
880 first_radio = radio;
881
882 if (i == gaim_request_field_choice_get_default_value(field))
883 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
884
885 gtk_box_pack_start(GTK_BOX(box), radio, TRUE, TRUE, 0);
886 gtk_widget_show(radio);
887
888 g_signal_connect(G_OBJECT(radio), "toggled",
889 G_CALLBACK(field_choice_option_cb), field);
890 }
891 }
892
893 return widget;
894 }
895
896 static GtkWidget *
897 create_image_field(GaimRequestField *field)
898 {
899 GtkWidget *widget;
900 GdkPixbuf *buf, *scale;
901 GdkPixbufLoader *loader;
902
903 loader = gdk_pixbuf_loader_new();
904 gdk_pixbuf_loader_write(loader,
905 (const guchar *)gaim_request_field_image_get_buffer(field),
906 gaim_request_field_image_get_size(field),
907 NULL);
908 gdk_pixbuf_loader_close(loader, NULL);
909 buf = gdk_pixbuf_loader_get_pixbuf(loader);
910
911 scale = gdk_pixbuf_scale_simple(buf,
912 gaim_request_field_image_get_scale_x(field) * gdk_pixbuf_get_width(buf),
913 gaim_request_field_image_get_scale_y(field) * gdk_pixbuf_get_height(buf),
914 GDK_INTERP_BILINEAR);
915 widget = gtk_image_new_from_pixbuf(scale);
916 g_object_unref(G_OBJECT(buf));
917 g_object_unref(G_OBJECT(scale));
918
919 return widget;
920 }
921
922 static GtkWidget *
923 create_account_field(GaimRequestField *field)
924 {
925 GtkWidget *widget;
926
927 widget = gaim_gtk_account_option_menu_new(
928 gaim_request_field_account_get_default_value(field),
929 gaim_request_field_account_get_show_all(field),
930 G_CALLBACK(field_account_cb),
931 gaim_request_field_account_get_filter(field),
932 field);
933
934 return widget;
935 }
936
937 static void
938 select_field_list_item(GtkTreeModel *model, GtkTreePath *path,
939 GtkTreeIter *iter, gpointer data)
940 {
941 GaimRequestField *field = (GaimRequestField *)data;
942 char *text;
943
944 gtk_tree_model_get(model, iter, 1, &text, -1);
945
946 gaim_request_field_list_add_selected(field, text);
947 g_free(text);
948 }
949
950 static void
951 list_field_select_changed_cb(GtkTreeSelection *sel, GaimRequestField *field)
952 {
953 gaim_request_field_list_clear_selected(field);
954
955 gtk_tree_selection_selected_foreach(sel, select_field_list_item, field);
956 }
957
958 static GtkWidget *
959 create_list_field(GaimRequestField *field)
960 {
961 GtkWidget *sw;
962 GtkWidget *treeview;
963 GtkListStore *store;
964 GtkCellRenderer *renderer;
965 GtkTreeSelection *sel;
966 GtkTreeViewColumn *column;
967 GtkTreeIter iter;
968 const GList *l;
969
970 /* Create the scrolled window */
971 sw = gtk_scrolled_window_new(NULL, NULL);
972 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
973 GTK_POLICY_AUTOMATIC,
974 GTK_POLICY_AUTOMATIC);
975 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
976 GTK_SHADOW_IN);
977 gtk_widget_show(sw);
978
979 /* Create the list store */
980 store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING);
981
982 /* Create the tree view */
983 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
984 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
985 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
986
987 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
988
989 if (gaim_request_field_list_get_multi_select(field))
990 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
991
992 g_signal_connect(G_OBJECT(sel), "changed",
993 G_CALLBACK(list_field_select_changed_cb), field);
994
995 column = gtk_tree_view_column_new();
996 gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1);
997
998 renderer = gtk_cell_renderer_text_new();
999 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1000 gtk_tree_view_column_add_attribute(column, renderer, "text", 1);
1001
1002 for (l = gaim_request_field_list_get_items(field); l != NULL; l = l->next)
1003 {
1004 const char *text = (const char *)l->data;
1005
1006 gtk_list_store_append(store, &iter);
1007
1008 gtk_list_store_set(store, &iter,
1009 0, gaim_request_field_list_get_data(field, text),
1010 1, text,
1011 -1);
1012
1013 if (gaim_request_field_list_is_selected(field, text))
1014 gtk_tree_selection_select_iter(sel, &iter);
1015 }
1016
1017 gtk_container_add(GTK_CONTAINER(sw), treeview);
1018 gtk_widget_show(treeview);
1019
1020 return sw;
1021 }
1022
1023 static void *
1024 gaim_gtk_request_fields(const char *title, const char *primary,
1025 const char *secondary, GaimRequestFields *fields,
1026 const char *ok_text, GCallback ok_cb,
1027 const char *cancel_text, GCallback cancel_cb,
1028 void *user_data)
1029 {
1030 GaimGtkRequestData *data;
1031 GtkWidget *win;
1032 GtkWidget *vbox;
1033 GtkWidget *vbox2;
1034 GtkWidget *hbox;
1035 GtkWidget *bbox;
1036 GtkWidget *frame;
1037 GtkWidget *label;
1038 GtkWidget *table;
1039 GtkWidget *button;
1040 GtkWidget *img;
1041 GtkWidget *sw;
1042 GtkSizeGroup *sg;
1043 GList *gl, *fl;
1044 GaimRequestFieldGroup *group;
1045 GaimRequestField *field;
1046 char *label_text;
1047 char *primary_esc, *secondary_esc;
1048 int total_fields = 0;
1049
1050 data = g_new0(GaimGtkRequestData, 1);
1051 data->type = GAIM_REQUEST_FIELDS;
1052 data->user_data = user_data;
1053 data->u.multifield.fields = fields;
1054
1055 fields->ui_data = data;
1056
1057 data->cb_count = 2;
1058 data->cbs = g_new0(GCallback, 2);
1059
1060 data->cbs[0] = ok_cb;
1061 data->cbs[1] = cancel_cb;
1062
1063 data->dialog = win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1064
1065 if (title != NULL)
1066 gtk_window_set_title(GTK_WINDOW(win), title);
1067
1068 gtk_window_set_role(GTK_WINDOW(win), "multifield");
1069 gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER);
1070
1071 g_signal_connect(G_OBJECT(win), "delete_event",
1072 G_CALLBACK(destroy_multifield_cb), data);
1073
1074 /* Setup the main horizontal box */
1075 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER);
1076 gtk_container_add(GTK_CONTAINER(win), hbox);
1077 gtk_widget_show(hbox);
1078
1079 /* Dialog icon. */
1080 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
1081 GTK_ICON_SIZE_DIALOG);
1082 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
1083 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
1084 gtk_widget_show(img);
1085
1086 /* Setup the vbox */
1087 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
1088 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
1089 gtk_widget_show(vbox);
1090
1091 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1092
1093 if(primary) {
1094 primary_esc = g_markup_escape_text(primary, -1);
1095 label_text = g_strdup_printf(
1096 "<span weight=\"bold\" size=\"larger\">%s</span>", primary_esc);
1097 g_free(primary_esc);
1098 label = gtk_label_new(NULL);
1099
1100 gtk_label_set_markup(GTK_LABEL(label), label_text);
1101 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1102 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1103 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
1104 gtk_widget_show(label);
1105 g_free(label_text);
1106 }
1107
1108 for (gl = gaim_request_fields_get_groups(fields); gl != NULL;
1109 gl = gl->next)
1110 total_fields += g_list_length(gaim_request_field_group_get_fields(gl->data));
1111
1112 if(total_fields > 9) {
1113 sw = gtk_scrolled_window_new(NULL, NULL);
1114 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1115 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1116 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1117 GTK_SHADOW_NONE);
1118 gtk_widget_set_size_request(sw, -1, 200);
1119 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
1120 gtk_widget_show(sw);
1121
1122 vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
1123 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), vbox2);
1124 gtk_widget_show(vbox2);
1125 } else {
1126 vbox2 = vbox;
1127 }
1128
1129 if (secondary) {
1130 secondary_esc = g_markup_escape_text(secondary, -1);
1131 label = gtk_label_new(NULL);
1132
1133 gtk_label_set_markup(GTK_LABEL(label), secondary_esc);
1134 g_free(secondary_esc);
1135 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1136 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1137 gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0);
1138 gtk_widget_show(label);
1139 }
1140
1141 for (gl = gaim_request_fields_get_groups(fields);
1142 gl != NULL;
1143 gl = gl->next)
1144 {
1145 GList *field_list;
1146 size_t field_count = 0;
1147 size_t cols = 1;
1148 size_t rows;
1149 size_t col_num;
1150 size_t row_num = 0;
1151
1152 group = gl->data;
1153 field_list = gaim_request_field_group_get_fields(group);
1154
1155 if (gaim_request_field_group_get_title(group) != NULL)
1156 {
1157 frame = gaim_gtk_make_frame(vbox2,
1158 gaim_request_field_group_get_title(group));
1159 }
1160 else
1161 frame = vbox2;
1162
1163 field_count = g_list_length(field_list);
1164 /*
1165 if (field_count > 9)
1166 {
1167 rows = field_count / 2;
1168 cols++;
1169 }
1170 else
1171 */
1172 rows = field_count;
1173
1174 col_num = 0;
1175
1176 for (fl = field_list; fl != NULL; fl = fl->next)
1177 {
1178 GaimRequestFieldType type;
1179
1180 field = (GaimRequestField *)fl->data;
1181
1182 type = gaim_request_field_get_type(field);
1183
1184 if (type == GAIM_REQUEST_FIELD_LABEL)
1185 {
1186 if (col_num > 0)
1187 rows++;
1188
1189 rows++;
1190 }
1191 else if ((type == GAIM_REQUEST_FIELD_LIST) ||
1192 (type == GAIM_REQUEST_FIELD_STRING &&
1193 gaim_request_field_string_is_multiline(field)))
1194 {
1195 if (col_num > 0)
1196 rows++;
1197
1198 rows += 2;
1199 }
1200
1201 col_num++;
1202
1203 if (col_num >= cols)
1204 col_num = 0;
1205 }
1206
1207 table = gtk_table_new(rows, 2 * cols, FALSE);
1208 gtk_table_set_row_spacings(GTK_TABLE(table), GAIM_HIG_BOX_SPACE);
1209 gtk_table_set_col_spacings(GTK_TABLE(table), GAIM_HIG_BOX_SPACE);
1210
1211 gtk_container_add(GTK_CONTAINER(frame), table);
1212 gtk_widget_show(table);
1213
1214 for (row_num = 0, fl = field_list;
1215 row_num < rows && fl != NULL;
1216 row_num++)
1217 {
1218 for (col_num = 0;
1219 col_num < cols && fl != NULL;
1220 col_num++, fl = fl->next)
1221 {
1222 size_t col_offset = col_num * 2;
1223 GaimRequestFieldType type;
1224 GtkWidget *widget = NULL;
1225
1226 label = NULL;
1227 field = fl->data;
1228
1229 if (!gaim_request_field_is_visible(field)) {
1230 col_num--;
1231 continue;
1232 }
1233
1234 type = gaim_request_field_get_type(field);
1235
1236 if (type != GAIM_REQUEST_FIELD_BOOLEAN &&
1237 gaim_request_field_get_label(field))
1238 {
1239 char *text;
1240
1241 text = g_strdup_printf("%s:",
1242 gaim_request_field_get_label(field));
1243
1244 label = gtk_label_new(NULL);
1245 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), text);
1246 g_free(text);
1247
1248 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1249
1250 gtk_size_group_add_widget(sg, label);
1251
1252 if (type == GAIM_REQUEST_FIELD_LABEL ||
1253 type == GAIM_REQUEST_FIELD_LIST ||
1254 (type == GAIM_REQUEST_FIELD_STRING &&
1255 gaim_request_field_string_is_multiline(field)))
1256 {
1257 if(col_num > 0)
1258 row_num++;
1259
1260 gtk_table_attach_defaults(GTK_TABLE(table), label,
1261 0, 2 * cols,
1262 row_num, row_num + 1);
1263
1264 row_num++;
1265 col_num=cols;
1266 }
1267 else
1268 {
1269 gtk_table_attach_defaults(GTK_TABLE(table), label,
1270 col_offset, col_offset + 1,
1271 row_num, row_num + 1);
1272 }
1273
1274 gtk_widget_show(label);
1275 }
1276
1277 if (field->ui_data != NULL)
1278 widget = GTK_WIDGET(field->ui_data);
1279 else if (type == GAIM_REQUEST_FIELD_STRING)
1280 widget = create_string_field(field);
1281 else if (type == GAIM_REQUEST_FIELD_INTEGER)
1282 widget = create_int_field(field);
1283 else if (type == GAIM_REQUEST_FIELD_BOOLEAN)
1284 widget = create_bool_field(field);
1285 else if (type == GAIM_REQUEST_FIELD_CHOICE)
1286 widget = create_choice_field(field);
1287 else if (type == GAIM_REQUEST_FIELD_LIST)
1288 widget = create_list_field(field);
1289 else if (type == GAIM_REQUEST_FIELD_IMAGE)
1290 widget = create_image_field(field);
1291 else if (type == GAIM_REQUEST_FIELD_ACCOUNT)
1292 widget = create_account_field(field);
1293 else
1294 continue;
1295
1296 if (label)
1297 gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget);
1298
1299 if (type == GAIM_REQUEST_FIELD_STRING &&
1300 gaim_request_field_string_is_multiline(field))
1301 {
1302 gtk_table_attach(GTK_TABLE(table), widget,
1303 0, 2 * cols,
1304 row_num, row_num + 1,
1305 GTK_FILL | GTK_EXPAND,
1306 GTK_FILL | GTK_EXPAND,
1307 5, 0);
1308 }
1309 else if (type == GAIM_REQUEST_FIELD_LIST)
1310 {
1311 gtk_table_attach(GTK_TABLE(table), widget,
1312 0, 2 * cols,
1313 row_num, row_num + 1,
1314 GTK_FILL | GTK_EXPAND,
1315 GTK_FILL | GTK_EXPAND,
1316 5, 0);
1317 }
1318 else if (type == GAIM_REQUEST_FIELD_BOOLEAN)
1319 {
1320 gtk_table_attach(GTK_TABLE(table), widget,
1321 col_offset, col_offset + 1,
1322 row_num, row_num + 1,
1323 GTK_FILL | GTK_EXPAND,
1324 GTK_FILL | GTK_EXPAND,
1325 5, 0);
1326 }
1327 else
1328 {
1329 gtk_table_attach(GTK_TABLE(table), widget,
1330 1, 2 * cols,
1331 row_num, row_num + 1,
1332 GTK_FILL | GTK_EXPAND,
1333 GTK_FILL | GTK_EXPAND,
1334 5, 0);
1335 }
1336
1337 gtk_widget_show(widget);
1338
1339 field->ui_data = widget;
1340 }
1341 }
1342 }
1343
1344 g_object_unref(sg);
1345
1346 /* Button box. */
1347 bbox = gtk_hbutton_box_new();
1348 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE);
1349 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1350 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0);
1351 gtk_widget_show(bbox);
1352
1353 /* Cancel button */
1354 button = gtk_button_new_from_stock(text_to_stock(cancel_text));
1355 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1356 gtk_widget_show(button);
1357
1358 g_signal_connect(G_OBJECT(button), "clicked",
1359 G_CALLBACK(multifield_cancel_cb), data);
1360
1361 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1362
1363 /* OK button */
1364 button = gtk_button_new_from_stock(text_to_stock(ok_text));
1365 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1366 gtk_widget_show(button);
1367
1368 data->ok_button = button;
1369
1370 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1371 gtk_window_set_default(GTK_WINDOW(win), button);
1372
1373 g_signal_connect(G_OBJECT(button), "clicked",
1374 G_CALLBACK(multifield_ok_cb), data);
1375
1376 if (!gaim_request_fields_all_required_filled(fields))
1377 gtk_widget_set_sensitive(button, FALSE);
1378
1379 gtk_widget_show(win);
1380
1381 return data;
1382 }
1383
1384 static void
1385 file_yes_no_cb(GaimGtkRequestData *data, gint id)
1386 {
1387 /* Only call the callback if yes was selected, otherwise the request
1388 * (eg. file transfer) will be cancelled, then when a new filename is chosen
1389 * things go BOOM */
1390 if (id == 1) {
1391 if (data->cbs[1] != NULL)
1392 ((GaimRequestFileCb)data->cbs[1])(data->user_data, data->u.file.name);
1393 gaim_request_close(data->type, data);
1394 } else {
1395 gaim_gtk_clear_cursor(GTK_WIDGET(data->dialog));
1396 }
1397 }
1398
1399 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
1400 static void
1401 file_ok_check_if_exists_cb(GtkWidget *widget, gint response, GaimGtkRequestData *data)
1402 {
1403 gchar *current_folder;
1404
1405 generic_response_start(data);
1406
1407 if (response != GTK_RESPONSE_ACCEPT) {
1408 if (data->cbs[0] != NULL)
1409 ((GaimRequestFileCb)data->cbs[0])(data->user_data, NULL);
1410 gaim_request_close(data->type, data);
1411 return;
1412 }
1413
1414 data->u.file.name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data->dialog));
1415 current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(data->dialog));
1416 if (current_folder != NULL) {
1417 if (data->u.file.savedialog) {
1418 gaim_prefs_set_path("/gaim/gtk/filelocations/last_save_folder", current_folder);
1419 } else {
1420 gaim_prefs_set_path("/gaim/gtk/filelocations/last_open_folder", current_folder);
1421 }
1422 g_free(current_folder);
1423 }
1424
1425 #else /* FILECHOOSER */
1426
1427 static void
1428 file_ok_check_if_exists_cb(GtkWidget *button, GaimGtkRequestData *data)
1429 {
1430 const gchar *name;
1431 gchar *current_folder;
1432
1433 generic_response_start(data);
1434
1435 name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(data->dialog));
1436
1437 /* If name is a directory then change directories */
1438 if (data->type == GAIM_REQUEST_FILE) {
1439 if (gaim_gtk_check_if_dir(name, GTK_FILE_SELECTION(data->dialog)))
1440 return;
1441 }
1442
1443 current_folder = g_path_get_dirname(name);
1444
1445 g_free(data->u.file.name);
1446 if (data->type == GAIM_REQUEST_FILE)
1447 data->u.file.name = g_strdup(name);
1448 else
1449 {
1450 if (g_file_test(name, G_FILE_TEST_IS_DIR))
1451 data->u.file.name = g_strdup(name);
1452 else
1453 data->u.file.name = g_strdup(current_folder);
1454 }
1455
1456 if (current_folder != NULL) {
1457 if (data->u.file.savedialog) {
1458 gaim_prefs_set_path("/gaim/gtk/filelocations/last_save_folder", current_folder);
1459 } else {
1460 gaim_prefs_set_path("/gaim/gtk/filelocations/last_open_folder", current_folder);
1461 }
1462 g_free(current_folder);
1463 }
1464
1465 #endif /* FILECHOOSER */
1466
1467 if ((data->u.file.savedialog == TRUE) &&
1468 (g_file_test(data->u.file.name, G_FILE_TEST_EXISTS))) {
1469 gaim_request_action(data, NULL, _("That file already exists"),
1470 _("Would you like to overwrite it?"), 0, data, 2,
1471 _("Overwrite"), G_CALLBACK(file_yes_no_cb),
1472 _("Choose New Name"), G_CALLBACK(file_yes_no_cb));
1473 } else
1474 file_yes_no_cb(data, 1);
1475 }
1476
1477 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
1478 static void
1479 file_cancel_cb(GaimGtkRequestData *data)
1480 {
1481 generic_response_start(data);
1482
1483 if (data->cbs[0] != NULL)
1484 ((GaimRequestFileCb)data->cbs[0])(data->user_data, NULL);
1485
1486 gaim_request_close(data->type, data);
1487 }
1488 #endif /* FILECHOOSER */
1489
1490 static void *
1491 gaim_gtk_request_file(const char *title, const char *filename,
1492 gboolean savedialog,
1493 GCallback ok_cb, GCallback cancel_cb,
1494 void *user_data)
1495 {
1496 GaimGtkRequestData *data;
1497 GtkWidget *filesel;
1498 const gchar *current_folder;
1499 #if GTK_CHECK_VERSION(2,4,0)
1500 gboolean folder_set = FALSE;
1501 #endif
1502
1503 data = g_new0(GaimGtkRequestData, 1);
1504 data->type = GAIM_REQUEST_FILE;
1505 data->user_data = user_data;
1506 data->cb_count = 2;
1507 data->cbs = g_new0(GCallback, 2);
1508 data->cbs[0] = cancel_cb;
1509 data->cbs[1] = ok_cb;
1510 data->u.file.savedialog = savedialog;
1511
1512 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
1513 filesel = gtk_file_chooser_dialog_new(
1514 title ? title : (savedialog ? _("Save File...")
1515 : _("Open File...")),
1516 NULL,
1517 savedialog ? GTK_FILE_CHOOSER_ACTION_SAVE
1518 : GTK_FILE_CHOOSER_ACTION_OPEN,
1519 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1520 savedialog ? GTK_STOCK_SAVE
1521 : GTK_STOCK_OPEN,
1522 GTK_RESPONSE_ACCEPT,
1523 NULL);
1524 gtk_dialog_set_default_response(GTK_DIALOG(filesel), GTK_RESPONSE_ACCEPT);
1525
1526 if (savedialog) {
1527 current_folder = gaim_prefs_get_path("/gaim/gtk/filelocations/last_save_folder");
1528 } else {
1529 current_folder = gaim_prefs_get_path("/gaim/gtk/filelocations/last_open_folder");
1530 }
1531
1532 if ((filename != NULL) && (*filename != '\0')) {
1533 if (savedialog)
1534 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filesel), filename);
1535 else
1536 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(filesel), filename);
1537 }
1538 if ((current_folder != NULL) && (*current_folder != '\0')) {
1539 folder_set = gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filesel), current_folder);
1540 }
1541
1542 #ifdef _WIN32
1543 if (!folder_set) {
1544 char *my_documents = wgaim_get_special_folder(CSIDL_PERSONAL);
1545
1546 if (my_documents != NULL) {
1547 gtk_file_chooser_set_current_folder(
1548 GTK_FILE_CHOOSER(filesel), my_documents);
1549
1550 g_free(my_documents);
1551 }
1552 }
1553
1554 #endif
1555 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(filesel)), "response",
1556 G_CALLBACK(file_ok_check_if_exists_cb), data);
1557 #else /* FILECHOOSER */
1558 filesel = gtk_file_selection_new(
1559 title ? title : (savedialog ? _("Save File...")
1560 : _("Open File...")));
1561 if (savedialog) {
1562 current_folder = gaim_prefs_get_path("/gaim/gtk/filelocations/last_save_folder");
1563 } else {
1564 current_folder = gaim_prefs_get_path("/gaim/gtk/filelocations/last_open_folder");
1565 }
1566 if (current_folder != NULL) {
1567 gchar *path = g_strdup_printf("%s%s", current_folder, G_DIR_SEPARATOR_S);
1568 gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), path);
1569 g_free(path);
1570 }
1571 if (filename != NULL)
1572 gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), filename);
1573
1574 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)), "delete_event",
1575 G_CALLBACK(file_cancel_cb), data);
1576 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button),
1577 "clicked", G_CALLBACK(file_cancel_cb), data);
1578 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
1579 G_CALLBACK(file_ok_check_if_exists_cb), data);
1580 #endif /* FILECHOOSER */
1581
1582 data->dialog = filesel;
1583 gtk_widget_show(filesel);
1584
1585 return (void *)data;
1586 }
1587
1588 static void *
1589 gaim_gtk_request_folder(const char *title, const char *dirname,
1590 GCallback ok_cb, GCallback cancel_cb,
1591 void *user_data)
1592 {
1593 GaimGtkRequestData *data;
1594 GtkWidget *dirsel;
1595
1596 data = g_new0(GaimGtkRequestData, 1);
1597 data->type = GAIM_REQUEST_FOLDER;
1598 data->user_data = user_data;
1599 data->cb_count = 2;
1600 data->cbs = g_new0(GCallback, 2);
1601 data->cbs[0] = cancel_cb;
1602 data->cbs[1] = ok_cb;
1603 data->u.file.savedialog = FALSE;
1604
1605 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
1606 dirsel = gtk_file_chooser_dialog_new(
1607 title ? title : _("Select Folder..."),
1608 NULL,
1609 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
1610 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1611 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1612 NULL);
1613 gtk_dialog_set_default_response(GTK_DIALOG(dirsel), GTK_RESPONSE_ACCEPT);
1614
1615 if ((dirname != NULL) && (*dirname != '\0'))
1616 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirsel), dirname);
1617
1618 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(dirsel)), "response",
1619 G_CALLBACK(file_ok_check_if_exists_cb), data);
1620 #else
1621 dirsel = gtk_file_selection_new(title ? title : _("Select Folder..."));
1622
1623 g_signal_connect_swapped(G_OBJECT(dirsel), "delete_event",
1624 G_CALLBACK(file_cancel_cb), data);
1625 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(dirsel)->cancel_button),
1626 "clicked", G_CALLBACK(file_cancel_cb), data);
1627 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dirsel)->ok_button), "clicked",
1628 G_CALLBACK(file_ok_check_if_exists_cb), data);
1629 #endif
1630
1631 data->dialog = dirsel;
1632 gtk_widget_show(dirsel);
1633
1634 return (void *)data;
1635 }
1636
1637 static void
1638 gaim_gtk_close_request(GaimRequestType type, void *ui_handle)
1639 {
1640 GaimGtkRequestData *data = (GaimGtkRequestData *)ui_handle;
1641
1642 g_free(data->cbs);
1643
1644 gtk_widget_destroy(data->dialog);
1645
1646 if (type == GAIM_REQUEST_FIELDS)
1647 gaim_request_fields_destroy(data->u.multifield.fields);
1648 else if (type == GAIM_REQUEST_FILE)
1649 g_free(data->u.file.name);
1650
1651 g_free(data);
1652 }
1653
1654 static GaimRequestUiOps ops =
1655 {
1656 gaim_gtk_request_input,
1657 gaim_gtk_request_choice,
1658 gaim_gtk_request_action,
1659 gaim_gtk_request_fields,
1660 gaim_gtk_request_file,
1661 gaim_gtk_close_request,
1662 gaim_gtk_request_folder
1663 };
1664
1665 GaimRequestUiOps *
1666 gaim_gtk_request_get_ui_ops(void)
1667 {
1668 return &ops;
1669 }