comparison 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
comparison
equal deleted inserted replaced
14190:366be2ce35a7 14191:009db0b357b5
1 /**
2 * @file gtkprivacy.c GTK+ Privacy UI
3 * @ingroup gtkui
4 *
5 * gaim
6 *
7 * Gaim is the legal property of its developers, whose names are too numerous
8 * to list here. Please refer to the COPYRIGHT file distributed with this
9 * source distribution.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25 #include "internal.h"
26 #include "gtkgaim.h"
27
28 #include "connection.h"
29 #include "debug.h"
30 #include "privacy.h"
31 #include "request.h"
32 #include "util.h"
33
34 #include "gtkblist.h"
35 #include "gtkprivacy.h"
36 #include "gtkutils.h"
37
38 typedef struct
39 {
40 GtkWidget *win;
41
42 GtkWidget *type_menu;
43
44 GtkWidget *add_button;
45 GtkWidget *remove_button;
46 GtkWidget *clear_button;
47
48 GtkWidget *button_box;
49 GtkWidget *allow_widget;
50 GtkWidget *block_widget;
51
52 GtkListStore *allow_store;
53 GtkListStore *block_store;
54
55 GtkWidget *allow_list;
56 GtkWidget *block_list;
57
58 gboolean in_allow_list;
59
60 GaimAccount *account;
61
62 } GaimGtkPrivacyDialog;
63
64 typedef struct
65 {
66 GaimAccount *account;
67 char *name;
68 gboolean block;
69
70 } GaimGtkPrivacyRequestData;
71
72 static struct
73 {
74 const char *text;
75 int num;
76
77 } menu_entries[] =
78 {
79 { N_("Allow all users to contact me"), GAIM_PRIVACY_ALLOW_ALL },
80 { N_("Allow only the users on my buddy list"), GAIM_PRIVACY_ALLOW_BUDDYLIST },
81 { N_("Allow only the users below"), GAIM_PRIVACY_ALLOW_USERS },
82 { N_("Block all users"), GAIM_PRIVACY_DENY_ALL },
83 { N_("Block only the users below"), GAIM_PRIVACY_DENY_USERS }
84 };
85
86 static size_t menu_entry_count = sizeof(menu_entries) / sizeof(*menu_entries);
87
88 static GaimGtkPrivacyDialog *privacy_dialog = NULL;
89
90 static void
91 rebuild_allow_list(GaimGtkPrivacyDialog *dialog)
92 {
93 GSList *l;
94 GtkTreeIter iter;
95
96 gtk_list_store_clear(dialog->allow_store);
97
98 for (l = dialog->account->permit; l != NULL; l = l->next) {
99 gtk_list_store_append(dialog->allow_store, &iter);
100 gtk_list_store_set(dialog->allow_store, &iter, 0, l->data, -1);
101 }
102 }
103
104 static void
105 rebuild_block_list(GaimGtkPrivacyDialog *dialog)
106 {
107 GSList *l;
108 GtkTreeIter iter;
109
110 gtk_list_store_clear(dialog->block_store);
111
112 for (l = dialog->account->deny; l != NULL; l = l->next) {
113 gtk_list_store_append(dialog->block_store, &iter);
114 gtk_list_store_set(dialog->block_store, &iter, 0, l->data, -1);
115 }
116 }
117
118 static const char *
119 find_permit_block_by_name(GSList *list, const char *name)
120 {
121 const char *temp_name;
122 GSList *l;
123
124 for (l = list; l != NULL; l = l->next) {
125 temp_name = (const char *)l->data;
126
127 /* Should this use gaim_normalize()? */
128 if (!gaim_utf8_strcasecmp(name, temp_name))
129 return temp_name;
130 }
131
132 return NULL;
133 }
134
135 static void
136 user_selected_cb(GtkTreeSelection *sel, GaimGtkPrivacyDialog *dialog)
137 {
138 gtk_widget_set_sensitive(dialog->remove_button, TRUE);
139 }
140
141 static GtkWidget *
142 build_list(GaimGtkPrivacyDialog *dialog, GtkListStore *model,
143 GtkWidget **ret_treeview)
144 {
145 GtkWidget *sw;
146 GtkWidget *treeview;
147 GtkCellRenderer *rend;
148 GtkTreeViewColumn *column;
149 GtkTreeSelection *sel;
150
151 sw = gtk_scrolled_window_new(NULL, NULL);
152 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
153 GTK_POLICY_AUTOMATIC,
154 GTK_POLICY_AUTOMATIC);
155 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
156
157 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
158 *ret_treeview = treeview;
159
160 rend = gtk_cell_renderer_text_new();
161
162 column = gtk_tree_view_column_new_with_attributes(NULL, rend,
163 "text", 0,
164 NULL);
165 gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), TRUE);
166 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
167 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
168 gtk_container_add(GTK_CONTAINER(sw), treeview);
169
170 gtk_widget_show(treeview);
171
172 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
173
174 g_signal_connect(G_OBJECT(sel), "changed",
175 G_CALLBACK(user_selected_cb), dialog);
176
177 gtk_widget_set_size_request(sw, -1, 200);
178
179 return sw;
180 }
181
182 static GtkWidget *
183 build_allow_list(GaimGtkPrivacyDialog *dialog)
184 {
185 GtkWidget *widget;
186 GtkWidget *list;
187
188 dialog->allow_store = gtk_list_store_new(1, G_TYPE_STRING);
189
190 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->allow_store), 0, GTK_SORT_ASCENDING);
191
192 widget = build_list(dialog, dialog->allow_store, &list);
193
194 dialog->allow_list = list;
195
196 rebuild_allow_list(dialog);
197
198 return widget;
199 }
200
201 static GtkWidget *
202 build_block_list(GaimGtkPrivacyDialog *dialog)
203 {
204 GtkWidget *widget;
205 GtkWidget *list;
206
207 dialog->block_store = gtk_list_store_new(1, G_TYPE_STRING);
208
209 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->block_store), 0, GTK_SORT_ASCENDING);
210
211 widget = build_list(dialog, dialog->block_store, &list);
212
213 dialog->block_list = list;
214
215 rebuild_block_list(dialog);
216
217 return widget;
218 }
219
220 static gint
221 destroy_cb(GtkWidget *w, GdkEvent *event, GaimGtkPrivacyDialog *dialog)
222 {
223 gaim_gtk_privacy_dialog_hide();
224
225 return 0;
226 }
227
228 static void
229 select_account_cb(GtkWidget *dropdown, GaimAccount *account,
230 GaimGtkPrivacyDialog *dialog)
231 {
232 int i;
233
234 dialog->account = account;
235
236 for (i = 0; i < menu_entry_count; i++) {
237 if (menu_entries[i].num == account->perm_deny) {
238 gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), i);
239 break;
240 }
241 }
242
243 rebuild_allow_list(dialog);
244 rebuild_block_list(dialog);
245 }
246
247 /*
248 * TODO: Setting the permit/deny setting needs to go through privacy.c
249 * Even better: the privacy API needs to not suck.
250 */
251 static void
252 type_changed_cb(GtkOptionMenu *optmenu, GaimGtkPrivacyDialog *dialog)
253 {
254 int new_type = menu_entries[gtk_option_menu_get_history(optmenu)].num;
255
256 dialog->account->perm_deny = new_type;
257 serv_set_permit_deny(gaim_account_get_connection(dialog->account));
258
259 gtk_widget_hide(dialog->allow_widget);
260 gtk_widget_hide(dialog->block_widget);
261 gtk_widget_hide(dialog->button_box);
262
263 if (new_type == GAIM_PRIVACY_ALLOW_USERS) {
264 gtk_widget_show(dialog->allow_widget);
265 gtk_widget_show(dialog->button_box);
266 dialog->in_allow_list = TRUE;
267 }
268 else if (new_type == GAIM_PRIVACY_DENY_USERS) {
269 gtk_widget_show(dialog->block_widget);
270 gtk_widget_show(dialog->button_box);
271 dialog->in_allow_list = FALSE;
272 }
273
274 gaim_blist_schedule_save();
275 gaim_gtk_blist_refresh(gaim_get_blist());
276 }
277
278 static void
279 add_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog)
280 {
281 if (dialog->in_allow_list)
282 gaim_gtk_request_add_permit(dialog->account, NULL);
283 else
284 gaim_gtk_request_add_block(dialog->account, NULL);
285 }
286
287 static void
288 remove_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog)
289 {
290 GtkTreeIter iter;
291 GtkTreeModel *model;
292 GtkTreeSelection *sel;
293 char *name;
294
295 if (dialog->in_allow_list && dialog->allow_store == NULL)
296 return;
297
298 if (!dialog->in_allow_list && dialog->block_store == NULL)
299 return;
300
301 if (dialog->in_allow_list) {
302 model = GTK_TREE_MODEL(dialog->allow_store);
303 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->allow_list));
304 }
305 else {
306 model = GTK_TREE_MODEL(dialog->block_store);
307 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->block_list));
308 }
309
310 if (gtk_tree_selection_get_selected(sel, NULL, &iter))
311 gtk_tree_model_get(model, &iter, 0, &name, -1);
312 else
313 return;
314
315 if (dialog->in_allow_list) {
316 if (find_permit_block_by_name(dialog->account->permit, name))
317 gaim_privacy_permit_remove(dialog->account, name, FALSE);
318 }
319 else {
320 if (find_permit_block_by_name(dialog->account->deny, name))
321 gaim_privacy_deny_remove(dialog->account, name, FALSE);
322 }
323 g_free(name);
324 }
325
326 static void
327 clear_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog)
328 {
329 GSList *l;
330 if (dialog->in_allow_list)
331 l = dialog->account->permit;
332 else
333 l = dialog->account->deny;
334 while (l) {
335 char *user;
336 user = l->data;
337 l = l->next;
338 if (dialog->in_allow_list)
339 gaim_privacy_permit_remove(dialog->account, user, FALSE);
340 else
341 gaim_privacy_deny_remove(dialog->account, user, FALSE);
342 }
343 }
344
345 static void
346 close_cb(GtkWidget *button, GaimGtkPrivacyDialog *dialog)
347 {
348 gtk_widget_destroy(dialog->win);
349
350 gaim_gtk_privacy_dialog_hide();
351 }
352
353 static GaimGtkPrivacyDialog *
354 privacy_dialog_new(void)
355 {
356 GaimGtkPrivacyDialog *dialog;
357 GtkWidget *bbox;
358 GtkWidget *hbox;
359 GtkWidget *vbox;
360 GtkWidget *button;
361 GtkWidget *dropdown;
362 GtkWidget *label;
363 GtkWidget *menu;
364 int selected = 0;
365 int i;
366
367 dialog = g_new0(GaimGtkPrivacyDialog, 1);
368
369 dialog->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
370 gtk_window_set_resizable(GTK_WINDOW(dialog->win), FALSE);
371 gtk_window_set_role(GTK_WINDOW(dialog->win), "privacy");
372 gtk_window_set_title(GTK_WINDOW(dialog->win), _("Privacy"));
373 gtk_container_set_border_width(GTK_CONTAINER(dialog->win), GAIM_HIG_BORDER);
374
375 g_signal_connect(G_OBJECT(dialog->win), "delete_event",
376 G_CALLBACK(destroy_cb), dialog);
377
378 /* Main vbox */
379 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER);
380 gtk_container_add(GTK_CONTAINER(dialog->win), vbox);
381 gtk_widget_show(vbox);
382
383 /* Description label */
384 label = gtk_label_new(
385 _("Changes to privacy settings take effect immediately."));
386
387 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
388 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
389 gtk_widget_show(label);
390
391 /* Hbox for the accounts drop-down and label. */
392 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BORDER);
393 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
394 gtk_widget_show(hbox);
395
396 /* "Set privacy for:" label */
397 label = gtk_label_new(_("Set privacy for:"));
398 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
399 gtk_widget_show(label);
400
401 /* Accounts drop-down */
402 dropdown = gaim_gtk_account_option_menu_new(NULL, FALSE,
403 G_CALLBACK(select_account_cb), NULL, dialog);
404 gtk_box_pack_start(GTK_BOX(hbox), dropdown, FALSE, FALSE, 0);
405 gtk_widget_show(dropdown);
406 gaim_set_accessible_label (dropdown, label);
407 dialog->account = gaim_gtk_account_option_menu_get_selected(dropdown);
408
409 /* Add the drop-down list with the allow/block types. */
410 dialog->type_menu = gtk_option_menu_new();
411 gtk_box_pack_start(GTK_BOX(vbox), dialog->type_menu, FALSE, FALSE, 0);
412 gtk_widget_show(dialog->type_menu);
413
414 /* Build the menu for that. */
415 menu = gtk_menu_new();
416
417 for (i = 0; i < menu_entry_count; i++) {
418 gaim_new_item(menu, _(menu_entries[i].text));
419
420 if (menu_entries[i].num == dialog->account->perm_deny)
421 selected = i;
422 }
423
424 gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->type_menu), menu);
425 gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), selected);
426
427 g_signal_connect(G_OBJECT(dialog->type_menu), "changed",
428 G_CALLBACK(type_changed_cb), dialog);
429
430 /* Build the treeview for the allow list. */
431 dialog->allow_widget = build_allow_list(dialog);
432 gtk_box_pack_start(GTK_BOX(vbox), dialog->allow_widget, TRUE, TRUE, 0);
433
434 /* Build the treeview for the block list. */
435 dialog->block_widget = build_block_list(dialog);
436 gtk_box_pack_start(GTK_BOX(vbox), dialog->block_widget, TRUE, TRUE, 0);
437
438 /* Add the button box for Add, Remove, Clear */
439 dialog->button_box = bbox = gtk_hbutton_box_new();
440 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
441 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
442
443 /* Add button */
444 button = gtk_button_new_from_stock(GTK_STOCK_ADD);
445 dialog->add_button = button;
446 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
447 gtk_widget_show(button);
448
449 g_signal_connect(G_OBJECT(button), "clicked",
450 G_CALLBACK(add_cb), dialog);
451
452 /* Remove button */
453 button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
454 dialog->remove_button = button;
455 gtk_widget_set_sensitive(button, FALSE);
456 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
457 gtk_widget_show(button);
458
459 g_signal_connect(G_OBJECT(button), "clicked",
460 G_CALLBACK(remove_cb), dialog);
461
462 /* Clear button */
463 button = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
464 dialog->clear_button = button;
465 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
466 gtk_widget_show(button);
467
468 g_signal_connect(G_OBJECT(button), "clicked",
469 G_CALLBACK(clear_cb), dialog);
470
471 /* Another button box. */
472 bbox = gtk_hbutton_box_new();
473 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
474 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
475 gtk_widget_show(bbox);
476
477 /* Close button */
478 button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
479 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
480 gtk_widget_show(button);
481
482 g_signal_connect(G_OBJECT(button), "clicked",
483 G_CALLBACK(close_cb), dialog);
484
485 if (dialog->account->perm_deny == GAIM_PRIVACY_ALLOW_USERS) {
486 gtk_widget_show(dialog->allow_widget);
487 gtk_widget_show(dialog->button_box);
488 dialog->in_allow_list = TRUE;
489 }
490 else if (dialog->account->perm_deny == GAIM_PRIVACY_DENY_USERS) {
491 gtk_widget_show(dialog->block_widget);
492 gtk_widget_show(dialog->button_box);
493 dialog->in_allow_list = FALSE;
494 }
495
496 return dialog;
497 }
498
499 void
500 gaim_gtk_privacy_dialog_show(void)
501 {
502 g_return_if_fail(gaim_connections_get_all() != NULL);
503
504 if (privacy_dialog == NULL)
505 privacy_dialog = privacy_dialog_new();
506
507 gtk_widget_show(privacy_dialog->win);
508 gdk_window_raise(privacy_dialog->win->window);
509 }
510
511 void
512 gaim_gtk_privacy_dialog_hide(void)
513 {
514 if (privacy_dialog == NULL)
515 return;
516
517 g_free(privacy_dialog);
518 privacy_dialog = NULL;
519 }
520
521 static void
522 destroy_request_data(GaimGtkPrivacyRequestData *data)
523 {
524 g_free(data->name);
525 g_free(data);
526 }
527
528 static void
529 confirm_permit_block_cb(GaimGtkPrivacyRequestData *data, int option)
530 {
531 if (data->block)
532 gaim_privacy_deny_add(data->account, data->name, FALSE);
533 else
534 gaim_privacy_permit_add(data->account, data->name, FALSE);
535
536 destroy_request_data(data);
537 }
538
539 static void
540 add_permit_block_cb(GaimGtkPrivacyRequestData *data, const char *name)
541 {
542 data->name = g_strdup(name);
543
544 confirm_permit_block_cb(data, 0);
545 }
546
547 void
548 gaim_gtk_request_add_permit(GaimAccount *account, const char *name)
549 {
550 GaimGtkPrivacyRequestData *data;
551
552 g_return_if_fail(account != NULL);
553
554 data = g_new0(GaimGtkPrivacyRequestData, 1);
555 data->account = account;
556 data->name = g_strdup(name);
557 data->block = FALSE;
558
559 if (name == NULL) {
560 gaim_request_input(account, _("Permit User"),
561 _("Type a user you permit to contact you."),
562 _("Please enter the name of the user you wish to be "
563 "able to contact you."),
564 NULL, FALSE, FALSE, NULL,
565 _("_Permit"), G_CALLBACK(add_permit_block_cb),
566 _("Cancel"), G_CALLBACK(destroy_request_data),
567 data);
568 }
569 else {
570 char *primary = g_strdup_printf(_("Allow %s to contact you?"), name);
571 char *secondary =
572 g_strdup_printf(_("Are you sure you wish to allow "
573 "%s to contact you?"), name);
574
575
576 gaim_request_action(account, _("Permit User"), primary, secondary,
577 0, data, 2,
578 _("_Permit"), G_CALLBACK(confirm_permit_block_cb),
579 _("Cancel"), G_CALLBACK(destroy_request_data));
580
581 g_free(primary);
582 g_free(secondary);
583 }
584 }
585
586 void
587 gaim_gtk_request_add_block(GaimAccount *account, const char *name)
588 {
589 GaimGtkPrivacyRequestData *data;
590
591 g_return_if_fail(account != NULL);
592
593 data = g_new0(GaimGtkPrivacyRequestData, 1);
594 data->account = account;
595 data->name = g_strdup(name);
596 data->block = TRUE;
597
598 if (name == NULL) {
599 gaim_request_input(account, _("Block User"),
600 _("Type a user to block."),
601 _("Please enter the name of the user you wish to block."),
602 NULL, FALSE, FALSE, NULL,
603 _("_Block"), G_CALLBACK(add_permit_block_cb),
604 _("Cancel"), G_CALLBACK(destroy_request_data),
605 data);
606 }
607 else {
608 char *primary = g_strdup_printf(_("Block %s?"), name);
609 char *secondary =
610 g_strdup_printf(_("Are you sure you want to block %s?"), name);
611
612 gaim_request_action(account, _("Block User"), primary, secondary,
613 0, data, 2,
614 _("_Block"), G_CALLBACK(confirm_permit_block_cb),
615 _("Cancel"), G_CALLBACK(destroy_request_data));
616
617 g_free(primary);
618 g_free(secondary);
619 }
620 }
621
622 static void
623 gaim_gtk_permit_added_removed(GaimAccount *account, const char *name)
624 {
625 if (privacy_dialog != NULL)
626 rebuild_allow_list(privacy_dialog);
627 }
628
629 static void
630 gaim_gtk_deny_added_removed(GaimAccount *account, const char *name)
631 {
632 if (privacy_dialog != NULL)
633 rebuild_block_list(privacy_dialog);
634 }
635
636 static GaimPrivacyUiOps privacy_ops =
637 {
638 gaim_gtk_permit_added_removed,
639 gaim_gtk_permit_added_removed,
640 gaim_gtk_deny_added_removed,
641 gaim_gtk_deny_added_removed
642 };
643
644 GaimPrivacyUiOps *
645 gaim_gtk_privacy_get_ui_ops(void)
646 {
647 return &privacy_ops;
648 }
649
650 void
651 gaim_gtk_privacy_init(void)
652 {
653 }