diff options
author | Sean Egan <seanegan@pidgin.im> | 2007-01-20 02:32:10 +0000 |
---|---|---|
committer | Sean Egan <seanegan@pidgin.im> | 2007-01-20 02:32:10 +0000 |
commit | 87b298a83b8bca7be01ddc853ea4cd15e455b44e (patch) | |
tree | 0fe4490ce85d4f60342ad371f49a5df37ae0aeda /pidgin/gtkrequest.c | |
parent | 0979b409b87b353266d00be787749486024a840a (diff) | |
download | pidgin-87b298a83b8bca7be01ddc853ea4cd15e455b44e.tar.gz |
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
Diffstat (limited to 'pidgin/gtkrequest.c')
-rw-r--r-- | pidgin/gtkrequest.c | 1669 |
1 files changed, 1669 insertions, 0 deletions
diff --git a/pidgin/gtkrequest.c b/pidgin/gtkrequest.c new file mode 100644 index 0000000000..a2657a02ff --- /dev/null +++ b/pidgin/gtkrequest.c @@ -0,0 +1,1669 @@ +/** + * @file gtkrequest.c GTK+ Request API + * @ingroup gtkui + * + * gaim + * + * Gaim 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "internal.h" +#include "gtkgaim.h" + +#include "prefs.h" +#include "util.h" + +#include "gtkimhtml.h" +#include "gtkimhtmltoolbar.h" +#include "gtkrequest.h" +#include "gtkutils.h" +#include "gaimstock.h" + +#include <gdk/gdkkeysyms.h> + +static GtkWidget * create_account_field(GaimRequestField *field); + +typedef struct +{ + GaimRequestType type; + + void *user_data; + GtkWidget *dialog; + + GtkWidget *ok_button; + + size_t cb_count; + GCallback *cbs; + + union + { + struct + { + GtkWidget *entry; + + gboolean multiline; + gchar *hint; + + } input; + + struct + { + GaimRequestFields *fields; + + } multifield; + + struct + { + gboolean savedialog; + gchar *name; + + } file; + + } u; + +} GaimGtkRequestData; + +static void +generic_response_start(GaimGtkRequestData *data) +{ + g_return_if_fail(data != NULL); + + /* Tell the user we're doing something. */ + gaim_gtk_set_cursor(GTK_WIDGET(data->dialog), GDK_WATCH); +} + +static void +input_response_cb(GtkDialog *dialog, gint id, GaimGtkRequestData *data) +{ + const char *value; + char *multiline_value = NULL; + + generic_response_start(data); + + if (data->u.input.multiline) { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = + gtk_text_view_get_buffer(GTK_TEXT_VIEW(data->u.input.entry)); + + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + + if ((data->u.input.hint != NULL) && (!strcmp(data->u.input.hint, "html"))) + multiline_value = gtk_imhtml_get_markup(GTK_IMHTML(data->u.input.entry)); + else + multiline_value = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, + FALSE); + + value = multiline_value; + } + else + value = gtk_entry_get_text(GTK_ENTRY(data->u.input.entry)); + + if (id < data->cb_count && data->cbs[id] != NULL) + ((GaimRequestInputCb)data->cbs[id])(data->user_data, value); + else if (data->cbs[1] != NULL) + ((GaimRequestInputCb)data->cbs[1])(data->user_data, value); + + if (data->u.input.multiline) + g_free(multiline_value); + + gaim_request_close(GAIM_REQUEST_INPUT, data); +} + +static void +action_response_cb(GtkDialog *dialog, gint id, GaimGtkRequestData *data) +{ + generic_response_start(data); + + if (id < data->cb_count && data->cbs[id] != NULL) + ((GaimRequestActionCb)data->cbs[id])(data->user_data, id); + + gaim_request_close(GAIM_REQUEST_INPUT, data); +} + + +static void +choice_response_cb(GtkDialog *dialog, gint id, GaimGtkRequestData *data) +{ + GtkWidget *radio = g_object_get_data(G_OBJECT(dialog), "radio"); + GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio)); + + generic_response_start(data); + + if (id < data->cb_count && data->cbs[id] != NULL) + while (group) { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group->data))) { + ((GaimRequestChoiceCb)data->cbs[id])(data->user_data, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(group->data), "choice_id"))); + break; + } + group = group->next; + } + gaim_request_close(GAIM_REQUEST_INPUT, data); +} + +static gboolean +field_string_focus_out_cb(GtkWidget *entry, GdkEventFocus *event, + GaimRequestField *field) +{ + const char *value; + + if (gaim_request_field_string_is_multiline(field)) + { + GtkTextBuffer *buffer; + GtkTextIter start_iter, end_iter; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry)); + + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + + value = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, FALSE); + } + else + value = gtk_entry_get_text(GTK_ENTRY(entry)); + + gaim_request_field_string_set_value(field, + (*value == '\0' ? NULL : value)); + + return FALSE; +} + +static gboolean +field_int_focus_out_cb(GtkEntry *entry, GdkEventFocus *event, + GaimRequestField *field) +{ + gaim_request_field_int_set_value(field, + atoi(gtk_entry_get_text(entry))); + + return FALSE; +} + +static void +field_bool_cb(GtkToggleButton *button, GaimRequestField *field) +{ + gaim_request_field_bool_set_value(field, + gtk_toggle_button_get_active(button)); +} + +static void +field_choice_menu_cb(GtkOptionMenu *menu, GaimRequestField *field) +{ + gaim_request_field_choice_set_value(field, + gtk_option_menu_get_history(menu)); +} + +static void +field_choice_option_cb(GtkRadioButton *button, GaimRequestField *field) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) + gaim_request_field_choice_set_value(field, + (g_slist_length(gtk_radio_button_get_group(button)) - + g_slist_index(gtk_radio_button_get_group(button), button)) - 1); +} + +static void +field_account_cb(GObject *w, GaimAccount *account, GaimRequestField *field) +{ + gaim_request_field_account_set_value(field, account); +} + +static void +multifield_ok_cb(GtkWidget *button, GaimGtkRequestData *data) +{ + generic_response_start(data); + + if (!GTK_WIDGET_HAS_FOCUS(button)) + gtk_widget_grab_focus(button); + + if (data->cbs[0] != NULL) + ((GaimRequestFieldsCb)data->cbs[0])(data->user_data, + data->u.multifield.fields); + + gaim_request_close(GAIM_REQUEST_FIELDS, data); +} + +static void +multifield_cancel_cb(GtkWidget *button, GaimGtkRequestData *data) +{ + generic_response_start(data); + + if (data->cbs[1] != NULL) + ((GaimRequestFieldsCb)data->cbs[1])(data->user_data, + data->u.multifield.fields); + + gaim_request_close(GAIM_REQUEST_FIELDS, data); +} + +static void +destroy_multifield_cb(GtkWidget *dialog, GdkEvent *event, + GaimGtkRequestData *data) +{ + multifield_cancel_cb(NULL, data); +} + + +#define STOCK_ITEMIZE(r, l) \ + if (!strcmp((r), text)) \ + return (l); + +static const char * +text_to_stock(const char *text) +{ + STOCK_ITEMIZE(_("Yes"), GTK_STOCK_YES); + STOCK_ITEMIZE(_("No"), GTK_STOCK_NO); + STOCK_ITEMIZE(_("OK"), GTK_STOCK_OK); + STOCK_ITEMIZE(_("Cancel"), GTK_STOCK_CANCEL); + STOCK_ITEMIZE(_("Apply"), GTK_STOCK_APPLY); + STOCK_ITEMIZE(_("Close"), GTK_STOCK_CLOSE); + STOCK_ITEMIZE(_("Delete"), GTK_STOCK_DELETE); + STOCK_ITEMIZE(_("Add"), GTK_STOCK_ADD); + STOCK_ITEMIZE(_("Remove"), GTK_STOCK_REMOVE); + STOCK_ITEMIZE(_("Save"), GTK_STOCK_SAVE); + STOCK_ITEMIZE(_("Alias"), GAIM_STOCK_ALIAS); + + return text; +} + +static void * +gaim_gtk_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, + void *user_data) +{ + GaimGtkRequestData *data; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *entry; + GtkWidget *img; + GtkWidget *toolbar; + char *label_text; + char *primary_esc, *secondary_esc; + + data = g_new0(GaimGtkRequestData, 1); + data->type = GAIM_REQUEST_INPUT; + data->user_data = user_data; + + data->cb_count = 2; + data->cbs = g_new0(GCallback, 2); + + data->cbs[0] = ok_cb; + data->cbs[1] = cancel_cb; + + /* Create the dialog. */ + dialog = gtk_dialog_new_with_buttons(title ? title : GAIM_ALERT_TITLE, + NULL, 0, + text_to_stock(cancel_text), 1, + text_to_stock(ok_text), 0, + NULL); + data->dialog = dialog; + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(input_response_cb), data); + + /* Setup the dialog */ + gtk_container_set_border_width(GTK_CONTAINER(dialog), GAIM_HIG_BORDER/2); + gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER/2); + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER); + + /* Setup the main horizontal box */ + hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); + + /* Dialog icon. */ + img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment(GTK_MISC(img), 0, 0); + gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); + + /* Vertical box */ + vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); + + gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + + /* Descriptive label */ + primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL; + secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL; + label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">" + "%s</span>%s%s" : "%s%s%s"), + (primary ? primary_esc : ""), + ((primary && secondary) ? "\n\n" : ""), + (secondary ? secondary_esc : "")); + g_free(primary_esc); + g_free(secondary_esc); + + label = gtk_label_new(NULL); + + gtk_label_set_markup(GTK_LABEL(label), label_text); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); + + g_free(label_text); + + /* Entry field. */ + data->u.input.multiline = multiline; + data->u.input.hint = g_strdup(hint); + + if ((data->u.input.hint != NULL) && (!strcmp(data->u.input.hint, "html"))) { + GtkWidget *frame; + + /* imhtml */ + frame = gaim_gtk_create_imhtml(TRUE, &entry, &toolbar, NULL); + gtk_widget_set_size_request(entry, 320, 130); + gtk_widget_set_name(entry, "gaim_gtkrequest_imhtml"); + if (default_value != NULL) + gtk_imhtml_append_text(GTK_IMHTML(entry), default_value, GTK_IMHTML_NO_SCROLL); + gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); + gtk_widget_show(frame); + } + else { + if (multiline) { + GtkWidget *sw; + + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_IN); + + gtk_widget_set_size_request(sw, 320, 130); + + /* GtkTextView */ + entry = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(entry), TRUE); + + if (default_value != NULL) { + GtkTextBuffer *buffer; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry)); + gtk_text_buffer_set_text(buffer, default_value, -1); + } + + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(entry), GTK_WRAP_WORD_CHAR); + + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); + + if (gaim_prefs_get_bool("/gaim/gtk/conversations/spellcheck")) + gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(entry)); + + gtk_container_add(GTK_CONTAINER(sw), entry); + } + else { + entry = gtk_entry_new(); + + gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); + + gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); + + if (default_value != NULL) + gtk_entry_set_text(GTK_ENTRY(entry), default_value); + + if (masked) + { + gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); + if (gtk_entry_get_invisible_char(GTK_ENTRY(entry)) == '*') + gtk_entry_set_invisible_char(GTK_ENTRY(entry), GAIM_INVISIBLE_CHAR); + } + } + } + + gaim_set_accessible_label (entry, label); + data->u.input.entry = entry; + + /* Show everything. */ + gtk_widget_show_all(dialog); + + return data; +} + +static void * +gaim_gtk_request_choice(const char *title, const char *primary, + const char *secondary, unsigned int default_value, + const char *ok_text, GCallback ok_cb, + const char *cancel_text, GCallback cancel_cb, + void *user_data, va_list args) +{ + GaimGtkRequestData *data; + GtkWidget *dialog; + GtkWidget *vbox, *vbox2; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *img; + GtkWidget *radio = NULL; + char *label_text; + char *radio_text; + char *primary_esc, *secondary_esc; + + data = g_new0(GaimGtkRequestData, 1); + data->type = GAIM_REQUEST_ACTION; + data->user_data = user_data; + + data->cb_count = 2; + data->cbs = g_new0(GCallback, 2); + data->cbs[0] = cancel_cb; + data->cbs[1] = ok_cb; + + /* Create the dialog. */ + data->dialog = dialog = gtk_dialog_new(); + + if (title != NULL) + gtk_window_set_title(GTK_WINDOW(dialog), title); + + + gtk_dialog_add_button(GTK_DIALOG(dialog), + text_to_stock(cancel_text), 0); + + gtk_dialog_add_button(GTK_DIALOG(dialog), + text_to_stock(ok_text), 1); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(choice_response_cb), data); + + /* Setup the dialog */ + gtk_container_set_border_width(GTK_CONTAINER(dialog), GAIM_HIG_BORDER/2); + gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER/2); + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER); + + /* Setup the main horizontal box */ + hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); + + /* Dialog icon. */ + img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment(GTK_MISC(img), 0, 0); + gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); + + /* Vertical box */ + vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); + gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + + /* Descriptive label */ + primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL; + secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL; + label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">" + "%s</span>%s%s" : "%s%s%s"), + (primary ? primary_esc : ""), + ((primary && secondary) ? "\n\n" : ""), + (secondary ? secondary_esc : "")); + g_free(primary_esc); + g_free(secondary_esc); + + label = gtk_label_new(NULL); + + gtk_label_set_markup(GTK_LABEL(label), label_text); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); + + g_free(label_text); + + vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE); + gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0); + while ((radio_text = va_arg(args, char*))) { + int resp = va_arg(args, int); + radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), radio_text); + gtk_box_pack_start(GTK_BOX(vbox2), radio, FALSE, FALSE, 0); + g_object_set_data(G_OBJECT(radio), "choice_id", GINT_TO_POINTER(resp)); + if (resp == default_value) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE); + } + + g_object_set_data(G_OBJECT(dialog), "radio", radio); + + /* Show everything. */ + gtk_widget_show_all(dialog); + + return data; +} + +static void * +gaim_gtk_request_action(const char *title, const char *primary, + const char *secondary, unsigned int default_action, + void *user_data, size_t action_count, va_list actions) +{ + GaimGtkRequestData *data; + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *img; + void **buttons; + char *label_text; + char *primary_esc, *secondary_esc; + int i; + + data = g_new0(GaimGtkRequestData, 1); + data->type = GAIM_REQUEST_ACTION; + data->user_data = user_data; + + data->cb_count = action_count; + data->cbs = g_new0(GCallback, action_count); + + /* Reverse the buttons */ + buttons = g_new0(void *, action_count * 2); + + for (i = 0; i < action_count * 2; i += 2) { + buttons[(action_count * 2) - i - 2] = va_arg(actions, char *); + buttons[(action_count * 2) - i - 1] = va_arg(actions, GCallback); + } + + /* Create the dialog. */ + data->dialog = dialog = gtk_dialog_new(); + + if (title != NULL) + gtk_window_set_title(GTK_WINDOW(dialog), title); + + for (i = 0; i < action_count; i++) { + gtk_dialog_add_button(GTK_DIALOG(dialog), + text_to_stock(buttons[2 * i]), i); + + data->cbs[i] = buttons[2 * i + 1]; + } + + g_free(buttons); + + g_signal_connect(G_OBJECT(dialog), "response", + G_CALLBACK(action_response_cb), data); + + /* Setup the dialog */ + gtk_container_set_border_width(GTK_CONTAINER(dialog), GAIM_HIG_BORDER/2); + gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER/2); + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), GAIM_HIG_BORDER); + + /* Setup the main horizontal box */ + hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); + + /* Dialog icon. */ + img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment(GTK_MISC(img), 0, 0); + gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); + + /* Vertical box */ + vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); + gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + + /* Descriptive label */ + primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL; + secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL; + label_text = g_strdup_printf((primary ? "<span weight=\"bold\" size=\"larger\">" + "%s</span>%s%s" : "%s%s%s"), + (primary ? primary_esc : ""), + ((primary && secondary) ? "\n\n" : ""), + (secondary ? secondary_esc : "")); + g_free(primary_esc); + g_free(secondary_esc); + + label = gtk_label_new(NULL); + + gtk_label_set_markup(GTK_LABEL(label), label_text); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_label_set_selectable(GTK_LABEL(label), TRUE); + gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); + + g_free(label_text); + + + if (default_action == GAIM_DEFAULT_ACTION_NONE) { + GTK_WIDGET_SET_FLAGS(img, GTK_CAN_DEFAULT); + GTK_WIDGET_SET_FLAGS(img, GTK_CAN_FOCUS); + gtk_widget_grab_focus(img); + gtk_widget_grab_default(img); + } else + gtk_dialog_set_default_response(GTK_DIALOG(dialog), default_action); + + /* Show everything. */ + gtk_widget_show_all(dialog); + + return data; +} + +static void +req_entry_field_changed_cb(GtkWidget *entry, GaimRequestField *field) +{ + GaimGtkRequestData *req_data; + const char *text = gtk_entry_get_text(GTK_ENTRY(entry)); + + gaim_request_field_string_set_value(field, (*text == '\0' ? NULL : text)); + + req_data = (GaimGtkRequestData *)field->group->fields_list->ui_data; + + gtk_widget_set_sensitive(req_data->ok_button, + gaim_request_fields_all_required_filled(field->group->fields_list)); +} + +static void +setup_entry_field(GtkWidget *entry, GaimRequestField *field) +{ + const char *type_hint; + + gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); + + if (gaim_request_field_is_required(field)) + { + g_signal_connect(G_OBJECT(entry), "changed", + G_CALLBACK(req_entry_field_changed_cb), field); + } + + if ((type_hint = gaim_request_field_get_type_hint(field)) != NULL) + { + if (gaim_str_has_prefix(type_hint, "screenname")) + { + GtkWidget *optmenu = NULL; + GList *fields = field->group->fields; + while (fields) + { + GaimRequestField *fld = fields->data; + fields = fields->next; + + if (gaim_request_field_get_type(fld) == GAIM_REQUEST_FIELD_ACCOUNT) + { + const char *type_hint = gaim_request_field_get_type_hint(fld); + if (type_hint != NULL && strcmp(type_hint, "account") == 0) + { + if (fld->ui_data == NULL) + fld->ui_data = create_account_field(fld); + optmenu = GTK_WIDGET(fld->ui_data); + break; + } + } + } + gaim_gtk_setup_screenname_autocomplete(entry, optmenu, !strcmp(type_hint, "screenname-all")); + } + } +} + +static GtkWidget * +create_string_field(GaimRequestField *field) +{ + const char *value; + GtkWidget *widget; + + value = gaim_request_field_string_get_default_value(field); + + if (gaim_request_field_string_is_multiline(field)) + { + GtkWidget *textview; + + widget = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), + GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + + textview = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), + TRUE); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview), + GTK_WRAP_WORD_CHAR); + + if (gaim_prefs_get_bool("/gaim/gtk/conversations/spellcheck")) + gaim_gtk_setup_gtkspell(GTK_TEXT_VIEW(textview)); + + gtk_container_add(GTK_CONTAINER(widget), textview); + gtk_widget_show(textview); + + gtk_widget_set_size_request(widget, -1, 75); + + if (value != NULL) + { + GtkTextBuffer *buffer; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); + + gtk_text_buffer_set_text(buffer, value, -1); + } + + gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), + gaim_request_field_string_is_editable(field)); + + g_signal_connect(G_OBJECT(textview), "focus-out-event", + G_CALLBACK(field_string_focus_out_cb), field); + } + else + { + widget = gtk_entry_new(); + + setup_entry_field(widget, field); + + if (value != NULL) + gtk_entry_set_text(GTK_ENTRY(widget), value); + + if (gaim_request_field_string_is_masked(field)) + { + gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE); + if (gtk_entry_get_invisible_char(GTK_ENTRY(widget)) == '*') + gtk_entry_set_invisible_char(GTK_ENTRY(widget), GAIM_INVISIBLE_CHAR); + } + + gtk_editable_set_editable(GTK_EDITABLE(widget), + gaim_request_field_string_is_editable(field)); + + g_signal_connect(G_OBJECT(widget), "focus-out-event", + G_CALLBACK(field_string_focus_out_cb), field); + } + + return widget; +} + +static GtkWidget * +create_int_field(GaimRequestField *field) +{ + int value; + GtkWidget *widget; + + widget = gtk_entry_new(); + + setup_entry_field(widget, field); + + value = gaim_request_field_int_get_default_value(field); + + if (value != 0) + { + char buf[32]; + + g_snprintf(buf, sizeof(buf), "%d", value); + + gtk_entry_set_text(GTK_ENTRY(widget), buf); + } + + g_signal_connect(G_OBJECT(widget), "focus-out-event", + G_CALLBACK(field_int_focus_out_cb), field); + + return widget; +} + +static GtkWidget * +create_bool_field(GaimRequestField *field) +{ + GtkWidget *widget; + + widget = gtk_check_button_new_with_label( + gaim_request_field_get_label(field)); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), + gaim_request_field_bool_get_default_value(field)); + + g_signal_connect(G_OBJECT(widget), "toggled", + G_CALLBACK(field_bool_cb), field); + + return widget; +} + +static GtkWidget * +create_choice_field(GaimRequestField *field) +{ + GtkWidget *widget; + GList *labels; + GList *l; + + labels = gaim_request_field_choice_get_labels(field); + + if (g_list_length(labels) > 5) + { + GtkWidget *menu; + GtkWidget *item; + + widget = gtk_option_menu_new(); + + menu = gtk_menu_new(); + + for (l = labels; l != NULL; l = l->next) + { + const char *text = l->data; + + item = gtk_menu_item_new_with_label(text); + gtk_widget_show(item); + + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + } + + gtk_widget_show(menu); + gtk_option_menu_set_menu(GTK_OPTION_MENU(widget), menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(widget), + gaim_request_field_choice_get_default_value(field)); + + g_signal_connect(G_OBJECT(widget), "changed", + G_CALLBACK(field_choice_menu_cb), field); + } + else + { + GtkWidget *box; + GtkWidget *first_radio = NULL; + GtkWidget *radio; + gint i; + + if (g_list_length(labels) == 2) + box = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); + else + box = gtk_vbox_new(FALSE, 0); + + widget = box; + + for (l = labels, i = 0; l != NULL; l = l->next, i++) + { + const char *text = l->data; + + radio = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON(first_radio), text); + + if (first_radio == NULL) + first_radio = radio; + + if (i == gaim_request_field_choice_get_default_value(field)) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE); + + gtk_box_pack_start(GTK_BOX(box), radio, TRUE, TRUE, 0); + gtk_widget_show(radio); + + g_signal_connect(G_OBJECT(radio), "toggled", + G_CALLBACK(field_choice_option_cb), field); + } + } + + return widget; +} + +static GtkWidget * +create_image_field(GaimRequestField *field) +{ + GtkWidget *widget; + GdkPixbuf *buf, *scale; + GdkPixbufLoader *loader; + + loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(loader, + (const guchar *)gaim_request_field_image_get_buffer(field), + gaim_request_field_image_get_size(field), + NULL); + gdk_pixbuf_loader_close(loader, NULL); + buf = gdk_pixbuf_loader_get_pixbuf(loader); + + scale = gdk_pixbuf_scale_simple(buf, + gaim_request_field_image_get_scale_x(field) * gdk_pixbuf_get_width(buf), + gaim_request_field_image_get_scale_y(field) * gdk_pixbuf_get_height(buf), + GDK_INTERP_BILINEAR); + widget = gtk_image_new_from_pixbuf(scale); + g_object_unref(G_OBJECT(buf)); + g_object_unref(G_OBJECT(scale)); + + return widget; +} + +static GtkWidget * +create_account_field(GaimRequestField *field) +{ + GtkWidget *widget; + + widget = gaim_gtk_account_option_menu_new( + gaim_request_field_account_get_default_value(field), + gaim_request_field_account_get_show_all(field), + G_CALLBACK(field_account_cb), + gaim_request_field_account_get_filter(field), + field); + + return widget; +} + +static void +select_field_list_item(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + GaimRequestField *field = (GaimRequestField *)data; + char *text; + + gtk_tree_model_get(model, iter, 1, &text, -1); + + gaim_request_field_list_add_selected(field, text); + g_free(text); +} + +static void +list_field_select_changed_cb(GtkTreeSelection *sel, GaimRequestField *field) +{ + gaim_request_field_list_clear_selected(field); + + gtk_tree_selection_selected_foreach(sel, select_field_list_item, field); +} + +static GtkWidget * +create_list_field(GaimRequestField *field) +{ + GtkWidget *sw; + GtkWidget *treeview; + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + GtkTreeIter iter; + const GList *l; + + /* Create the scrolled window */ + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_IN); + gtk_widget_show(sw); + + /* Create the list store */ + store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING); + + /* Create the tree view */ + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + + if (gaim_request_field_list_get_multi_select(field)) + gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); + + g_signal_connect(G_OBJECT(sel), "changed", + G_CALLBACK(list_field_select_changed_cb), field); + + column = gtk_tree_view_column_new(); + gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, "text", 1); + + for (l = gaim_request_field_list_get_items(field); l != NULL; l = l->next) + { + const char *text = (const char *)l->data; + + gtk_list_store_append(store, &iter); + + gtk_list_store_set(store, &iter, + 0, gaim_request_field_list_get_data(field, text), + 1, text, + -1); + + if (gaim_request_field_list_is_selected(field, text)) + gtk_tree_selection_select_iter(sel, &iter); + } + + gtk_container_add(GTK_CONTAINER(sw), treeview); + gtk_widget_show(treeview); + + return sw; +} + +static void * +gaim_gtk_request_fields(const char *title, const char *primary, + const char *secondary, GaimRequestFields *fields, + const char *ok_text, GCallback ok_cb, + const char *cancel_text, GCallback cancel_cb, + void *user_data) +{ + GaimGtkRequestData *data; + GtkWidget *win; + GtkWidget *vbox; + GtkWidget *vbox2; + GtkWidget *hbox; + GtkWidget *bbox; + GtkWidget *frame; + GtkWidget *label; + GtkWidget *table; + GtkWidget *button; + GtkWidget *img; + GtkWidget *sw; + GtkSizeGroup *sg; + GList *gl, *fl; + GaimRequestFieldGroup *group; + GaimRequestField *field; + char *label_text; + char *primary_esc, *secondary_esc; + int total_fields = 0; + + data = g_new0(GaimGtkRequestData, 1); + data->type = GAIM_REQUEST_FIELDS; + data->user_data = user_data; + data->u.multifield.fields = fields; + + fields->ui_data = data; + + data->cb_count = 2; + data->cbs = g_new0(GCallback, 2); + + data->cbs[0] = ok_cb; + data->cbs[1] = cancel_cb; + + data->dialog = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + if (title != NULL) + gtk_window_set_title(GTK_WINDOW(win), title); + + gtk_window_set_role(GTK_WINDOW(win), "multifield"); + gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); + + g_signal_connect(G_OBJECT(win), "delete_event", + G_CALLBACK(destroy_multifield_cb), data); + + /* Setup the main horizontal box */ + hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER); + gtk_container_add(GTK_CONTAINER(win), hbox); + gtk_widget_show(hbox); + + /* Dialog icon. */ + img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION, + GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment(GTK_MISC(img), 0, 0); + gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); + gtk_widget_show(img); + + /* Setup the vbox */ + vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); + gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + gtk_widget_show(vbox); + + sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + + if(primary) { + primary_esc = g_markup_escape_text(primary, -1); + label_text = g_strdup_printf( + "<span weight=\"bold\" size=\"larger\">%s</span>", primary_esc); + g_free(primary_esc); + label = gtk_label_new(NULL); + + gtk_label_set_markup(GTK_LABEL(label), label_text); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + g_free(label_text); + } + + for (gl = gaim_request_fields_get_groups(fields); gl != NULL; + gl = gl->next) + total_fields += g_list_length(gaim_request_field_group_get_fields(gl->data)); + + if(total_fields > 9) { + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_NONE); + gtk_widget_set_size_request(sw, -1, 200); + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); + gtk_widget_show(sw); + + vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), vbox2); + gtk_widget_show(vbox2); + } else { + vbox2 = vbox; + } + + if (secondary) { + secondary_esc = g_markup_escape_text(secondary, -1); + label = gtk_label_new(NULL); + + gtk_label_set_markup(GTK_LABEL(label), secondary_esc); + g_free(secondary_esc); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0); + gtk_widget_show(label); + } + + for (gl = gaim_request_fields_get_groups(fields); + gl != NULL; + gl = gl->next) + { + GList *field_list; + size_t field_count = 0; + size_t cols = 1; + size_t rows; + size_t col_num; + size_t row_num = 0; + + group = gl->data; + field_list = gaim_request_field_group_get_fields(group); + + if (gaim_request_field_group_get_title(group) != NULL) + { + frame = gaim_gtk_make_frame(vbox2, + gaim_request_field_group_get_title(group)); + } + else + frame = vbox2; + + field_count = g_list_length(field_list); +/* + if (field_count > 9) + { + rows = field_count / 2; + cols++; + } + else + */ + rows = field_count; + + col_num = 0; + + for (fl = field_list; fl != NULL; fl = fl->next) + { + GaimRequestFieldType type; + + field = (GaimRequestField *)fl->data; + + type = gaim_request_field_get_type(field); + + if (type == GAIM_REQUEST_FIELD_LABEL) + { + if (col_num > 0) + rows++; + + rows++; + } + else if ((type == GAIM_REQUEST_FIELD_LIST) || + (type == GAIM_REQUEST_FIELD_STRING && + gaim_request_field_string_is_multiline(field))) + { + if (col_num > 0) + rows++; + + rows += 2; + } + + col_num++; + + if (col_num >= cols) + col_num = 0; + } + + table = gtk_table_new(rows, 2 * cols, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), GAIM_HIG_BOX_SPACE); + gtk_table_set_col_spacings(GTK_TABLE(table), GAIM_HIG_BOX_SPACE); + + gtk_container_add(GTK_CONTAINER(frame), table); + gtk_widget_show(table); + + for (row_num = 0, fl = field_list; + row_num < rows && fl != NULL; + row_num++) + { + for (col_num = 0; + col_num < cols && fl != NULL; + col_num++, fl = fl->next) + { + size_t col_offset = col_num * 2; + GaimRequestFieldType type; + GtkWidget *widget = NULL; + + label = NULL; + field = fl->data; + + if (!gaim_request_field_is_visible(field)) { + col_num--; + continue; + } + + type = gaim_request_field_get_type(field); + + if (type != GAIM_REQUEST_FIELD_BOOLEAN && + gaim_request_field_get_label(field)) + { + char *text; + + text = g_strdup_printf("%s:", + gaim_request_field_get_label(field)); + + label = gtk_label_new(NULL); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), text); + g_free(text); + + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + + gtk_size_group_add_widget(sg, label); + + if (type == GAIM_REQUEST_FIELD_LABEL || + type == GAIM_REQUEST_FIELD_LIST || + (type == GAIM_REQUEST_FIELD_STRING && + gaim_request_field_string_is_multiline(field))) + { + if(col_num > 0) + row_num++; + + gtk_table_attach_defaults(GTK_TABLE(table), label, + 0, 2 * cols, + row_num, row_num + 1); + + row_num++; + col_num=cols; + } + else + { + gtk_table_attach_defaults(GTK_TABLE(table), label, + col_offset, col_offset + 1, + row_num, row_num + 1); + } + + gtk_widget_show(label); + } + + if (field->ui_data != NULL) + widget = GTK_WIDGET(field->ui_data); + else if (type == GAIM_REQUEST_FIELD_STRING) + widget = create_string_field(field); + else if (type == GAIM_REQUEST_FIELD_INTEGER) + widget = create_int_field(field); + else if (type == GAIM_REQUEST_FIELD_BOOLEAN) + widget = create_bool_field(field); + else if (type == GAIM_REQUEST_FIELD_CHOICE) + widget = create_choice_field(field); + else if (type == GAIM_REQUEST_FIELD_LIST) + widget = create_list_field(field); + else if (type == GAIM_REQUEST_FIELD_IMAGE) + widget = create_image_field(field); + else if (type == GAIM_REQUEST_FIELD_ACCOUNT) + widget = create_account_field(field); + else + continue; + + if (label) + gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget); + + if (type == GAIM_REQUEST_FIELD_STRING && + gaim_request_field_string_is_multiline(field)) + { + gtk_table_attach(GTK_TABLE(table), widget, + 0, 2 * cols, + row_num, row_num + 1, + GTK_FILL | GTK_EXPAND, + GTK_FILL | GTK_EXPAND, + 5, 0); + } + else if (type == GAIM_REQUEST_FIELD_LIST) + { + gtk_table_attach(GTK_TABLE(table), widget, + 0, 2 * cols, + row_num, row_num + 1, + GTK_FILL | GTK_EXPAND, + GTK_FILL | GTK_EXPAND, + 5, 0); + } + else if (type == GAIM_REQUEST_FIELD_BOOLEAN) + { + gtk_table_attach(GTK_TABLE(table), widget, + col_offset, col_offset + 1, + row_num, row_num + 1, + GTK_FILL | GTK_EXPAND, + GTK_FILL | GTK_EXPAND, + 5, 0); + } + else + { + gtk_table_attach(GTK_TABLE(table), widget, + 1, 2 * cols, + row_num, row_num + 1, + GTK_FILL | GTK_EXPAND, + GTK_FILL | GTK_EXPAND, + 5, 0); + } + + gtk_widget_show(widget); + + field->ui_data = widget; + } + } + } + + g_object_unref(sg); + + /* Button box. */ + bbox = gtk_hbutton_box_new(); + gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); + gtk_widget_show(bbox); + + /* Cancel button */ + button = gtk_button_new_from_stock(text_to_stock(cancel_text)); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(multifield_cancel_cb), data); + + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + + /* OK button */ + button = gtk_button_new_from_stock(text_to_stock(ok_text)); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + data->ok_button = button; + + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_window_set_default(GTK_WINDOW(win), button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(multifield_ok_cb), data); + + if (!gaim_request_fields_all_required_filled(fields)) + gtk_widget_set_sensitive(button, FALSE); + + gtk_widget_show(win); + + return data; +} + +static void +file_yes_no_cb(GaimGtkRequestData *data, gint id) +{ + /* Only call the callback if yes was selected, otherwise the request + * (eg. file transfer) will be cancelled, then when a new filename is chosen + * things go BOOM */ + if (id == 1) { + if (data->cbs[1] != NULL) + ((GaimRequestFileCb)data->cbs[1])(data->user_data, data->u.file.name); + gaim_request_close(data->type, data); + } else { + gaim_gtk_clear_cursor(GTK_WIDGET(data->dialog)); + } +} + +#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ +static void +file_ok_check_if_exists_cb(GtkWidget *widget, gint response, GaimGtkRequestData *data) +{ + gchar *current_folder; + + generic_response_start(data); + + if (response != GTK_RESPONSE_ACCEPT) { + if (data->cbs[0] != NULL) + ((GaimRequestFileCb)data->cbs[0])(data->user_data, NULL); + gaim_request_close(data->type, data); + return; + } + + data->u.file.name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data->dialog)); + current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(data->dialog)); + if (current_folder != NULL) { + if (data->u.file.savedialog) { + gaim_prefs_set_path("/gaim/gtk/filelocations/last_save_folder", current_folder); + } else { + gaim_prefs_set_path("/gaim/gtk/filelocations/last_open_folder", current_folder); + } + g_free(current_folder); + } + +#else /* FILECHOOSER */ + +static void +file_ok_check_if_exists_cb(GtkWidget *button, GaimGtkRequestData *data) +{ + const gchar *name; + gchar *current_folder; + + generic_response_start(data); + + name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(data->dialog)); + + /* If name is a directory then change directories */ + if (data->type == GAIM_REQUEST_FILE) { + if (gaim_gtk_check_if_dir(name, GTK_FILE_SELECTION(data->dialog))) + return; + } + + current_folder = g_path_get_dirname(name); + + g_free(data->u.file.name); + if (data->type == GAIM_REQUEST_FILE) + data->u.file.name = g_strdup(name); + else + { + if (g_file_test(name, G_FILE_TEST_IS_DIR)) + data->u.file.name = g_strdup(name); + else + data->u.file.name = g_strdup(current_folder); + } + + if (current_folder != NULL) { + if (data->u.file.savedialog) { + gaim_prefs_set_path("/gaim/gtk/filelocations/last_save_folder", current_folder); + } else { + gaim_prefs_set_path("/gaim/gtk/filelocations/last_open_folder", current_folder); + } + g_free(current_folder); + } + +#endif /* FILECHOOSER */ + + if ((data->u.file.savedialog == TRUE) && + (g_file_test(data->u.file.name, G_FILE_TEST_EXISTS))) { + gaim_request_action(data, NULL, _("That file already exists"), + _("Would you like to overwrite it?"), 0, data, 2, + _("Overwrite"), G_CALLBACK(file_yes_no_cb), + _("Choose New Name"), G_CALLBACK(file_yes_no_cb)); + } else + file_yes_no_cb(data, 1); +} + +#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ +static void +file_cancel_cb(GaimGtkRequestData *data) +{ + generic_response_start(data); + + if (data->cbs[0] != NULL) + ((GaimRequestFileCb)data->cbs[0])(data->user_data, NULL); + + gaim_request_close(data->type, data); +} +#endif /* FILECHOOSER */ + +static void * +gaim_gtk_request_file(const char *title, const char *filename, + gboolean savedialog, + GCallback ok_cb, GCallback cancel_cb, + void *user_data) +{ + GaimGtkRequestData *data; + GtkWidget *filesel; + const gchar *current_folder; +#if GTK_CHECK_VERSION(2,4,0) + gboolean folder_set = FALSE; +#endif + + data = g_new0(GaimGtkRequestData, 1); + data->type = GAIM_REQUEST_FILE; + data->user_data = user_data; + data->cb_count = 2; + data->cbs = g_new0(GCallback, 2); + data->cbs[0] = cancel_cb; + data->cbs[1] = ok_cb; + data->u.file.savedialog = savedialog; + +#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ + filesel = gtk_file_chooser_dialog_new( + title ? title : (savedialog ? _("Save File...") + : _("Open File...")), + NULL, + savedialog ? GTK_FILE_CHOOSER_ACTION_SAVE + : GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + savedialog ? GTK_STOCK_SAVE + : GTK_STOCK_OPEN, + GTK_RESPONSE_ACCEPT, + NULL); + gtk_dialog_set_default_response(GTK_DIALOG(filesel), GTK_RESPONSE_ACCEPT); + + if (savedialog) { + current_folder = gaim_prefs_get_path("/gaim/gtk/filelocations/last_save_folder"); + } else { + current_folder = gaim_prefs_get_path("/gaim/gtk/filelocations/last_open_folder"); + } + + if ((filename != NULL) && (*filename != '\0')) { + if (savedialog) + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filesel), filename); + else + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(filesel), filename); + } + if ((current_folder != NULL) && (*current_folder != '\0')) { + folder_set = gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filesel), current_folder); + } + +#ifdef _WIN32 + if (!folder_set) { + char *my_documents = wgaim_get_special_folder(CSIDL_PERSONAL); + + if (my_documents != NULL) { + gtk_file_chooser_set_current_folder( + GTK_FILE_CHOOSER(filesel), my_documents); + + g_free(my_documents); + } + } + +#endif + g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(filesel)), "response", + G_CALLBACK(file_ok_check_if_exists_cb), data); +#else /* FILECHOOSER */ + filesel = gtk_file_selection_new( + title ? title : (savedialog ? _("Save File...") + : _("Open File..."))); + if (savedialog) { + current_folder = gaim_prefs_get_path("/gaim/gtk/filelocations/last_save_folder"); + } else { + current_folder = gaim_prefs_get_path("/gaim/gtk/filelocations/last_open_folder"); + } + if (current_folder != NULL) { + gchar *path = g_strdup_printf("%s%s", current_folder, G_DIR_SEPARATOR_S); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), path); + g_free(path); + } + if (filename != NULL) + gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), filename); + + g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)), "delete_event", + G_CALLBACK(file_cancel_cb), data); + g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button), + "clicked", G_CALLBACK(file_cancel_cb), data); + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked", + G_CALLBACK(file_ok_check_if_exists_cb), data); +#endif /* FILECHOOSER */ + + data->dialog = filesel; + gtk_widget_show(filesel); + + return (void *)data; +} + +static void * +gaim_gtk_request_folder(const char *title, const char *dirname, + GCallback ok_cb, GCallback cancel_cb, + void *user_data) +{ + GaimGtkRequestData *data; + GtkWidget *dirsel; + + data = g_new0(GaimGtkRequestData, 1); + data->type = GAIM_REQUEST_FOLDER; + data->user_data = user_data; + data->cb_count = 2; + data->cbs = g_new0(GCallback, 2); + data->cbs[0] = cancel_cb; + data->cbs[1] = ok_cb; + data->u.file.savedialog = FALSE; + +#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ + dirsel = gtk_file_chooser_dialog_new( + title ? title : _("Select Folder..."), + NULL, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + NULL); + gtk_dialog_set_default_response(GTK_DIALOG(dirsel), GTK_RESPONSE_ACCEPT); + + if ((dirname != NULL) && (*dirname != '\0')) + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirsel), dirname); + + g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(dirsel)), "response", + G_CALLBACK(file_ok_check_if_exists_cb), data); +#else + dirsel = gtk_file_selection_new(title ? title : _("Select Folder...")); + + g_signal_connect_swapped(G_OBJECT(dirsel), "delete_event", + G_CALLBACK(file_cancel_cb), data); + g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(dirsel)->cancel_button), + "clicked", G_CALLBACK(file_cancel_cb), data); + g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(dirsel)->ok_button), "clicked", + G_CALLBACK(file_ok_check_if_exists_cb), data); +#endif + + data->dialog = dirsel; + gtk_widget_show(dirsel); + + return (void *)data; +} + +static void +gaim_gtk_close_request(GaimRequestType type, void *ui_handle) +{ + GaimGtkRequestData *data = (GaimGtkRequestData *)ui_handle; + + g_free(data->cbs); + + gtk_widget_destroy(data->dialog); + + if (type == GAIM_REQUEST_FIELDS) + gaim_request_fields_destroy(data->u.multifield.fields); + else if (type == GAIM_REQUEST_FILE) + g_free(data->u.file.name); + + g_free(data); +} + +static GaimRequestUiOps ops = +{ + gaim_gtk_request_input, + gaim_gtk_request_choice, + gaim_gtk_request_action, + gaim_gtk_request_fields, + gaim_gtk_request_file, + gaim_gtk_close_request, + gaim_gtk_request_folder +}; + +GaimRequestUiOps * +gaim_gtk_request_get_ui_ops(void) +{ + return &ops; +} |