/* * finch * * Finch is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include #include #include #include "gntrequest.h" typedef struct { void *user_data; GntWidget *dialog; GCallback *cbs; gboolean save; } FinchFileRequest; static GntWidget * setup_request_window(const char *title, const char *primary, const char *secondary, PurpleRequestType type) { GntWidget *window; window = gnt_vbox_new(FALSE); gnt_box_set_toplevel(GNT_BOX(window), TRUE); gnt_box_set_title(GNT_BOX(window), title); gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); if (primary) gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD)); if (secondary) gnt_box_add_widget(GNT_BOX(window), gnt_label_new(secondary)); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(purple_request_close), GINT_TO_POINTER(type)); return window; } /* * If the window is closed by the wm (ie, without triggering any of * the buttons, then do some default callback. */ static void setup_default_callback(GntWidget *window, gpointer default_cb, gpointer data) { if (default_cb == NULL) return; g_object_set_data(G_OBJECT(window), "default-callback", default_cb); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(default_cb), data); } static void action_performed(G_GNUC_UNUSED GntWidget *button, gpointer data) { g_signal_handlers_disconnect_matched(data, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, g_object_get_data(data, "default-callback"), NULL); } /* * setup_button_box: * @win: this is the window * @userdata: the userdata to pass to the primary callbacks * @cb: the callback * @data: data for the callback * @...: (text, primary-callback) pairs, ended by a NULL * * The cancellation callback should be the last callback sent. */ static GntWidget * setup_button_box(GntWidget *win, gpointer userdata, gpointer cb, gpointer data, ...) { GntWidget *box; GntWidget *button = NULL; va_list list; const char *text; gpointer callback; box = gnt_hbox_new(FALSE); va_start(list, data); while ((text = va_arg(list, const char *))) { callback = va_arg(list, gpointer); button = gnt_button_new(text); gnt_box_add_widget(GNT_BOX(box), button); g_object_set_data(G_OBJECT(button), "activate-callback", callback); g_object_set_data(G_OBJECT(button), "activate-userdata", userdata); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(action_performed), win); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(cb), data); } if (button) g_object_set_data(G_OBJECT(button), "cancellation-function", GINT_TO_POINTER(TRUE)); va_end(list); return box; } static void notify_input_cb(GntWidget *button, GntWidget *entry) { PurpleRequestInputCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); GntWidget *window; if (callback) callback(data, text); window = gnt_widget_get_toplevel(button); purple_request_close(PURPLE_REQUEST_INPUT, window); } static void * finch_request_input(const char *title, const char *primary, const char *secondary, const char *default_value, G_GNUC_UNUSED gboolean multiline, gboolean masked, G_GNUC_UNUSED gchar *hint, const char *ok_text, GCallback ok_cb, const char *cancel_text, GCallback cancel_cb, G_GNUC_UNUSED PurpleRequestCommonParameters *cpar, void *user_data) { GntWidget *window, *box, *entry; window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_INPUT); entry = gnt_entry_new(default_value); if (masked) gnt_entry_set_masked(GNT_ENTRY(entry), TRUE); gnt_box_add_widget(GNT_BOX(window), entry); box = setup_button_box(window, user_data, notify_input_cb, entry, ok_text, ok_cb, cancel_text, cancel_cb, NULL); gnt_box_add_widget(GNT_BOX(window), box); setup_default_callback(window, cancel_cb, user_data); gnt_widget_show(window); return window; } static void finch_close_request(G_GNUC_UNUSED PurpleRequestType type, gpointer ui_handle) { GntWidget *widget = GNT_WIDGET(ui_handle); widget = gnt_widget_get_toplevel(widget); gnt_widget_destroy(widget); } static void request_choice_cb(GntWidget *button, GntComboBox *combo) { PurpleRequestChoiceCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); gpointer choice = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)); GntWidget *window; if (callback) callback(data, choice); window = gnt_widget_get_toplevel(button); purple_request_close(PURPLE_REQUEST_INPUT, window); } static void * finch_request_choice(const char *title, const char *primary, const char *secondary, gpointer default_value, const char *ok_text, GCallback ok_cb, const char *cancel_text, GCallback cancel_cb, G_GNUC_UNUSED PurpleRequestCommonParameters *cpar, void *user_data, va_list choices) { GntWidget *window, *combo, *box; const char *text; int val; window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_CHOICE); combo = gnt_combo_box_new(); gnt_box_add_widget(GNT_BOX(window), combo); while ((text = va_arg(choices, const char *))) { val = va_arg(choices, int); gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(val + 1), text); } gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), default_value); box = setup_button_box(window, user_data, request_choice_cb, combo, ok_text, ok_cb, cancel_text, cancel_cb, NULL); gnt_box_add_widget(GNT_BOX(window), box); setup_default_callback(window, cancel_cb, user_data); gnt_widget_show(window); return window; } static void request_action_cb(GntWidget *button, GntWidget *window) { PurpleRequestActionCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "activate-id")); if (callback) callback(data, id); purple_request_close(PURPLE_REQUEST_ACTION, window); } static void* finch_request_action(const char *title, const char *primary, const char *secondary, int default_value, G_GNUC_UNUSED PurpleRequestCommonParameters *cpar, void *user_data, size_t actioncount, va_list actions) { GntWidget *window, *box, *button, *focus = NULL; gsize i; window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_ACTION); box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(window), box); for (i = 0; i < actioncount; i++) { const char *text = va_arg(actions, const char *); PurpleRequestActionCb callback = va_arg(actions, PurpleRequestActionCb); button = gnt_button_new(text); gnt_box_add_widget(GNT_BOX(box), button); g_object_set_data(G_OBJECT(button), "activate-callback", callback); g_object_set_data(G_OBJECT(button), "activate-userdata", user_data); g_object_set_data(G_OBJECT(button), "activate-id", GINT_TO_POINTER(i)); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(request_action_cb), window); if (default_value >= 0 && i == (gsize)default_value) focus = button; } gnt_widget_show(window); if (focus) gnt_box_give_focus_to_child(GNT_BOX(window), focus); return window; } static void request_fields_cb(GntWidget *button, PurpleRequestPage *page) { PurpleRequestFieldsCb callback = g_object_get_data(G_OBJECT(button), "activate-callback"); gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata"); GntWidget *window; guint n_groups; /* Update the data of the fields. Pidgin does this differently. Instead of * updating the fields at the end like here, it updates the appropriate field * instantly whenever a change is made. That allows it to make sure the * 'required' fields are entered before the user can hit OK. It's not the case * here, although it can be done. */ n_groups = g_list_model_get_n_items(G_LIST_MODEL(page)); for(guint group_index = 0; group_index < n_groups; group_index++) { GListModel *group = NULL; guint n_fields; group = g_list_model_get_item(G_LIST_MODEL(page), group_index); n_fields = g_list_model_get_n_items(group); for(guint field_index = 0; field_index < n_fields; field_index++) { PurpleRequestField *field = NULL; field = g_list_model_get_item(group, field_index); if(!purple_request_field_is_visible(field)) { g_object_unref(field); continue; } if(PURPLE_IS_REQUEST_FIELD_BOOL(field)) { GntWidget *check = g_object_get_data(G_OBJECT(field), "finch-ui-data"); gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(check)); purple_request_field_bool_set_value(PURPLE_REQUEST_FIELD_BOOL(field), value); } else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) { GntWidget *entry = g_object_get_data(G_OBJECT(field), "finch-ui-data"); const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); if(purple_strempty(text)) { text = NULL; } purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field), text); } else if(PURPLE_IS_REQUEST_FIELD_INT(field)) { GntWidget *entry = g_object_get_data(G_OBJECT(field), "finch-ui-data"); const char *text = gnt_entry_get_text(GNT_ENTRY(entry)); int value = (text && *text) ? atoi(text) : 0; purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field), value); } else if(PURPLE_IS_REQUEST_FIELD_CHOICE(field)) { GntWidget *combo = g_object_get_data(G_OBJECT(field), "finch-ui-data"); gpointer value = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)); purple_request_field_choice_set_value(PURPLE_REQUEST_FIELD_CHOICE(field), value); } else if(PURPLE_IS_REQUEST_FIELD_LIST(field)) { PurpleRequestFieldList *lfield = PURPLE_REQUEST_FIELD_LIST(field); GList *selected = NULL; GList *list = purple_request_field_list_get_items(lfield); if(purple_request_field_list_get_multi_select(lfield)) { GntWidget *tree = g_object_get_data(G_OBJECT(field), "finch-ui-data"); for (; list; list = list->next) { PurpleKeyValuePair *item = list->data; const char *text = item->key; gpointer key = NULL; key = purple_request_field_list_get_data(lfield, text); if (gnt_tree_get_choice(GNT_TREE(tree), key)) { selected = g_list_prepend(selected, (gpointer)text); } } } else { GntWidget *combo = g_object_get_data(G_OBJECT(field), "finch-ui-data"); gpointer data = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)); for (; list; list = list->next) { PurpleKeyValuePair *item = list->data; const char *text = item->key; gpointer key = NULL; key = purple_request_field_list_get_data(lfield, text); if (key == data) { selected = g_list_prepend(selected, (gpointer)text); break; } } } purple_request_field_list_set_selected(lfield, selected); g_list_free(selected); } else if (PURPLE_IS_REQUEST_FIELD_ACCOUNT(field)) { GntWidget *combo = NULL; PurpleAccount *acc = NULL; PurpleRequestFieldAccount *afield = NULL; combo = g_object_get_data(G_OBJECT(field), "finch-ui-data"); acc = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo)); afield = PURPLE_REQUEST_FIELD_ACCOUNT(field); purple_request_field_account_set_value(afield, acc); } g_object_unref(field); } g_object_unref(group); } purple_notify_close_with_handle(button); if(!g_object_get_data(G_OBJECT(button), "cancellation-function") && !purple_request_page_is_valid(page)) { purple_notify_error(button, _("Error"), _("You must properly fill all the required fields."), _("The required fields are underlined."), NULL); return; } if(callback) { callback(data, page); } window = gnt_widget_get_toplevel(button); purple_request_close(PURPLE_REQUEST_FIELDS, window); } static void update_selected_account(GntEntry *username, G_GNUC_UNUSED const char *start, G_GNUC_UNUSED const char *end, GntComboBox *accountlist) { GList *accounts = gnt_tree_get_rows(GNT_TREE(gnt_combo_box_get_dropdown(accountlist))); const char *name = gnt_entry_get_text(username); while (accounts) { if (purple_blist_find_buddy(accounts->data, name)) { gnt_combo_box_set_selected(accountlist, accounts->data); gnt_widget_draw(GNT_WIDGET(accountlist)); break; } accounts = accounts->next; } } static GntWidget* create_boolean_field(PurpleRequestField *field) { PurpleRequestFieldBool *boolfield = PURPLE_REQUEST_FIELD_BOOL(field); const char *label = purple_request_field_get_label(field); GntWidget *check = gnt_check_box_new(label); gnt_check_box_set_checked(GNT_CHECK_BOX(check), purple_request_field_bool_get_default_value(boolfield)); return check; } static GntWidget* create_string_field(PurpleRequestField *field, GntWidget **username) { PurpleRequestFieldString *strfield = PURPLE_REQUEST_FIELD_STRING(field); const char *hint = purple_request_field_get_type_hint(field); GntWidget *entry = gnt_entry_new( purple_request_field_string_get_default_value(strfield)); gnt_entry_set_masked(GNT_ENTRY(entry), purple_request_field_string_is_masked(strfield)); if (hint && g_str_has_prefix(hint, "screenname")) { PurpleBlistNode *node = purple_blist_get_default_root(); gboolean offline = g_str_has_suffix(hint, "all"); for (; node; node = purple_blist_node_next(node, offline)) { if (!PURPLE_IS_BUDDY(node)) continue; gnt_entry_add_suggest(GNT_ENTRY(entry), purple_buddy_get_name((PurpleBuddy*)node)); } gnt_entry_set_always_suggest(GNT_ENTRY(entry), TRUE); if (username) *username = entry; } else if (purple_strequal(hint, "group")) { PurpleBlistNode *node; for (node = purple_blist_get_default_root(); node; node = purple_blist_node_get_sibling_next(node)) { if (PURPLE_IS_GROUP(node)) gnt_entry_add_suggest(GNT_ENTRY(entry), purple_group_get_name((PurpleGroup *)node)); } } return entry; } static GntWidget* create_integer_field(PurpleRequestField *field) { PurpleRequestFieldInt *intfield = PURPLE_REQUEST_FIELD_INT(field); char str[256]; int val = purple_request_field_int_get_default_value(intfield); GntWidget *entry; g_snprintf(str, sizeof(str), "%d", val); entry = gnt_entry_new(str); gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT); return entry; } static GntWidget* create_choice_field(PurpleRequestField *field) { PurpleRequestFieldChoice *cfield = PURPLE_REQUEST_FIELD_CHOICE(field); GntWidget *combo = gnt_combo_box_new(); for(GList *it = purple_request_field_choice_get_elements(cfield); it != NULL; it = g_list_next(it)) { PurpleKeyValuePair *choice = it->data; gnt_combo_box_add_data(GNT_COMBO_BOX(combo), choice->value, choice->key); } gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), purple_request_field_choice_get_default_value(cfield)); return combo; } static GntWidget* create_list_field(PurpleRequestField *field) { PurpleRequestFieldList *lfield = PURPLE_REQUEST_FIELD_LIST(field); GntWidget *ret = NULL; GList *list = purple_request_field_list_get_items(lfield); if(purple_request_field_list_get_multi_select(lfield)) { GntWidget *tree = gnt_tree_new(); for (; list; list = list->next) { PurpleKeyValuePair *item = list->data; const char *text = item->key; gpointer key = purple_request_field_list_get_data(lfield, text); gnt_tree_add_choice(GNT_TREE(tree), key, gnt_tree_create_row(GNT_TREE(tree), text), NULL, NULL); if(purple_request_field_list_is_selected(lfield, text)) { gnt_tree_set_choice(GNT_TREE(tree), key, TRUE); } } ret = tree; } else { GntWidget *combo = gnt_combo_box_new(); for (; list; list = list->next) { PurpleKeyValuePair *item = list->data; const char *text = item->key; gpointer key = purple_request_field_list_get_data(lfield, text); gnt_combo_box_add_data(GNT_COMBO_BOX(combo), key, text); if(purple_request_field_list_is_selected(lfield, text)) { gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), key); } } ret = combo; } return ret; } static void add_account_to_combo(GntWidget *combo, PurpleAccount *account) { PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); char *text = NULL; text = g_strdup_printf("%s (%s)", purple_contact_info_get_username(info), purple_account_get_protocol_name(account)); gnt_combo_box_add_data(GNT_COMBO_BOX(combo), account, text); g_free(text); } static GntWidget* create_account_field(PurpleRequestField *field) { PurpleRequestFieldAccount *afield = PURPLE_REQUEST_FIELD_ACCOUNT(field); gboolean all; PurpleAccount *def; GntWidget *combo = gnt_combo_box_new(); all = purple_request_field_account_get_show_all(afield); def = purple_request_field_account_get_value(afield); if(!PURPLE_IS_ACCOUNT(def)) { def = purple_request_field_account_get_default_value(afield); } if(all) { GListModel *manager_model = NULL; guint n_items = 0; manager_model = purple_account_manager_get_default_as_model(); n_items = g_list_model_get_n_items(manager_model); for(guint index = 0; index < n_items; index++) { PurpleAccount *account; account = g_list_model_get_item(manager_model, index); add_account_to_combo(combo, account); if(account == def) { gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), account); } g_object_unref(account); } } else { GList *list = purple_connections_get_all(); for(; list; list = list->next) { PurpleAccount *account = NULL; account = purple_connection_get_account(list->data); add_account_to_combo(combo, account); if(account == def) { gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), account); } } } gnt_widget_set_size(combo, 20, 3); /* ew */ return combo; } static void multifield_extra_cb(GntWidget *button, PurpleRequestPage *page) { PurpleRequestFieldsCb cb; gpointer cb_data; gpointer handle; handle = g_object_get_data(G_OBJECT(button), "ui-handle"); cb = g_object_get_data(G_OBJECT(button), "extra-cb"); cb_data = g_object_get_data(G_OBJECT(button), "extra-cb-data"); if(cb != NULL) { cb(cb_data, page); } action_performed(button, handle); purple_request_close(PURPLE_REQUEST_FIELDS, handle); } static void * finch_request_fields(const char *title, const char *primary, const char *secondary, PurpleRequestPage *page, const char *ok, GCallback ok_cb, const char *cancel, GCallback cancel_cb, PurpleRequestCommonParameters *cpar, void *userdata) { GntWidget *window, *box; GntWidget *username = NULL, *accountlist = NULL; PurpleRequestHelpCb help_cb; gpointer help_data; GSList *extra_actions; guint n_groups; window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_FIELDS); /* This is how it's going to work: the request-groups are going to be * stacked vertically one after the other. A GntLine will be separating * the groups. */ box = gnt_vbox_new(FALSE); gnt_box_set_pad(GNT_BOX(box), 0); gnt_box_set_fill(GNT_BOX(box), TRUE); n_groups = g_list_model_get_n_items(G_LIST_MODEL(page)); for(guint group_index = 0; group_index < n_groups; group_index++) { PurpleRequestGroup *group = NULL; GntWidget *hbox; const char *title = NULL; guint n_fields; group = g_list_model_get_item(G_LIST_MODEL(page), group_index); title = purple_request_group_get_title(group); if (title) gnt_box_add_widget(GNT_BOX(box), gnt_label_new_with_format(title, GNT_TEXT_FLAG_BOLD)); n_fields = g_list_model_get_n_items(G_LIST_MODEL(group)); for(guint field_index = 0; field_index < n_fields; field_index++) { PurpleRequestField *field = NULL; const char *label = NULL; GntWidget *widget = NULL; field = g_list_model_get_item(G_LIST_MODEL(group), field_index); label = purple_request_field_get_label(field); if(!purple_request_field_is_visible(field)) { g_object_unref(field); continue; } hbox = gnt_hbox_new(TRUE); /* hrm */ gnt_box_add_widget(GNT_BOX(box), hbox); if(!PURPLE_IS_REQUEST_FIELD_BOOL(field) && label) { GntWidget *l; if (purple_request_field_is_required(field)) l = gnt_label_new_with_format(label, GNT_TEXT_FLAG_UNDERLINE); else l = gnt_label_new(label); gnt_widget_set_size(l, 0, 1); gnt_box_add_widget(GNT_BOX(hbox), l); } if(PURPLE_IS_REQUEST_FIELD_BOOL(field)) { widget = create_boolean_field(field); } else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) { widget = create_string_field(field, &username); } else if(PURPLE_IS_REQUEST_FIELD_INT(field)) { widget = create_integer_field(field); } else if(PURPLE_IS_REQUEST_FIELD_CHOICE(field)) { widget = create_choice_field(field); } else if(PURPLE_IS_REQUEST_FIELD_LIST(field)) { widget = create_list_field(field); } else if(PURPLE_IS_REQUEST_FIELD_ACCOUNT(field)) { accountlist = create_account_field(field); widget = accountlist; } else { widget = gnt_label_new_with_format(_("Not implemented yet."), GNT_TEXT_FLAG_BOLD); } gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID); gnt_box_add_widget(GNT_BOX(hbox), widget); g_object_set_data(G_OBJECT(field), "finch-ui-data", widget); g_object_unref(field); } if(group_index < n_groups - 1) { gnt_box_add_widget(GNT_BOX(box), gnt_hline_new()); } g_object_unref(group); } gnt_box_add_widget(GNT_BOX(window), box); box = setup_button_box(window, userdata, request_fields_cb, page, ok, ok_cb, cancel, cancel_cb, NULL); extra_actions = purple_request_cpar_get_extra_actions(cpar); for (GSList *it = extra_actions; it; it = it->next) { PurpleKeyValuePair *extra_action = it->data; GntWidget *button = gnt_button_new(extra_action->key); gnt_box_add_widget_in_front(GNT_BOX(box), button); g_object_set_data(G_OBJECT(button), "ui-handle", window); g_object_set_data(G_OBJECT(button), "extra-cb", extra_action->value); g_object_set_data(G_OBJECT(button), "extra-cb-data", userdata); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(multifield_extra_cb), page); } help_cb = purple_request_cpar_get_help_cb(cpar, &help_data); if (help_cb) { GntWidget *button = gnt_button_new(_("Help")); gnt_box_add_widget_in_front(GNT_BOX(box), button); g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(help_cb), help_data); } gnt_box_add_widget(GNT_BOX(window), box); setup_default_callback(window, cancel_cb, userdata); gnt_widget_show(window); if (username && accountlist) { g_signal_connect(username, "completion", G_CALLBACK(update_selected_account), accountlist); } g_object_set_data_full(G_OBJECT(window), "fields", page, g_object_unref); return window; } static void file_cancel_cb(G_GNUC_UNUSED GntWidget *wid, gpointer fq) { FinchFileRequest *data = fq; if (data->dialog == NULL) { /* We've already handled this request, and are in the destroy handler. */ return; } if (data->cbs[1] != NULL) ((PurpleRequestFileCb)data->cbs[1])(data->user_data, NULL); purple_request_close(PURPLE_REQUEST_FILE, data->dialog); data->dialog = NULL; } static void file_ok_cb(G_GNUC_UNUSED GntWidget *widget, const char *path, const char *file, gpointer fq) { FinchFileRequest *data = fq; char *dir = g_path_get_dirname(path); if (data->cbs[0] != NULL) ((PurpleRequestFileCb)data->cbs[0])(data->user_data, file); purple_prefs_set_path(data->save ? "/finch/filelocations/last_save_folder" : "/finch/filelocations/last_open_folder", dir); g_free(dir); purple_request_close(PURPLE_REQUEST_FILE, data->dialog); data->dialog = NULL; } static void file_request_destroy(FinchFileRequest *data) { g_free(data->cbs); g_free(data); } static FinchFileRequest * finch_file_request_window(const char *title, const char *path, GCallback ok_cb, GCallback cancel_cb, void *user_data) { GntWidget *window = gnt_file_sel_new(); GntFileSel *sel = GNT_FILE_SEL(window); FinchFileRequest *data = g_new0(FinchFileRequest, 1); data->user_data = user_data; data->cbs = g_new0(GCallback, 2); data->cbs[0] = ok_cb; data->cbs[1] = cancel_cb; data->dialog = window; gnt_box_set_title(GNT_BOX(window), title); gnt_file_sel_set_current_location(sel, (path && *path) ? path : purple_home_dir()); g_signal_connect(G_OBJECT(sel), "destroy", G_CALLBACK(file_cancel_cb), data); g_signal_connect(G_OBJECT(sel), "cancelled", G_CALLBACK(file_cancel_cb), data); g_signal_connect(G_OBJECT(sel), "file_selected", G_CALLBACK(file_ok_cb), data); g_object_set_data_full(G_OBJECT(window), "filerequestdata", data, (GDestroyNotify)file_request_destroy); return data; } static void * finch_request_file(const char *title, const char *filename, gboolean savedialog, GCallback ok_cb, GCallback cancel_cb, G_GNUC_UNUSED PurpleRequestCommonParameters *cpar, void *user_data) { FinchFileRequest *data; const char *path; path = purple_prefs_get_path(savedialog ? "/finch/filelocations/last_save_folder" : "/finch/filelocations/last_open_folder"); data = finch_file_request_window(title ? title : (savedialog ? _("Save File...") : _("Open File...")), path, ok_cb, cancel_cb, user_data); data->save = savedialog; if (savedialog) gnt_file_sel_set_suggested_filename(GNT_FILE_SEL(data->dialog), filename); gnt_widget_show(data->dialog); return data->dialog; } static void * finch_request_folder(const char *title, const char *dirname, GCallback ok_cb, GCallback cancel_cb, G_GNUC_UNUSED PurpleRequestCommonParameters *cpar, gpointer user_data) { FinchFileRequest *data; data = finch_file_request_window(title ? title : _("Choose Location..."), dirname, ok_cb, cancel_cb, user_data); data->save = TRUE; gnt_file_sel_set_dirs_only(GNT_FILE_SEL(data->dialog), TRUE); gnt_widget_show(data->dialog); return data->dialog; } static PurpleRequestUiOps uiops = { .request_input = finch_request_input, .request_choice = finch_request_choice, .request_action = finch_request_action, .request_fields = finch_request_fields, .request_file = finch_request_file, .request_folder = finch_request_folder, .close_request = finch_close_request, }; PurpleRequestUiOps * finch_request_get_ui_ops(void) { return &uiops; } void finch_request_init(void) { } void finch_request_uninit(void) { } void finch_request_save_in_prefs(G_GNUC_UNUSED gpointer data, PurpleRequestPage *page) { guint n_groups; n_groups = g_list_model_get_n_items(G_LIST_MODEL(page)); for(guint group_index = 0; group_index < n_groups; group_index++) { GListModel *group = NULL; guint n_fields; group = g_list_model_get_item(G_LIST_MODEL(page), group_index); n_fields = g_list_model_get_n_items(group); for(guint field_index = 0; field_index < n_fields; field_index++) { PurpleRequestField *field = NULL; PurplePrefType pt; gpointer val = NULL; const char *id = NULL; field = g_list_model_get_item(group, field_index); id = purple_request_field_get_id(field); if(PURPLE_IS_REQUEST_FIELD_CHOICE(field)) { PurpleRequestFieldChoice *choice = PURPLE_REQUEST_FIELD_CHOICE(field); val = purple_request_field_choice_get_value(choice); } else if(PURPLE_IS_REQUEST_FIELD_LIST(field)) { PurpleRequestFieldList *lfield = PURPLE_REQUEST_FIELD_LIST(field); val = purple_request_field_list_get_selected(lfield)->data; val = purple_request_field_list_get_data(lfield, val); } else if(PURPLE_IS_REQUEST_FIELD_BOOL(field)) { PurpleRequestFieldBool *bfield = PURPLE_REQUEST_FIELD_BOOL(field); val = GINT_TO_POINTER(purple_request_field_bool_get_value(bfield)); } else if(PURPLE_IS_REQUEST_FIELD_INT(field)) { PurpleRequestFieldInt *ifield = PURPLE_REQUEST_FIELD_INT(field); val = GINT_TO_POINTER(purple_request_field_int_get_value(ifield)); } else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) { PurpleRequestFieldString *sfield = PURPLE_REQUEST_FIELD_STRING(field); val = (gpointer)purple_request_field_string_get_value(sfield); } pt = purple_prefs_get_pref_type(id); switch (pt) { case PURPLE_PREF_INT: { long int tmp = GPOINTER_TO_INT(val); if(PURPLE_IS_REQUEST_FIELD_LIST(field)) { /* Lists always return string */ if (sscanf(val, "%ld", &tmp) != 1) tmp = 0; } purple_prefs_set_int(id, (gint)tmp); break; } case PURPLE_PREF_BOOLEAN: purple_prefs_set_bool(id, GPOINTER_TO_INT(val)); break; case PURPLE_PREF_STRING: purple_prefs_set_string(id, val); break; default: break; } g_object_unref(field); } g_object_unref(group); } } GntWidget *finch_request_field_get_widget(PurpleRequestField *field) { GntWidget *ret = NULL; if(PURPLE_IS_REQUEST_FIELD_BOOL(field)) { ret = create_boolean_field(field); } else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) { ret = create_string_field(field, NULL); } else if(PURPLE_IS_REQUEST_FIELD_INT(field)) { ret = create_integer_field(field); } else if(PURPLE_IS_REQUEST_FIELD_CHOICE(field)) { ret = create_choice_field(field); } else if(PURPLE_IS_REQUEST_FIELD_ACCOUNT(field)) { ret = create_account_field(field); } else if(PURPLE_IS_REQUEST_FIELD_LIST(field)) { ret = create_list_field(field); } else { purple_debug_error("GntRequest", "Unimplemented request-field %s", G_OBJECT_TYPE_NAME(field)); } return ret; }