Mercurial > pidgin
diff gtk/gtkprivacy.c @ 14191:009db0b357b5
This is a hand-crafted commit to migrate across subversion revisions
16854:16861, due to some vagaries of the way the original renames were
done. Witness that monotone can do in one revision what svn had to
spread across several.
author | Ethan Blanton <elb@pidgin.im> |
---|---|
date | Sat, 16 Dec 2006 04:59:55 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gtk/gtkprivacy.c Sat Dec 16 04:59:55 2006 +0000 @@ -0,0 +1,653 @@ +/** + * @file gtkprivacy.c GTK+ Privacy UI + * @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 "connection.h" +#include "debug.h" +#include "privacy.h" +#include "request.h" +#include "util.h" + +#include "gtkblist.h" +#include "gtkprivacy.h" +#include "gtkutils.h" + +typedef struct +{ + GtkWidget *win; + + GtkWidget *type_menu; + + GtkWidget *add_button; + GtkWidget *remove_button; + GtkWidget *clear_button; + + GtkWidget *button_box; + GtkWidget *allow_widget; + GtkWidget *block_widget; + + GtkListStore *allow_store; + GtkListStore *block_store; + + GtkWidget *allow_list; + GtkWidget *block_list; + + gboolean in_allow_list; + + GaimAccount *account; + +} GaimGtkPrivacyDialog; + +typedef struct +{ + GaimAccount *account; + char *name; + gboolean block; + +} GaimGtkPrivacyRequestData; + +static struct +{ + const char *text; + int num; + +} menu_entries[] = +{ + { N_("Allow all users to contact me"), GAIM_PRIVACY_ALLOW_ALL }, + { N_("Allow only the users on my buddy list"), GAIM_PRIVACY_ALLOW_BUDDYLIST }, + { N_("Allow only the users below"), GAIM_PRIVACY_ALLOW_USERS }, + { N_("Block all users"), GAIM_PRIVACY_DENY_ALL }, + { N_("Block only the users below"), GAIM_PRIVACY_DENY_USERS } +}; + +static size_t menu_entry_count = sizeof(menu_entries) / sizeof(*menu_entries); + +static GaimGtkPrivacyDialog *privacy_dialog = NULL; + +static void +rebuild_allow_list(GaimGtkPrivacyDialog *dialog) +{ + GSList *l; + GtkTreeIter iter; + + gtk_list_store_clear(dialog->allow_store); + + for (l = dialog->account->permit; l != NULL; l = l->next) { + gtk_list_store_append(dialog->allow_store, &iter); + gtk_list_store_set(dialog->allow_store, &iter, 0, l->data, -1); + } +} + +static void +rebuild_block_list(GaimGtkPrivacyDialog *dialog) +{ + GSList *l; + GtkTreeIter iter; + + gtk_list_store_clear(dialog->block_store); + + for (l = dialog->account->deny; l != NULL; l = l->next) { + gtk_list_store_append(dialog->block_store, &iter); + gtk_list_store_set(dialog->block_store, &iter, 0, l->data, -1); + } +} + +static const char * +find_permit_block_by_name(GSList *list, const char *name) +{ + const char *temp_name; + GSList *l; + + for (l = list; l != NULL; l = l->next) { + temp_name = (const char *)l->data; + + /* Should this use gaim_normalize()? */ + if (!gaim_utf8_strcasecmp(name, temp_name)) + return temp_name; + } + + return NULL; +} + +static void +user_selected_cb(GtkTreeSelection *sel, GaimGtkPrivacyDialog *dialog) +{ + gtk_widget_set_sensitive(dialog->remove_button, TRUE); +} + +static GtkWidget * +build_list(GaimGtkPrivacyDialog *dialog, GtkListStore *model, + GtkWidget **ret_treeview) +{ + GtkWidget *sw; + GtkWidget *treeview; + GtkCellRenderer *rend; + GtkTreeViewColumn *column; + GtkTreeSelection *sel; + + 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); + + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); + *ret_treeview = treeview; + + rend = gtk_cell_renderer_text_new(); + + column = gtk_tree_view_column_new_with_attributes(NULL, rend, + "text", 0, + NULL); + gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), TRUE); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); + gtk_container_add(GTK_CONTAINER(sw), treeview); + + gtk_widget_show(treeview); + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + + g_signal_connect(G_OBJECT(sel), "changed", + G_CALLBACK(user_selected_cb), dialog); + + gtk_widget_set_size_request(sw, -1, 200); + + return sw; +} + +static GtkWidget * +build_allow_list(GaimGtkPrivacyDialog *dialog) +{ + GtkWidget *widget; + GtkWidget *list; + + dialog->allow_store = gtk_list_store_new(1, G_TYPE_STRING); + + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->allow_store), 0, GTK_SORT_ASCENDING); + + widget = build_list(dialog, dialog->allow_store, &list); + + dialog->allow_list = list; + + rebuild_allow_list(dialog); + + return widget; +} + +static GtkWidget * +build_block_list(GaimGtkPrivacyDialog *dialog) +{ + GtkWidget *widget; + GtkWidget *list; + + dialog->block_store = gtk_list_store_new(1, G_TYPE_STRING); + + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->block_store), 0, GTK_SORT_ASCENDING); + + widget = build_list(dialog, dialog->block_store, &list); + + dialog->block_list = list; + + rebuild_block_list(dialog); + + return widget; +} + +static gint +destroy_cb(GtkWidget *w, GdkEvent *event, GaimGtkPrivacyDialog *dialog) +{ + gaim_gtk_privacy_dialog_hide(); + + return 0; +} + +static void +select_account_cb(GtkWidget *dropdown, GaimAccount *account, + GaimGtkPrivacyDialog *dialog) +{ + int i; + + dialog->account = account; + + for (i = 0; i < menu_entry_count; i++) { + if (menu_entries[i].num == account->perm_deny) { + gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), i); + break; + } + } + + rebuild_allow_list(dialog); + rebuild_block_list(dialog); +} + +/* + * TODO: Setting the permit/deny setting needs to go through privacy.c + * Even better: the privacy API needs to not suck. + */ +static void +type_changed_cb(GtkOptionMenu *optmenu, GaimGtkPrivacyDialog *dialog) +{ + int new_type = menu_entries[gtk_option_menu_get_history(optmenu)].num; + + dialog->account->perm_deny = new_type; + serv_set_permit_deny(gaim_account_get_connection(dialog->account)); + + gtk_widget_hide(dialog->allow_widget); + gtk_widget_hide(dialog->block_widget); + gtk_widget_hide(dialog->button_box); + + if (new_type == GAIM_PRIVACY_ALLOW_USERS) { + gtk_widget_show(dialog->allow_widget); + gtk_widget_show(dialog->button_box); + dialog->in_allow_list = TRUE; + } + else if (new_type == GAIM_PRIVACY_DENY_USERS) { + gtk_widget_show(dialog->block_widget); + gtk_widget_show(dialog->button_box); + dialog->in_allow_list = FALSE; + } + + gaim_blist_schedule_save(); + gaim_gtk_blist_refresh(gaim_get_blist()); +} + +static void +add_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog) +{ + if (dialog->in_allow_list) + gaim_gtk_request_add_permit(dialog->account, NULL); + else + gaim_gtk_request_add_block(dialog->account, NULL); +} + +static void +remove_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *sel; + char *name; + + if (dialog->in_allow_list && dialog->allow_store == NULL) + return; + + if (!dialog->in_allow_list && dialog->block_store == NULL) + return; + + if (dialog->in_allow_list) { + model = GTK_TREE_MODEL(dialog->allow_store); + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->allow_list)); + } + else { + model = GTK_TREE_MODEL(dialog->block_store); + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->block_list)); + } + + if (gtk_tree_selection_get_selected(sel, NULL, &iter)) + gtk_tree_model_get(model, &iter, 0, &name, -1); + else + return; + + if (dialog->in_allow_list) { + if (find_permit_block_by_name(dialog->account->permit, name)) + gaim_privacy_permit_remove(dialog->account, name, FALSE); + } + else { + if (find_permit_block_by_name(dialog->account->deny, name)) + gaim_privacy_deny_remove(dialog->account, name, FALSE); + } + g_free(name); +} + +static void +clear_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog) +{ + GSList *l; + if (dialog->in_allow_list) + l = dialog->account->permit; + else + l = dialog->account->deny; + while (l) { + char *user; + user = l->data; + l = l->next; + if (dialog->in_allow_list) + gaim_privacy_permit_remove(dialog->account, user, FALSE); + else + gaim_privacy_deny_remove(dialog->account, user, FALSE); + } +} + +static void +close_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog) +{ + gtk_widget_destroy(dialog->win); + + gaim_gtk_privacy_dialog_hide(); +} + +static GaimGtkPrivacyDialog * +privacy_dialog_new(void) +{ + GaimGtkPrivacyDialog *dialog; + GtkWidget *bbox; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *dropdown; + GtkWidget *label; + GtkWidget *menu; + int selected = 0; + int i; + + dialog = g_new0(GaimGtkPrivacyDialog, 1); + + dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_resizable(GTK_WINDOW(dialog->win), FALSE); + gtk_window_set_role(GTK_WINDOW(dialog->win), "privacy"); + gtk_window_set_title(GTK_WINDOW(dialog->win), _("Privacy")); + gtk_container_set_border_width(GTK_CONTAINER(dialog->win), GAIM_HIG_BORDER); + + g_signal_connect(G_OBJECT(dialog->win), "delete_event", + G_CALLBACK(destroy_cb), dialog); + + /* Main vbox */ + vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); + gtk_container_add(GTK_CONTAINER(dialog->win), vbox); + gtk_widget_show(vbox); + + /* Description label */ + label = gtk_label_new( + _("Changes to privacy settings take effect immediately.")); + + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_widget_show(label); + + /* Hbox for the accounts drop-down and label. */ + hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show(hbox); + + /* "Set privacy for:" label */ + label = gtk_label_new(_("Set privacy for:")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_widget_show(label); + + /* Accounts drop-down */ + dropdown = gaim_gtk_account_option_menu_new(NULL, FALSE, + G_CALLBACK(select_account_cb), NULL, dialog); + gtk_box_pack_start(GTK_BOX(hbox), dropdown, FALSE, FALSE, 0); + gtk_widget_show(dropdown); + gaim_set_accessible_label (dropdown, label); + dialog->account = gaim_gtk_account_option_menu_get_selected(dropdown); + + /* Add the drop-down list with the allow/block types. */ + dialog->type_menu = gtk_option_menu_new(); + gtk_box_pack_start(GTK_BOX(vbox), dialog->type_menu, FALSE, FALSE, 0); + gtk_widget_show(dialog->type_menu); + + /* Build the menu for that. */ + menu = gtk_menu_new(); + + for (i = 0; i < menu_entry_count; i++) { + gaim_new_item(menu, _(menu_entries[i].text)); + + if (menu_entries[i].num == dialog->account->perm_deny) + selected = i; + } + + gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->type_menu), menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), selected); + + g_signal_connect(G_OBJECT(dialog->type_menu), "changed", + G_CALLBACK(type_changed_cb), dialog); + + /* Build the treeview for the allow list. */ + dialog->allow_widget = build_allow_list(dialog); + gtk_box_pack_start(GTK_BOX(vbox), dialog->allow_widget, TRUE, TRUE, 0); + + /* Build the treeview for the block list. */ + dialog->block_widget = build_block_list(dialog); + gtk_box_pack_start(GTK_BOX(vbox), dialog->block_widget, TRUE, TRUE, 0); + + /* Add the button box for Add, Remove, Clear */ + dialog->button_box = bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + /* Add button */ + button = gtk_button_new_from_stock(GTK_STOCK_ADD); + dialog->add_button = button; + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(add_cb), dialog); + + /* Remove button */ + button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); + dialog->remove_button = button; + gtk_widget_set_sensitive(button, FALSE); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(remove_cb), dialog); + + /* Clear button */ + button = gtk_button_new_from_stock(GTK_STOCK_CLEAR); + dialog->clear_button = button; + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(clear_cb), dialog); + + /* Another button box. */ + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + gtk_widget_show(bbox); + + /* Close button */ + button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_widget_show(button); + + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(close_cb), dialog); + + if (dialog->account->perm_deny == GAIM_PRIVACY_ALLOW_USERS) { + gtk_widget_show(dialog->allow_widget); + gtk_widget_show(dialog->button_box); + dialog->in_allow_list = TRUE; + } + else if (dialog->account->perm_deny == GAIM_PRIVACY_DENY_USERS) { + gtk_widget_show(dialog->block_widget); + gtk_widget_show(dialog->button_box); + dialog->in_allow_list = FALSE; + } + + return dialog; +} + +void +gaim_gtk_privacy_dialog_show(void) +{ + g_return_if_fail(gaim_connections_get_all() != NULL); + + if (privacy_dialog == NULL) + privacy_dialog = privacy_dialog_new(); + + gtk_widget_show(privacy_dialog->win); + gdk_window_raise(privacy_dialog->win->window); +} + +void +gaim_gtk_privacy_dialog_hide(void) +{ + if (privacy_dialog == NULL) + return; + + g_free(privacy_dialog); + privacy_dialog = NULL; +} + +static void +destroy_request_data(GaimGtkPrivacyRequestData *data) +{ + g_free(data->name); + g_free(data); +} + +static void +confirm_permit_block_cb(GaimGtkPrivacyRequestData *data, int option) +{ + if (data->block) + gaim_privacy_deny_add(data->account, data->name, FALSE); + else + gaim_privacy_permit_add(data->account, data->name, FALSE); + + destroy_request_data(data); +} + +static void +add_permit_block_cb(GaimGtkPrivacyRequestData *data, const char *name) +{ + data->name = g_strdup(name); + + confirm_permit_block_cb(data, 0); +} + +void +gaim_gtk_request_add_permit(GaimAccount *account, const char *name) +{ + GaimGtkPrivacyRequestData *data; + + g_return_if_fail(account != NULL); + + data = g_new0(GaimGtkPrivacyRequestData, 1); + data->account = account; + data->name = g_strdup(name); + data->block = FALSE; + + if (name == NULL) { + gaim_request_input(account, _("Permit User"), + _("Type a user you permit to contact you."), + _("Please enter the name of the user you wish to be " + "able to contact you."), + NULL, FALSE, FALSE, NULL, + _("_Permit"), G_CALLBACK(add_permit_block_cb), + _("Cancel"), G_CALLBACK(destroy_request_data), + data); + } + else { + char *primary = g_strdup_printf(_("Allow %s to contact you?"), name); + char *secondary = + g_strdup_printf(_("Are you sure you wish to allow " + "%s to contact you?"), name); + + + gaim_request_action(account, _("Permit User"), primary, secondary, + 0, data, 2, + _("_Permit"), G_CALLBACK(confirm_permit_block_cb), + _("Cancel"), G_CALLBACK(destroy_request_data)); + + g_free(primary); + g_free(secondary); + } +} + +void +gaim_gtk_request_add_block(GaimAccount *account, const char *name) +{ + GaimGtkPrivacyRequestData *data; + + g_return_if_fail(account != NULL); + + data = g_new0(GaimGtkPrivacyRequestData, 1); + data->account = account; + data->name = g_strdup(name); + data->block = TRUE; + + if (name == NULL) { + gaim_request_input(account, _("Block User"), + _("Type a user to block."), + _("Please enter the name of the user you wish to block."), + NULL, FALSE, FALSE, NULL, + _("_Block"), G_CALLBACK(add_permit_block_cb), + _("Cancel"), G_CALLBACK(destroy_request_data), + data); + } + else { + char *primary = g_strdup_printf(_("Block %s?"), name); + char *secondary = + g_strdup_printf(_("Are you sure you want to block %s?"), name); + + gaim_request_action(account, _("Block User"), primary, secondary, + 0, data, 2, + _("_Block"), G_CALLBACK(confirm_permit_block_cb), + _("Cancel"), G_CALLBACK(destroy_request_data)); + + g_free(primary); + g_free(secondary); + } +} + +static void +gaim_gtk_permit_added_removed(GaimAccount *account, const char *name) +{ + if (privacy_dialog != NULL) + rebuild_allow_list(privacy_dialog); +} + +static void +gaim_gtk_deny_added_removed(GaimAccount *account, const char *name) +{ + if (privacy_dialog != NULL) + rebuild_block_list(privacy_dialog); +} + +static GaimPrivacyUiOps privacy_ops = +{ + gaim_gtk_permit_added_removed, + gaim_gtk_permit_added_removed, + gaim_gtk_deny_added_removed, + gaim_gtk_deny_added_removed +}; + +GaimPrivacyUiOps * +gaim_gtk_privacy_get_ui_ops(void) +{ + return &privacy_ops; +} + +void +gaim_gtk_privacy_init(void) +{ +}