1 /**
2 * @file gntrequest.c GNT Request API
3 * @ingroup finch
4 */
5
6 /* finch
7 *
8 * Finch is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 */
26 #include <internal.h>
27
28 #include <gnt.h>
29 #include <gntbox.h>
30 #include <gntbutton.h>
31 #include <gntcheckbox.h>
32 #include <gntcombobox.h>
33 #include <gntentry.h>
34 #include <gntfilesel.h>
35 #include <gntlabel.h>
36 #include <gntline.h>
37 #include <gnttree.h>
38
39 #include "finch.h"
40 #include "gntrequest.h"
41 #include "debug.h"
42 #include "util.h"
43
44 /* XXX: Until gobjectification ... */
45 #undef FINCH_GET_DATA
46 #undef FINCH_SET_DATA
47 #define FINCH_GET_DATA(obj) purple_request_field_get_ui_data(obj)
48 #define FINCH_SET_DATA(obj, data) purple_request_field_set_ui_data(obj, data)
49
50 typedef struct
51 {
52 void *user_data;
53 GntWidget *dialog;
54 GCallback *cbs;
55 gboolean save;
56 } FinchFileRequest;
57
58 static GntWidget *
setup_request_window(const char * title,const char * primary,const char * secondary,PurpleRequestType type)59 setup_request_window(const char *title, const char *primary,
60 const char *secondary, PurpleRequestType type)
61 {
62 GntWidget *window;
63
64 window = gnt_vbox_new(FALSE);
65 gnt_box_set_toplevel(GNT_BOX(window), TRUE);
66 gnt_box_set_title(GNT_BOX(window), title);
67 gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
68
69 if (primary)
70 gnt_box_add_widget(GNT_BOX(window),
71 gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD));
72 if (secondary)
73 gnt_box_add_widget(GNT_BOX(window), gnt_label_new(secondary));
74
75 g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(purple_request_close),
76 GINT_TO_POINTER(type));
77
78 return window;
79 }
80
81 /**
82 * If the window is closed by the wm (ie, without triggering any of
83 * the buttons, then do some default callback.
84 */
85 static void
setup_default_callback(GntWidget * window,gpointer default_cb,gpointer data)86 setup_default_callback(GntWidget *window, gpointer default_cb, gpointer data)
87 {
88 if (default_cb == NULL)
89 return;
90 g_object_set_data(G_OBJECT(window), "default-callback", default_cb);
91 g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(default_cb), data);
92 }
93
94 static void
action_performed(GntWidget * button,gpointer data)95 action_performed(GntWidget *button, gpointer data)
96 {
97 g_signal_handlers_disconnect_matched(data, G_SIGNAL_MATCH_FUNC,
98 0, 0, NULL,
99 g_object_get_data(data, "default-callback"),
100 NULL);
101 }
102
103 /**
104 * window: this is the window
105 * userdata: the userdata to pass to the primary callbacks
106 * cb: the callback
107 * data: data for the callback
108 * (text, primary-callback) pairs, ended by a NULL
109 *
110 * The cancellation callback should be the last callback sent.
111 */
112 static GntWidget *
setup_button_box(GntWidget * win,gpointer userdata,gpointer cb,gpointer data,...)113 setup_button_box(GntWidget *win, gpointer userdata, gpointer cb, gpointer data, ...)
114 {
115 GntWidget *box;
116 GntWidget *button = NULL;
117 va_list list;
118 const char *text;
119 gpointer callback;
120
121 box = gnt_hbox_new(FALSE);
122
123 va_start(list, data);
124
125 while ((text = va_arg(list, const char *)))
126 {
127 callback = va_arg(list, gpointer);
128 button = gnt_button_new(text);
129 gnt_box_add_widget(GNT_BOX(box), button);
130 g_object_set_data(G_OBJECT(button), "activate-callback", callback);
131 g_object_set_data(G_OBJECT(button), "activate-userdata", userdata);
132 g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(action_performed), win);
133 g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(cb), data);
134 }
135
136 if (button)
137 g_object_set_data(G_OBJECT(button), "cancellation-function", GINT_TO_POINTER(TRUE));
138
139 va_end(list);
140 return box;
141 }
142
143 static void
notify_input_cb(GntWidget * button,GntWidget * entry)144 notify_input_cb(GntWidget *button, GntWidget *entry)
145 {
146 PurpleRequestInputCb callback = g_object_get_data(G_OBJECT(button), "activate-callback");
147 gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata");
148 const char *text = gnt_entry_get_text(GNT_ENTRY(entry));
149 GntWidget *window;
150
151 if (callback)
152 callback(data, text);
153
154 window = gnt_widget_get_toplevel(button);
155 purple_request_close(PURPLE_REQUEST_INPUT, window);
156 }
157
158 static void *
finch_request_input(const char * title,const char * primary,const char * secondary,const char * default_value,gboolean multiline,gboolean masked,gchar * hint,const char * ok_text,GCallback ok_cb,const char * cancel_text,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data)159 finch_request_input(const char *title, const char *primary,
160 const char *secondary, const char *default_value,
161 gboolean multiline, gboolean masked, gchar *hint,
162 const char *ok_text, GCallback ok_cb,
163 const char *cancel_text, GCallback cancel_cb,
164 PurpleAccount *account, const char *who, PurpleConversation *conv,
165 void *user_data)
166 {
167 GntWidget *window, *box, *entry;
168
169 window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_INPUT);
170
171 entry = gnt_entry_new(default_value);
172 if (masked)
173 gnt_entry_set_masked(GNT_ENTRY(entry), TRUE);
174 gnt_box_add_widget(GNT_BOX(window), entry);
175
176 box = setup_button_box(window, user_data, notify_input_cb, entry,
177 ok_text, ok_cb, cancel_text, cancel_cb, NULL);
178 gnt_box_add_widget(GNT_BOX(window), box);
179
180 setup_default_callback(window, cancel_cb, user_data);
181 gnt_widget_show(window);
182
183 return window;
184 }
185
186 static void
finch_close_request(PurpleRequestType type,gpointer ui_handle)187 finch_close_request(PurpleRequestType type, gpointer ui_handle)
188 {
189 GntWidget *widget = GNT_WIDGET(ui_handle);
190 if (type == PURPLE_REQUEST_FIELDS) {
191 PurpleRequestFields *fields = g_object_get_data(G_OBJECT(widget), "fields");
192 purple_request_fields_destroy(fields);
193 }
194
195 widget = gnt_widget_get_toplevel(widget);
196 gnt_widget_destroy(widget);
197 }
198
199 static void
request_choice_cb(GntWidget * button,GntComboBox * combo)200 request_choice_cb(GntWidget *button, GntComboBox *combo)
201 {
202 PurpleRequestChoiceCb callback = g_object_get_data(G_OBJECT(button), "activate-callback");
203 gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata");
204 int choice = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo))) - 1;
205 GntWidget *window;
206
207 if (callback)
208 callback(data, choice);
209
210 window = gnt_widget_get_toplevel(button);
211 purple_request_close(PURPLE_REQUEST_INPUT, window);
212 }
213
214 static void *
finch_request_choice(const char * title,const char * primary,const char * secondary,int default_value,const char * ok_text,GCallback ok_cb,const char * cancel_text,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data,va_list choices)215 finch_request_choice(const char *title, const char *primary,
216 const char *secondary, int default_value,
217 const char *ok_text, GCallback ok_cb,
218 const char *cancel_text, GCallback cancel_cb,
219 PurpleAccount *account, const char *who, PurpleConversation *conv,
220 void *user_data, va_list choices)
221 {
222 GntWidget *window, *combo, *box;
223 const char *text;
224 int val;
225
226 window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_CHOICE);
227
228 combo = gnt_combo_box_new();
229 gnt_box_add_widget(GNT_BOX(window), combo);
230 while ((text = va_arg(choices, const char *)))
231 {
232 val = va_arg(choices, int);
233 gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(val + 1), text);
234 }
235 gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), GINT_TO_POINTER(default_value + 1));
236
237 box = setup_button_box(window, user_data, request_choice_cb, combo,
238 ok_text, ok_cb, cancel_text, cancel_cb, NULL);
239 gnt_box_add_widget(GNT_BOX(window), box);
240
241 setup_default_callback(window, cancel_cb, user_data);
242 gnt_widget_show(window);
243
244 return window;
245 }
246
247 static void
request_action_cb(GntWidget * button,GntWidget * window)248 request_action_cb(GntWidget *button, GntWidget *window)
249 {
250 PurpleRequestActionCb callback = g_object_get_data(G_OBJECT(button), "activate-callback");
251 gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata");
252 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "activate-id"));
253
254 if (callback)
255 callback(data, id);
256
257 purple_request_close(PURPLE_REQUEST_ACTION, window);
258 }
259
260 static void*
finch_request_action(const char * title,const char * primary,const char * secondary,int default_value,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data,size_t actioncount,va_list actions)261 finch_request_action(const char *title, const char *primary,
262 const char *secondary, int default_value,
263 PurpleAccount *account, const char *who, PurpleConversation *conv,
264 void *user_data, size_t actioncount,
265 va_list actions)
266 {
267 GntWidget *window, *box, *button, *focus = NULL;
268 gsize i;
269
270 window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_ACTION);
271
272 box = gnt_hbox_new(FALSE);
273 gnt_box_add_widget(GNT_BOX(window), box);
274 for (i = 0; i < actioncount; i++)
275 {
276 const char *text = va_arg(actions, const char *);
277 PurpleRequestActionCb callback = va_arg(actions, PurpleRequestActionCb);
278
279 button = gnt_button_new(text);
280 gnt_box_add_widget(GNT_BOX(box), button);
281
282 g_object_set_data(G_OBJECT(button), "activate-callback", callback);
283 g_object_set_data(G_OBJECT(button), "activate-userdata", user_data);
284 g_object_set_data(G_OBJECT(button), "activate-id", GINT_TO_POINTER(i));
285 g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(request_action_cb), window);
286
287 if (default_value >= 0 && i == (gsize)default_value)
288 focus = button;
289 }
290
291 gnt_widget_show(window);
292 if (focus)
293 gnt_box_give_focus_to_child(GNT_BOX(window), focus);
294
295 return window;
296 }
297
298 static void
request_fields_cb(GntWidget * button,PurpleRequestFields * fields)299 request_fields_cb(GntWidget *button, PurpleRequestFields *fields)
300 {
301 PurpleRequestFieldsCb callback = g_object_get_data(G_OBJECT(button), "activate-callback");
302 gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata");
303 GList *list;
304 GntWidget *window;
305
306 /* Update the data of the fields. Pidgin does this differently. Instead of
307 * updating the fields at the end like here, it updates the appropriate field
308 * instantly whenever a change is made. That allows it to make sure the
309 * 'required' fields are entered before the user can hit OK. It's not the case
310 * here, althought it can be done. */
311 for (list = purple_request_fields_get_groups(fields); list; list = list->next)
312 {
313 PurpleRequestFieldGroup *group = list->data;
314 GList *fields = purple_request_field_group_get_fields(group);
315
316 for (; fields ; fields = fields->next)
317 {
318 PurpleRequestField *field = fields->data;
319 PurpleRequestFieldType type = purple_request_field_get_type(field);
320 if (!purple_request_field_is_visible(field))
321 continue;
322 if (type == PURPLE_REQUEST_FIELD_BOOLEAN)
323 {
324 GntWidget *check = FINCH_GET_DATA(field);
325 gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(check));
326 purple_request_field_bool_set_value(field, value);
327 }
328 else if (type == PURPLE_REQUEST_FIELD_STRING)
329 {
330 GntWidget *entry = FINCH_GET_DATA(field);
331 const char *text = gnt_entry_get_text(GNT_ENTRY(entry));
332 purple_request_field_string_set_value(field, (text && *text) ? text : NULL);
333 }
334 else if (type == PURPLE_REQUEST_FIELD_INTEGER)
335 {
336 GntWidget *entry = FINCH_GET_DATA(field);
337 const char *text = gnt_entry_get_text(GNT_ENTRY(entry));
338 int value = (text && *text) ? atoi(text) : 0;
339 purple_request_field_int_set_value(field, value);
340 }
341 else if (type == PURPLE_REQUEST_FIELD_CHOICE)
342 {
343 GntWidget *combo = FINCH_GET_DATA(field);
344 int id;
345 id = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)));
346 purple_request_field_choice_set_value(field, id);
347 }
348 else if (type == PURPLE_REQUEST_FIELD_LIST)
349 {
350 GList *list = NULL, *iter;
351 if (purple_request_field_list_get_multi_select(field))
352 {
353 GntWidget *tree = FINCH_GET_DATA(field);
354
355 iter = purple_request_field_list_get_items(field);
356 for (; iter; iter = iter->next)
357 {
358 const char *text = iter->data;
359 gpointer key = purple_request_field_list_get_data(field, text);
360 if (gnt_tree_get_choice(GNT_TREE(tree), key))
361 list = g_list_prepend(list, (gpointer)text);
362 }
363 }
364 else
365 {
366 GntWidget *combo = FINCH_GET_DATA(field);
367 gpointer data = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo));
368
369 iter = purple_request_field_list_get_items(field);
370 for (; iter; iter = iter->next) {
371 const char *text = iter->data;
372 gpointer key = purple_request_field_list_get_data(field, text);
373 if (key == data) {
374 list = g_list_prepend(list, (gpointer)text);
375 break;
376 }
377 }
378 }
379
380 purple_request_field_list_set_selected(field, list);
381 g_list_free(list);
382 }
383 else if (type == PURPLE_REQUEST_FIELD_ACCOUNT)
384 {
385 GntWidget *combo = FINCH_GET_DATA(field);
386 PurpleAccount *acc = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo));
387 purple_request_field_account_set_value(field, acc);
388 }
389 }
390 }
391
392 purple_notify_close_with_handle(button);
393
394 if (!g_object_get_data(G_OBJECT(button), "cancellation-function") &&
395 !purple_request_fields_all_required_filled(fields)) {
396 purple_notify_error(button, _("Error"),
397 _("You must fill all the required fields."),
398 _("The required fields are underlined."));
399 return;
400 }
401
402 if (callback)
403 callback(data, fields);
404
405 window = gnt_widget_get_toplevel(button);
406 purple_request_close(PURPLE_REQUEST_FIELDS, window);
407 }
408
409 static void
update_selected_account(GntEntry * username,const char * start,const char * end,GntComboBox * accountlist)410 update_selected_account(GntEntry *username, const char *start, const char *end,
411 GntComboBox *accountlist)
412 {
413 GList *accounts =
414 gnt_tree_get_rows(GNT_TREE(gnt_combo_box_get_dropdown(accountlist)));
415 const char *name = gnt_entry_get_text(username);
416 while (accounts) {
417 if (purple_find_buddy(accounts->data, name)) {
418 gnt_combo_box_set_selected(accountlist, accounts->data);
419 gnt_widget_draw(GNT_WIDGET(accountlist));
420 break;
421 }
422 accounts = accounts->next;
423 }
424 }
425
426 static GntWidget*
create_boolean_field(PurpleRequestField * field)427 create_boolean_field(PurpleRequestField *field)
428 {
429 const char *label = purple_request_field_get_label(field);
430 GntWidget *check = gnt_check_box_new(label);
431 gnt_check_box_set_checked(GNT_CHECK_BOX(check),
432 purple_request_field_bool_get_default_value(field));
433 return check;
434 }
435
436 static GntWidget*
create_string_field(PurpleRequestField * field,GntWidget ** username)437 create_string_field(PurpleRequestField *field, GntWidget **username)
438 {
439 const char *hint = purple_request_field_get_type_hint(field);
440 GntWidget *entry = gnt_entry_new(
441 purple_request_field_string_get_default_value(field));
442 gnt_entry_set_masked(GNT_ENTRY(entry),
443 purple_request_field_string_is_masked(field));
444 if (hint && purple_str_has_prefix(hint, "screenname")) {
445 PurpleBlistNode *node = purple_blist_get_root();
446 gboolean offline = purple_str_has_suffix(hint, "all");
447 for (; node; node = purple_blist_node_next(node, offline)) {
448 if (!PURPLE_BLIST_NODE_IS_BUDDY(node))
449 continue;
450 gnt_entry_add_suggest(GNT_ENTRY(entry), purple_buddy_get_name((PurpleBuddy*)node));
451 }
452 gnt_entry_set_always_suggest(GNT_ENTRY(entry), TRUE);
453 if (username)
454 *username = entry;
455 } else if (purple_strequal(hint, "group")) {
456 PurpleBlistNode *node;
457 for (node = purple_blist_get_root(); node;
458 node = purple_blist_node_get_sibling_next(node)) {
459 if (PURPLE_BLIST_NODE_IS_GROUP(node))
460 gnt_entry_add_suggest(GNT_ENTRY(entry), purple_group_get_name((PurpleGroup *)node));
461 }
462 }
463 return entry;
464 }
465
466 static GntWidget*
create_integer_field(PurpleRequestField * field)467 create_integer_field(PurpleRequestField *field)
468 {
469 char str[256];
470 int val = purple_request_field_int_get_default_value(field);
471 GntWidget *entry;
472
473 snprintf(str, sizeof(str), "%d", val);
474 entry = gnt_entry_new(str);
475 gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT);
476 return entry;
477 }
478
479 static GntWidget*
create_choice_field(PurpleRequestField * field)480 create_choice_field(PurpleRequestField *field)
481 {
482 int id;
483 GList *list;
484 GntWidget *combo = gnt_combo_box_new();
485
486 list = purple_request_field_choice_get_labels(field);
487 for (id = 1; list; list = list->next, id++)
488 {
489 gnt_combo_box_add_data(GNT_COMBO_BOX(combo),
490 GINT_TO_POINTER(id), list->data);
491 }
492 gnt_combo_box_set_selected(GNT_COMBO_BOX(combo),
493 GINT_TO_POINTER(purple_request_field_choice_get_default_value(field)));
494 return combo;
495 }
496
497 static GntWidget*
create_list_field(PurpleRequestField * field)498 create_list_field(PurpleRequestField *field)
499 {
500 GntWidget *ret = NULL;
501 GList *list;
502 gboolean multi = purple_request_field_list_get_multi_select(field);
503 if (multi)
504 {
505 GntWidget *tree = gnt_tree_new();
506
507 list = purple_request_field_list_get_items(field);
508 for (; list; list = list->next)
509 {
510 const char *text = list->data;
511 gpointer key = purple_request_field_list_get_data(field, text);
512 gnt_tree_add_choice(GNT_TREE(tree), key,
513 gnt_tree_create_row(GNT_TREE(tree), text), NULL, NULL);
514 if (purple_request_field_list_is_selected(field, text))
515 gnt_tree_set_choice(GNT_TREE(tree), key, TRUE);
516 }
517 ret = tree;
518 }
519 else
520 {
521 GntWidget *combo = gnt_combo_box_new();
522
523 list = purple_request_field_list_get_items(field);
524 for (; list; list = list->next)
525 {
526 const char *text = list->data;
527 gpointer key = purple_request_field_list_get_data(field, text);
528 gnt_combo_box_add_data(GNT_COMBO_BOX(combo), key, text);
529 if (purple_request_field_list_is_selected(field, text))
530 gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), key);
531 }
532 ret = combo;
533 }
534 return ret;
535 }
536
537 static GntWidget*
create_account_field(PurpleRequestField * field)538 create_account_field(PurpleRequestField *field)
539 {
540 gboolean all;
541 PurpleAccount *def;
542 GList *list;
543 GntWidget *combo = gnt_combo_box_new();
544
545 all = purple_request_field_account_get_show_all(field);
546 def = purple_request_field_account_get_value(field);
547 if (!def)
548 def = purple_request_field_account_get_default_value(field);
549
550 if (all)
551 list = purple_accounts_get_all();
552 else
553 list = purple_connections_get_all();
554
555 for (; list; list = list->next)
556 {
557 PurpleAccount *account;
558 char *text;
559
560 if (all)
561 account = list->data;
562 else
563 account = purple_connection_get_account(list->data);
564
565 text = g_strdup_printf("%s (%s)",
566 purple_account_get_username(account),
567 purple_account_get_protocol_name(account));
568 gnt_combo_box_add_data(GNT_COMBO_BOX(combo), account, text);
569 g_free(text);
570 if (account == def)
571 gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), account);
572 }
573 gnt_widget_set_size(combo, 20, 3); /* ew */
574 return combo;
575 }
576
577 static void *
finch_request_fields(const char * title,const char * primary,const char * secondary,PurpleRequestFields * allfields,const char * ok,GCallback ok_cb,const char * cancel,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * userdata)578 finch_request_fields(const char *title, const char *primary,
579 const char *secondary, PurpleRequestFields *allfields,
580 const char *ok, GCallback ok_cb,
581 const char *cancel, GCallback cancel_cb,
582 PurpleAccount *account, const char *who, PurpleConversation *conv,
583 void *userdata)
584 {
585 GntWidget *window, *box;
586 GList *grlist;
587 GntWidget *username = NULL, *accountlist = NULL;
588
589 window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_FIELDS);
590
591 /* This is how it's going to work: the request-groups are going to be
592 * stacked vertically one after the other. A GntLine will be separating
593 * the groups. */
594 box = gnt_vbox_new(FALSE);
595 gnt_box_set_pad(GNT_BOX(box), 0);
596 gnt_box_set_fill(GNT_BOX(box), TRUE);
597 for (grlist = purple_request_fields_get_groups(allfields); grlist; grlist = grlist->next)
598 {
599 PurpleRequestFieldGroup *group = grlist->data;
600 GList *fields = purple_request_field_group_get_fields(group);
601 GntWidget *hbox;
602 const char *title = purple_request_field_group_get_title(group);
603
604 if (title)
605 gnt_box_add_widget(GNT_BOX(box),
606 gnt_label_new_with_format(title, GNT_TEXT_FLAG_BOLD));
607
608 for (; fields ; fields = fields->next)
609 {
610 PurpleRequestField *field = fields->data;
611 PurpleRequestFieldType type = purple_request_field_get_type(field);
612 const char *label = purple_request_field_get_label(field);
613
614 if (!purple_request_field_is_visible(field))
615 continue;
616
617 hbox = gnt_hbox_new(TRUE); /* hrm */
618 gnt_box_add_widget(GNT_BOX(box), hbox);
619
620 if (type != PURPLE_REQUEST_FIELD_BOOLEAN && label)
621 {
622 GntWidget *l;
623 if (purple_request_field_is_required(field))
624 l = gnt_label_new_with_format(label, GNT_TEXT_FLAG_UNDERLINE);
625 else
626 l = gnt_label_new(label);
627 gnt_widget_set_size(l, 0, 1);
628 gnt_box_add_widget(GNT_BOX(hbox), l);
629 }
630
631 if (type == PURPLE_REQUEST_FIELD_BOOLEAN)
632 {
633 FINCH_SET_DATA(field, create_boolean_field(field));
634 }
635 else if (type == PURPLE_REQUEST_FIELD_STRING)
636 {
637 FINCH_SET_DATA(field, create_string_field(field, &username));
638 }
639 else if (type == PURPLE_REQUEST_FIELD_INTEGER)
640 {
641 FINCH_SET_DATA(field, create_integer_field(field));
642 }
643 else if (type == PURPLE_REQUEST_FIELD_CHOICE)
644 {
645 FINCH_SET_DATA(field, create_choice_field(field));
646 }
647 else if (type == PURPLE_REQUEST_FIELD_LIST)
648 {
649 FINCH_SET_DATA(field, create_list_field(field));
650 }
651 else if (type == PURPLE_REQUEST_FIELD_ACCOUNT)
652 {
653 accountlist = create_account_field(field);
654 FINCH_SET_DATA(field, accountlist);
655 }
656 else
657 {
658 FINCH_SET_DATA(field, gnt_label_new_with_format(_("Not implemented yet."),
659 GNT_TEXT_FLAG_BOLD));
660 }
661 gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
662 gnt_box_add_widget(GNT_BOX(hbox), GNT_WIDGET(FINCH_GET_DATA(field)));
663 }
664 if (grlist->next)
665 gnt_box_add_widget(GNT_BOX(box), gnt_hline_new());
666 }
667 gnt_box_add_widget(GNT_BOX(window), box);
668
669 box = setup_button_box(window, userdata, request_fields_cb, allfields,
670 ok, ok_cb, cancel, cancel_cb, NULL);
671 gnt_box_add_widget(GNT_BOX(window), box);
672
673 setup_default_callback(window, cancel_cb, userdata);
674 gnt_widget_show(window);
675
676 if (username && accountlist) {
677 g_signal_connect(username, "completion", G_CALLBACK(update_selected_account), accountlist);
678 }
679
680 g_object_set_data(G_OBJECT(window), "fields", allfields);
681
682 return window;
683 }
684
685 static void
file_cancel_cb(GntWidget * wid,gpointer fq)686 file_cancel_cb(GntWidget *wid, gpointer fq)
687 {
688 FinchFileRequest *data = fq;
689 if (data->dialog == NULL) {
690 /* We've already handled this request, and are in the destroy handler. */
691 return;
692 }
693
694 if (data->cbs[1] != NULL)
695 ((PurpleRequestFileCb)data->cbs[1])(data->user_data, NULL);
696
697 purple_request_close(PURPLE_REQUEST_FILE, data->dialog);
698 data->dialog = NULL;
699 }
700
701 static void
file_ok_cb(GntWidget * widget,const char * path,const char * file,gpointer fq)702 file_ok_cb(GntWidget *widget, const char *path, const char *file, gpointer fq)
703 {
704 FinchFileRequest *data = fq;
705 char *dir = g_path_get_dirname(path);
706 if (data->cbs[0] != NULL)
707 ((PurpleRequestFileCb)data->cbs[0])(data->user_data, file);
708 purple_prefs_set_path(data->save ? "/finch/filelocations/last_save_folder" :
709 "/finch/filelocations/last_open_folder", dir);
710 g_free(dir);
711
712 purple_request_close(PURPLE_REQUEST_FILE, data->dialog);
713 data->dialog = NULL;
714 }
715
716 static void
file_request_destroy(FinchFileRequest * data)717 file_request_destroy(FinchFileRequest *data)
718 {
719 g_free(data->cbs);
720 g_free(data);
721 }
722
723 static FinchFileRequest *
finch_file_request_window(const char * title,const char * path,GCallback ok_cb,GCallback cancel_cb,void * user_data)724 finch_file_request_window(const char *title, const char *path,
725 GCallback ok_cb, GCallback cancel_cb,
726 void *user_data)
727 {
728 GntWidget *window = gnt_file_sel_new();
729 GntFileSel *sel = GNT_FILE_SEL(window);
730 FinchFileRequest *data = g_new0(FinchFileRequest, 1);
731
732 data->user_data = user_data;
733 data->cbs = g_new0(GCallback, 2);
734 data->cbs[0] = ok_cb;
735 data->cbs[1] = cancel_cb;
736 data->dialog = window;
737 gnt_box_set_title(GNT_BOX(window), title);
738
739 gnt_file_sel_set_current_location(sel, (path && *path) ? path : purple_home_dir());
740
741 g_signal_connect(G_OBJECT(sel), "destroy",
742 G_CALLBACK(file_cancel_cb), data);
743 g_signal_connect(G_OBJECT(sel), "cancelled",
744 G_CALLBACK(file_cancel_cb), data);
745 g_signal_connect(G_OBJECT(sel), "file_selected",
746 G_CALLBACK(file_ok_cb), data);
747
748 g_object_set_data_full(G_OBJECT(window), "filerequestdata", data,
749 (GDestroyNotify)file_request_destroy);
750
751 return data;
752 }
753
754 static void *
finch_request_file(const char * title,const char * filename,gboolean savedialog,GCallback ok_cb,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data)755 finch_request_file(const char *title, const char *filename,
756 gboolean savedialog,
757 GCallback ok_cb, GCallback cancel_cb,
758 PurpleAccount *account, const char *who, PurpleConversation *conv,
759 void *user_data)
760 {
761 FinchFileRequest *data;
762 const char *path;
763
764 path = purple_prefs_get_path(savedialog ? "/finch/filelocations/last_save_folder" : "/finch/filelocations/last_open_folder");
765 data = finch_file_request_window(title ? title : (savedialog ? _("Save File...") : _("Open File...")), path,
766 ok_cb, cancel_cb, user_data);
767 data->save = savedialog;
768 if (savedialog)
769 gnt_file_sel_set_suggested_filename(GNT_FILE_SEL(data->dialog), filename);
770
771 gnt_widget_show(data->dialog);
772 return data->dialog;
773 }
774
775 static void *
finch_request_folder(const char * title,const char * dirname,GCallback ok_cb,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data)776 finch_request_folder(const char *title, const char *dirname, GCallback ok_cb,
777 GCallback cancel_cb, PurpleAccount *account, const char *who, PurpleConversation *conv,
778 void *user_data)
779 {
780 FinchFileRequest *data;
781
782 data = finch_file_request_window(title ? title : _("Choose Location..."), dirname,
783 ok_cb, cancel_cb, user_data);
784 data->save = TRUE;
785 gnt_file_sel_set_dirs_only(GNT_FILE_SEL(data->dialog), TRUE);
786
787 gnt_widget_show(data->dialog);
788 return data->dialog;
789 }
790
791 static PurpleRequestUiOps uiops =
792 {
793 finch_request_input,
794 finch_request_choice,
795 finch_request_action,
796 finch_request_fields,
797 finch_request_file,
798 finch_close_request,
799 finch_request_folder,
800 NULL,
801 NULL,
802 NULL,
803 NULL
804 };
805
finch_request_get_ui_ops()806 PurpleRequestUiOps *finch_request_get_ui_ops()
807 {
808 return &uiops;
809 }
810
finch_request_init()811 void finch_request_init()
812 {
813 }
814
finch_request_uninit()815 void finch_request_uninit()
816 {
817 }
818
finch_request_save_in_prefs(gpointer null,PurpleRequestFields * allfields)819 void finch_request_save_in_prefs(gpointer null, PurpleRequestFields *allfields)
820 {
821 GList *list;
822 for (list = purple_request_fields_get_groups(allfields); list; list = list->next) {
823 PurpleRequestFieldGroup *group = list->data;
824 GList *fields = purple_request_field_group_get_fields(group);
825
826 for (; fields ; fields = fields->next) {
827 PurpleRequestField *field = fields->data;
828 PurpleRequestFieldType type = purple_request_field_get_type(field);
829 PurplePrefType pt;
830 gpointer val = NULL;
831 const char *id = purple_request_field_get_id(field);
832
833 switch (type) {
834 case PURPLE_REQUEST_FIELD_LIST:
835 val = purple_request_field_list_get_selected(field)->data;
836 val = purple_request_field_list_get_data(field, val);
837 break;
838 case PURPLE_REQUEST_FIELD_BOOLEAN:
839 val = GINT_TO_POINTER(purple_request_field_bool_get_value(field));
840 break;
841 case PURPLE_REQUEST_FIELD_INTEGER:
842 val = GINT_TO_POINTER(purple_request_field_int_get_value(field));
843 break;
844 case PURPLE_REQUEST_FIELD_STRING:
845 val = (gpointer)purple_request_field_string_get_value(field);
846 break;
847 default:
848 break;
849 }
850
851 pt = purple_prefs_get_type(id);
852 switch (pt) {
853 case PURPLE_PREF_INT:
854 {
855 long int tmp = GPOINTER_TO_INT(val);
856 if (type == PURPLE_REQUEST_FIELD_LIST) {
857 /* Lists always return string */
858 if (sscanf(val, "%ld", &tmp) != 1)
859 tmp = 0;
860 }
861 purple_prefs_set_int(id, (gint)tmp);
862 break;
863 }
864 case PURPLE_PREF_BOOLEAN:
865 purple_prefs_set_bool(id, GPOINTER_TO_INT(val));
866 break;
867 case PURPLE_PREF_STRING:
868 purple_prefs_set_string(id, val);
869 break;
870 default:
871 break;
872 }
873 }
874 }
875 }
876
finch_request_field_get_widget(PurpleRequestField * field)877 GntWidget *finch_request_field_get_widget(PurpleRequestField *field)
878 {
879 GntWidget *ret = NULL;
880 switch (purple_request_field_get_type(field)) {
881 case PURPLE_REQUEST_FIELD_BOOLEAN:
882 ret = create_boolean_field(field);
883 break;
884 case PURPLE_REQUEST_FIELD_STRING:
885 ret = create_string_field(field, NULL);
886 break;
887 case PURPLE_REQUEST_FIELD_INTEGER:
888 ret = create_integer_field(field);
889 break;
890 case PURPLE_REQUEST_FIELD_CHOICE:
891 ret = create_choice_field(field);
892 break;
893 case PURPLE_REQUEST_FIELD_LIST:
894 ret = create_list_field(field);
895 break;
896 case PURPLE_REQUEST_FIELD_ACCOUNT:
897 ret = create_account_field(field);
898 break;
899 default:
900 purple_debug_error("GntRequest", "Unimplemented request-field %d\n", purple_request_field_get_type(field));
901 break;
902 }
903 return ret;
904 }
905
906