finch/gntrequest.c

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

mercurial