src/mn-mailbox-view.gob (25636B) - raw
1 /* 2 * Mail Notification 3 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 %headertop{ 21 #include <gtk/gtk.h> 22 %} 23 24 %{ 25 #include <string.h> 26 #include <glib/gi18n.h> 27 #include <gdk/gdkkeysyms.h> 28 #include "mn-util.h" 29 #include "mn-shell.h" 30 #include "mn-stock.h" 31 #include "mn-mailbox-properties-dialog.h" 32 #include "mn-conf.h" 33 #include "mn-mailbox.h" 34 #include "nautilus-cell-renderer-pixbuf-emblem.h" 35 #include "mn-test-mailbox.h" 36 37 enum 38 { 39 COLUMN_MAILBOX, 40 COLUMN_ICON, 41 COLUMN_EMBLEM, 42 COLUMN_PIXBUF, 43 COLUMN_LABEL, 44 COLUMN_RAW_LABEL, 45 N_COLUMNS 46 }; 47 48 enum 49 { 50 TARGET_MAILBOXES, 51 TARGET_GNOME_COPIED_FILES, 52 N_TARGETS 53 }; 54 55 typedef struct 56 { 57 gboolean has_manually_checkable; 58 gboolean has_selection; 59 } SensitivityInfo; 60 61 static struct 62 { 63 char *name; 64 GdkAtom atom; 65 } clipboard_info[N_TARGETS] = { 66 { "x-special/mail-notification-mailboxes" }, 67 { "x-special/gnome-copied-files" } 68 }; 69 70 static GtkClipboard *global_clipboard; 71 %} 72 73 class MN:Mailbox:View from Gtk:Tree:View 74 { 75 private GtkWidget *menu = {gtk_menu_new()} destroywith gtk_widget_destroy; 76 private GtkWidget *properties_item; 77 private GtkWidget *update_item; 78 private GtkWidget *remove_item; 79 private GtkWidget *cut_item; 80 private GtkWidget *copy_item; 81 private GtkWidget *paste_item; 82 private GtkWidget *select_all_item; 83 84 signal (ACTION) NONE (NONE) 85 void activate_update (self) 86 { 87 GtkTreeSelection *selection; 88 89 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); 90 gtk_tree_selection_selected_foreach(selection, self_activate_update_cb, self); 91 } 92 93 private void 94 activate_update_cb (GtkTreeModel *model, 95 GtkTreePath *path, 96 GtkTreeIter *iter, 97 gpointer data) 98 { 99 MNMailbox *mailbox; 100 101 gtk_tree_model_get(model, iter, COLUMN_MAILBOX, &mailbox, -1); 102 if (mn_mailbox_get_manually_checkable(mailbox)) 103 mn_mailbox_check(mailbox); 104 g_object_unref(mailbox); 105 } 106 107 signal (ACTION) NONE (NONE) 108 void activate_properties (self) 109 { 110 GtkTreeSelection *selection; 111 112 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); 113 gtk_tree_selection_selected_foreach(selection, self_activate_properties_cb, self); 114 } 115 116 private void 117 activate_properties_cb (GtkTreeModel *model, 118 GtkTreePath *path, 119 GtkTreeIter *iter, 120 gpointer data) 121 { 122 Self *self = data; 123 MNMailbox *mailbox; 124 GtkWidget *dialog; 125 126 gtk_tree_model_get(model, iter, COLUMN_MAILBOX, &mailbox, -1); 127 128 dialog = (GtkWidget *) mn_shell_get_mailbox_properties_dialog(mn_shell, mailbox); 129 if (dialog) 130 mn_window_present_from_event(GTK_WINDOW(dialog)); 131 else 132 { 133 dialog = mn_mailbox_properties_dialog_new(mn_widget_get_parent_window(GTK_WIDGET(self)), mailbox); 134 135 g_signal_connect(dialog, 136 "response", 137 G_CALLBACK(self_properties_edit_response_h), 138 NULL); 139 140 mn_shell_add_mailbox_properties_dialog(mn_shell, MN_MAILBOX_PROPERTIES_DIALOG(dialog)); 141 gtk_widget_show(dialog); 142 } 143 144 g_object_unref(mailbox); 145 } 146 147 signal (ACTION) NONE (NONE) 148 void activate_add (self) 149 { 150 GtkWidget *dialog; 151 152 dialog = mn_mailbox_properties_dialog_new(mn_widget_get_parent_window(GTK_WIDGET(self)), NULL); 153 154 g_signal_connect(dialog, 155 "response", 156 G_CALLBACK(self_properties_add_response_h), 157 NULL); 158 159 gtk_widget_show(dialog); 160 } 161 162 signal (ACTION) NONE (NONE) 163 void activate_remove (self) 164 { 165 self_remove_mailbox(self); 166 } 167 168 signal (ACTION) NONE (NONE) 169 void activate_cut (self) 170 { 171 self_copy_mailbox(self); 172 self_remove_mailbox(self); 173 } 174 175 signal (ACTION) NONE (NONE) 176 void activate_copy (self) 177 { 178 self_copy_mailbox(self); 179 } 180 181 signal (ACTION) NONE (NONE) 182 void activate_paste (self) 183 { 184 GtkSelectionData *data; 185 186 data = gtk_clipboard_wait_for_contents(global_clipboard, clipboard_info[TARGET_MAILBOXES].atom); 187 if (data) 188 { 189 GSList *configurations; 190 GSList *l; 191 192 memcpy(&configurations, data->data, data->length); 193 194 MN_LIST_FOREACH(l, configurations) 195 { 196 MNMailbox *mailbox; 197 198 mailbox = mn_mailbox_new_from_configuration(l->data); 199 200 mn_mailbox_seal(mailbox); 201 mn_mailboxes_queue_add(mn_shell->mailboxes, mailbox); 202 203 g_object_unref(mailbox); 204 } 205 206 gtk_selection_data_free(data); 207 return; 208 } 209 210 data = gtk_clipboard_wait_for_contents(global_clipboard, clipboard_info[TARGET_GNOME_COPIED_FILES].atom); 211 if (data) 212 { 213 if (data->format == 8 && data->length > 0) 214 { 215 char *gnome_copied_files; 216 gboolean status; 217 MNGnomeCopiedFilesType type; 218 GSList *uri_list; 219 220 gnome_copied_files = g_strndup(data->data, data->length); 221 status = mn_parse_gnome_copied_files(gnome_copied_files, &type, &uri_list); 222 g_free(gnome_copied_files); 223 224 if (status) 225 { 226 if (type == MN_GNOME_COPIED_FILES_COPY) 227 { 228 GSList *l; 229 GSList *invalid_uri_list = NULL; 230 231 MN_LIST_FOREACH(l, uri_list) 232 { 233 const char *uri = l->data; 234 MNMailbox *mailbox; 235 236 mailbox = mn_mailbox_new_from_uri(uri); 237 if (mailbox) 238 { 239 mn_mailbox_seal(mailbox); 240 mn_mailboxes_queue_add(mn_shell->mailboxes, mailbox); 241 g_object_unref(mailbox); 242 } 243 else 244 invalid_uri_list = g_slist_append(invalid_uri_list, (gpointer) uri); 245 } 246 247 if (invalid_uri_list) 248 { 249 mn_show_invalid_uri_list_dialog(mn_widget_get_parent_window(GTK_WIDGET(self)), _("A paste error has occurred"), invalid_uri_list); 250 g_slist_free(invalid_uri_list); 251 } 252 } 253 254 mn_g_slist_free_deep(uri_list); 255 } 256 } 257 258 gtk_selection_data_free(data); 259 } 260 } 261 262 class_init (class) 263 { 264 GtkBindingSet *binding_set; 265 int i; 266 267 global_clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); 268 269 for (i = 0; i < N_TARGETS; i++) 270 clipboard_info[i].atom = gdk_atom_intern(clipboard_info[i].name, FALSE); 271 272 binding_set = gtk_binding_set_by_class(class); 273 274 /* Delete removes a row */ 275 gtk_binding_entry_add_signal(binding_set, GDK_Delete, 0, "activate-remove", 0); 276 gtk_binding_entry_add_signal(binding_set, GDK_KP_Delete, 0, "activate-remove", 0); 277 278 /* HIG 2.0 cut/copy/paste shortcuts */ 279 gtk_binding_entry_add_signal(binding_set, GDK_x, GDK_CONTROL_MASK, "activate-cut", 0); 280 gtk_binding_entry_add_signal(binding_set, GDK_c, GDK_CONTROL_MASK, "activate-copy", 0); 281 gtk_binding_entry_add_signal(binding_set, GDK_v, GDK_CONTROL_MASK, "activate-paste", 0); 282 283 /* cut/copy/paste shortcuts taken from gtkentry.c */ 284 gtk_binding_entry_add_signal(binding_set, GDK_Delete, GDK_SHIFT_MASK, "activate-cut", 0); 285 gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_CONTROL_MASK, "activate-copy", 0); 286 gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_SHIFT_MASK, "activate-paste", 0); 287 288 /* HIG 2.0 properties */ 289 gtk_binding_entry_add_signal(binding_set, GDK_Return, GDK_MOD1_MASK, "activate-properties", 0); 290 gtk_binding_entry_add_signal(binding_set, GDK_ISO_Enter, GDK_MOD1_MASK, "activate-properties", 0); 291 gtk_binding_entry_add_signal(binding_set, GDK_KP_Enter, GDK_MOD1_MASK, "activate-properties", 0); 292 } 293 294 init (self) 295 { 296 GtkMenuShell *shell; 297 GtkWidget *add_item; 298 GtkListStore *store; 299 GtkTreeViewColumn *column; 300 GtkCellRenderer *renderer; 301 GtkTreeSelection *selection; 302 GList *l; 303 304 /* popup menu */ 305 306 shell = GTK_MENU_SHELL(selfp->menu); 307 308 /* ordered according to chapter 4 of the HIG */ 309 310 selfp->properties_item = mn_menu_shell_append(shell, GTK_STOCK_PROPERTIES, NULL); 311 /* translators: header capitalization */ 312 selfp->update_item = mn_menu_shell_append(shell, GTK_STOCK_REFRESH, _("_Update")); 313 mn_menu_shell_append(shell, NULL, NULL); 314 add_item = mn_menu_shell_append(shell, GTK_STOCK_ADD, NULL); 315 selfp->remove_item = mn_menu_shell_append(shell, GTK_STOCK_REMOVE, NULL); 316 mn_menu_shell_append(shell, NULL, NULL); 317 selfp->cut_item = mn_menu_shell_append(shell, GTK_STOCK_CUT, NULL); 318 selfp->copy_item = mn_menu_shell_append(shell, GTK_STOCK_COPY, NULL); 319 selfp->paste_item = mn_menu_shell_append(shell, GTK_STOCK_PASTE, NULL); 320 mn_menu_shell_append(shell, NULL, NULL); 321 selfp->select_all_item = mn_menu_shell_append(shell, GTK_STOCK_SELECT_ALL, NULL); 322 323 g_signal_connect_swapped(selfp->properties_item, "activate", G_CALLBACK(self_activate_properties), self); 324 g_signal_connect_swapped(selfp->update_item, "activate", G_CALLBACK(self_activate_update), self); 325 g_signal_connect_swapped(add_item, "activate", G_CALLBACK(self_activate_add), self); 326 g_signal_connect_swapped(selfp->remove_item, "activate", G_CALLBACK(self_activate_remove), self); 327 g_signal_connect_swapped(selfp->cut_item, "activate", G_CALLBACK(self_activate_cut), self); 328 g_signal_connect_swapped(selfp->copy_item, "activate", G_CALLBACK(self_activate_copy), self); 329 g_signal_connect_swapped(selfp->paste_item, "activate", G_CALLBACK(self_activate_paste), self); 330 g_signal_connect_swapped(selfp->select_all_item, "activate", G_CALLBACK(self_select_all), self); 331 332 /* store */ 333 334 store = gtk_list_store_new(N_COLUMNS, 335 MN_TYPE_MAILBOX, 336 G_TYPE_STRING, 337 GDK_TYPE_PIXBUF, 338 GDK_TYPE_PIXBUF, 339 G_TYPE_STRING, 340 G_TYPE_STRING); 341 342 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), 343 self_sort_cb, 344 NULL, 345 NULL); 346 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 347 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, 348 GTK_SORT_ASCENDING); 349 350 gtk_tree_view_set_model(GTK_TREE_VIEW(self), GTK_TREE_MODEL(store)); 351 352 column = gtk_tree_view_column_new(); 353 354 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); 355 356 renderer = nautilus_cell_renderer_pixbuf_emblem_new(); 357 g_object_set(renderer, "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL); 358 gtk_tree_view_column_pack_start(column, renderer, FALSE); 359 gtk_tree_view_column_set_attributes(column, renderer, 360 "stock-id", COLUMN_ICON, 361 "pixbuf-emblem", COLUMN_EMBLEM, 362 "pixbuf", COLUMN_PIXBUF, 363 NULL); 364 365 renderer = gtk_cell_renderer_text_new(); 366 gtk_tree_view_column_pack_start(column, renderer, TRUE); 367 gtk_tree_view_column_add_attribute(column, renderer, "markup", COLUMN_LABEL); 368 369 gtk_tree_view_append_column(GTK_TREE_VIEW(self), column); 370 371 /* misc */ 372 373 gtk_tree_view_set_search_column(GTK_TREE_VIEW(self), COLUMN_RAW_LABEL); 374 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(self), self_search_equal_cb, NULL, NULL); 375 376 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(self), FALSE); 377 378 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); 379 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); 380 381 MN_LIST_FOREACH(l, mn_shell->mailboxes->list) 382 { 383 MNMailbox *mailbox = l->data; 384 385 if (! MN_IS_TEST_MAILBOX(mailbox)) 386 self_append(self, l->data); 387 } 388 389 self_update_sensitivity(self); 390 391 g_object_connect(store, 392 /* for the sensitivity of "Select All" */ 393 "swapped-signal::row-inserted", self_update_sensitivity, self, 394 "swapped-signal::row-deleted", self_update_sensitivity, self, 395 NULL); 396 397 mn_g_object_connect(self, 398 mn_shell->mailboxes, 399 "signal::mailbox-added", self_mailbox_added_h, self, 400 "signal::mailbox-notify::stock-id", self_mailbox_notify_h, self, 401 "swapped-signal::mailbox-notify::manually-checkable", self_update_sensitivity, self, 402 "signal::mailbox-notify::format", self_mailbox_notify_h, self, 403 "signal::mailbox-notify::error", self_mailbox_notify_h, self, 404 "signal::mailbox-removed", self_mailbox_removed_h, self, 405 NULL); 406 407 g_signal_connect_swapped(selection, "changed", G_CALLBACK(self_update_sensitivity), self); 408 409 g_object_connect(self, 410 "signal::popup-menu", self_popup_menu_h, NULL, 411 "signal::button-press-event", self_button_press_event_h, NULL, 412 "signal::row-activated", self_row_activated_h, NULL, 413 NULL); 414 415 g_object_unref(store); 416 } 417 418 private int 419 sort_cb (GtkTreeModel *model, 420 GtkTreeIter *a, 421 GtkTreeIter *b, 422 gpointer user_data) 423 { 424 MNMailbox *mailbox_a; 425 MNMailbox *mailbox_b; 426 int cmp; 427 428 gtk_tree_model_get(model, a, COLUMN_MAILBOX, &mailbox_a, -1); 429 gtk_tree_model_get(model, b, COLUMN_MAILBOX, &mailbox_b, -1); 430 431 cmp = mn_mailboxes_compare_by_name_func(mailbox_a, mailbox_b); 432 433 g_object_unref(mailbox_a); 434 g_object_unref(mailbox_b); 435 436 return cmp; 437 } 438 439 private gboolean 440 search_equal_cb (GtkTreeModel *model, 441 int column, 442 const char *key, 443 GtkTreeIter *iter, 444 gpointer search_data) 445 { 446 gboolean status = TRUE; 447 GValue value = { 0, }; 448 GValue transformed = { 0, }; 449 const char *str; 450 char *normalized_string; 451 char *normalized_key; 452 453 /* 454 * The stock gtk_tree_view_search_equal_func() only searches the 455 * start of the string, using strncmp(). We use strstr(), to 456 * search anywhere inside the string. 457 */ 458 459 gtk_tree_model_get_value(model, iter, column, &value); 460 461 g_value_init(&transformed, G_TYPE_STRING); 462 463 if (! g_value_transform(&value, &transformed)) 464 { 465 g_value_unset(&value); 466 return TRUE; 467 } 468 469 g_value_unset(&value); 470 471 str = g_value_get_string(&transformed); 472 if (! str) 473 { 474 g_value_unset(&transformed); 475 return TRUE; 476 } 477 478 normalized_string = g_utf8_normalize(str, -1, G_NORMALIZE_ALL); 479 normalized_key = g_utf8_normalize(key, -1, G_NORMALIZE_ALL); 480 481 if (normalized_string && normalized_key) 482 { 483 char *case_normalized_string; 484 char *case_normalized_key; 485 486 case_normalized_string = g_utf8_casefold(normalized_string, -1); 487 case_normalized_key = g_utf8_casefold(normalized_key, -1); 488 489 if (strstr(case_normalized_string, case_normalized_key)) 490 status = FALSE; 491 492 g_free(case_normalized_string); 493 g_free(case_normalized_key); 494 } 495 496 g_value_unset (&transformed); 497 g_free(normalized_key); 498 g_free(normalized_string); 499 500 return status; 501 } 502 503 private void 504 append (self, MN:Mailbox *mailbox (check null type)) 505 { 506 GtkTreeModel *model; 507 GtkTreeIter iter; 508 509 model = gtk_tree_view_get_model(GTK_TREE_VIEW(self)); 510 gtk_list_store_append(GTK_LIST_STORE(model), &iter); 511 self_update_iter(self, &iter, mailbox); 512 } 513 514 private void 515 mailbox_added_h (MNMailboxes *mailboxes, 516 MNMailbox *mailbox, 517 gpointer user_data) 518 { 519 Self *self = user_data; 520 521 if (! MN_IS_TEST_MAILBOX(mailbox)) 522 self_append(self, mailbox); 523 } 524 525 private void 526 mailbox_notify_h (MNMailboxes *mailboxes, 527 MNMailbox *mailbox, 528 GParamSpec *pspec, 529 gpointer user_data) 530 { 531 Self *self = user_data; 532 GtkTreeIter iter; 533 534 if (self_find_mailbox(self, mailbox, &iter)) 535 self_update_iter(self, &iter, mailbox); 536 } 537 538 private void 539 mailbox_removed_h (MNMailboxes *mailboxes, 540 MNMailbox *mailbox, 541 gpointer user_data) 542 { 543 Self *self = user_data; 544 GtkTreeIter iter; 545 546 if (self_find_mailbox(self, mailbox, &iter)) 547 { 548 GtkTreeModel *model; 549 550 model = gtk_tree_view_get_model(GTK_TREE_VIEW(self)); 551 gtk_list_store_remove(GTK_LIST_STORE(model), &iter); 552 } 553 } 554 555 private void 556 update_iter (self, 557 GtkTreeIter *iter (check null), 558 MN:Mailbox *mailbox (check null type)) 559 { 560 GtkTreeModel *model; 561 char *status; 562 const char *emblem_stock_id = NULL; 563 GdkPixbuf *emblem = NULL; 564 char *markup; 565 char *text; 566 567 if (mailbox->format) 568 { 569 if (mailbox->error) 570 { 571 status = g_strdup_printf(_("unhandled %s mailbox (%s)"), mailbox->format, mailbox->error); 572 emblem_stock_id = MN_STOCK_ERROR; 573 } 574 else 575 status = g_strdup_printf(_("%s mailbox"), mailbox->format); 576 } 577 else 578 { 579 if (mailbox->error) 580 { 581 status = g_strdup(mailbox->error); 582 emblem_stock_id = MN_STOCK_ERROR; 583 } 584 else 585 { 586 status = g_strdup(_("detecting mailbox type...")); 587 emblem_stock_id = GTK_STOCK_EXECUTE; 588 } 589 } 590 591 if (emblem_stock_id) 592 emblem = gtk_widget_render_icon(GTK_WIDGET(self), 593 emblem_stock_id, 594 GTK_ICON_SIZE_MENU, 595 NULL); 596 597 markup = g_markup_printf_escaped("<span weight=\"bold\">%s</span>\n%s", 598 mailbox->runtime_name, 599 status); 600 text = g_strdup_printf("%s\n%s", mailbox->runtime_name, status); 601 g_free(status); 602 603 model = gtk_tree_view_get_model(GTK_TREE_VIEW(self)); 604 gtk_list_store_set(GTK_LIST_STORE(model), iter, 605 COLUMN_MAILBOX, mailbox, 606 COLUMN_ICON, mailbox->stock_id, 607 COLUMN_EMBLEM, emblem, 608 COLUMN_PIXBUF, NULL, 609 COLUMN_LABEL, markup, 610 COLUMN_RAW_LABEL, text, 611 -1); 612 613 if (emblem) 614 g_object_unref(emblem); 615 616 g_free(markup); 617 g_free(text); 618 } 619 620 private gboolean 621 find_mailbox (self, 622 MN:Mailbox *mailbox (check null type), 623 GtkTreeIter *iter (check null)) 624 { 625 GtkTreeModel *model; 626 GtkTreeIter our_iter; 627 gboolean valid; 628 629 model = gtk_tree_view_get_model(GTK_TREE_VIEW(self)); 630 631 MN_TREE_MODEL_FOREACH(valid, &our_iter, model) 632 { 633 MNMailbox *this_mailbox; 634 gboolean is; 635 636 gtk_tree_model_get(model, &our_iter, COLUMN_MAILBOX, &this_mailbox, -1); 637 is = mailbox == this_mailbox; 638 g_object_unref(this_mailbox); 639 640 if (is) 641 { 642 *iter = our_iter; 643 return TRUE; 644 } 645 } 646 647 return FALSE; 648 } 649 650 private void 651 update_sensitivity (self) 652 { 653 GtkTreeSelection *selection; 654 SensitivityInfo info = { FALSE, FALSE }; 655 GtkTreeModel *model; 656 GtkTreeIter iter; 657 gboolean has_mailboxes; 658 659 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); 660 gtk_tree_selection_selected_foreach(selection, self_update_sensitivity_cb, &info); 661 662 model = gtk_tree_view_get_model(GTK_TREE_VIEW(self)); 663 has_mailboxes = gtk_tree_model_get_iter_first(model, &iter); 664 665 gtk_widget_set_sensitive(selfp->properties_item, info.has_selection); 666 gtk_widget_set_sensitive(selfp->update_item, info.has_manually_checkable); 667 gtk_widget_set_sensitive(selfp->remove_item, info.has_selection); 668 gtk_widget_set_sensitive(selfp->cut_item, info.has_selection); 669 gtk_widget_set_sensitive(selfp->copy_item, info.has_selection); 670 gtk_widget_set_sensitive(selfp->select_all_item, has_mailboxes); 671 } 672 673 private void 674 update_sensitivity_cb (GtkTreeModel *model, 675 GtkTreePath *path, 676 GtkTreeIter *iter, 677 gpointer data) 678 { 679 SensitivityInfo *info = data; 680 681 info->has_selection = TRUE; 682 if (! info->has_manually_checkable) 683 { 684 MNMailbox *mailbox; 685 686 gtk_tree_model_get(model, iter, COLUMN_MAILBOX, &mailbox, -1); 687 if (mn_mailbox_get_manually_checkable(mailbox)) 688 info->has_manually_checkable = TRUE; 689 g_object_unref(mailbox); 690 } 691 } 692 693 private void 694 remove_mailbox (self) 695 { 696 GtkTreeSelection *selection; 697 698 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); 699 gtk_tree_selection_selected_foreach(selection, self_remove_mailbox_cb, NULL); 700 } 701 702 private void 703 remove_mailbox_cb (GtkTreeModel *model, 704 GtkTreePath *path, 705 GtkTreeIter *iter, 706 gpointer data) 707 { 708 MNMailbox *mailbox; 709 710 gtk_tree_model_get(model, iter, COLUMN_MAILBOX, &mailbox, -1); 711 mn_mailboxes_queue_remove(mn_shell->mailboxes, mailbox); 712 g_object_unref(mailbox); 713 } 714 715 private void 716 copy_mailbox (self) 717 { 718 GSList *configurations = NULL; 719 GtkTreeSelection *selection; 720 const GtkTargetEntry targets[] = { 721 { clipboard_info[TARGET_MAILBOXES].name, 0, TARGET_MAILBOXES } 722 }; 723 gboolean status; 724 725 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); 726 gtk_tree_selection_selected_foreach(selection, self_copy_mailbox_cb, &configurations); 727 728 status = gtk_clipboard_set_with_data(global_clipboard, 729 targets, 730 G_N_ELEMENTS(targets), 731 self_get_clipboard_cb, 732 self_clear_clipboard_cb, 733 configurations); 734 g_assert(status == TRUE); 735 } 736 737 private void 738 copy_mailbox_cb (GtkTreeModel *model, 739 GtkTreePath *path, 740 GtkTreeIter *iter, 741 gpointer data) 742 { 743 GSList **configurations = data; 744 MNMailbox *mailbox; 745 746 /* 747 * Note that the MNMailboxConfiguration object returned by 748 * mn_mailbox_get_configuration() does not include the keyring 749 * password. This is not a problem unless the user copies a 750 * mailbox, removes the password from the keyring and then pastes 751 * the mailbox: the pasted mailbox will have no password. 752 * 753 * Including the password in MNMailboxConfiguration would require 754 * to cope with the fact that gnome-keyring requests can block the 755 * UI. It's really not worth the effort. 756 */ 757 758 gtk_tree_model_get(model, iter, COLUMN_MAILBOX, &mailbox, -1); 759 *configurations = g_slist_append(*configurations, mn_mailbox_get_configuration(mailbox)); 760 g_object_unref(mailbox); 761 } 762 763 private void 764 get_clipboard_cb (GtkClipboard *clipboard, 765 GtkSelectionData *selection_data, 766 unsigned int info, 767 gpointer user_data_or_owner) 768 { 769 GSList *configurations = user_data_or_owner; 770 771 g_assert(info == TARGET_MAILBOXES); 772 773 gtk_selection_data_set(selection_data, 774 clipboard_info[info].atom, 775 8, 776 (unsigned char *) &configurations, 777 sizeof(configurations)); 778 } 779 780 private void 781 clear_clipboard_cb (GtkClipboard *clipboard, gpointer user_data_or_owner) 782 { 783 GSList *configurations = user_data_or_owner; 784 785 mn_g_slist_free_deep_custom(configurations, (GFunc) mn_mailbox_configuration_free, NULL); 786 } 787 788 private void 789 select_all (self) 790 { 791 GtkTreeSelection *selection; 792 793 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self)); 794 gtk_tree_selection_select_all(selection); 795 } 796 797 private void 798 properties_add_response_h (GtkDialog *dialog, 799 int response, 800 gpointer user_data) 801 { 802 switch (response) 803 { 804 case GTK_RESPONSE_CANCEL: 805 gtk_widget_destroy(GTK_WIDGET(dialog)); 806 break; 807 808 case GTK_RESPONSE_ACCEPT: 809 { 810 MNMailbox *mailbox; 811 812 mailbox = mn_mailbox_properties_dialog_get_current_mailbox(MN_MAILBOX_PROPERTIES_DIALOG(dialog)); 813 g_assert(MN_IS_MAILBOX(mailbox)); 814 815 mn_mailbox_seal(mailbox); 816 mn_mailboxes_add(mn_shell->mailboxes, mailbox); 817 g_object_unref(mailbox); 818 819 gtk_widget_destroy(GTK_WIDGET(dialog)); 820 } 821 break; 822 } 823 } 824 825 private void 826 properties_edit_response_h (GtkDialog *dialog, 827 int response, 828 gpointer user_data) 829 { 830 switch (response) 831 { 832 case GTK_RESPONSE_APPLY: 833 mn_mailbox_properties_dialog_apply(MN_MAILBOX_PROPERTIES_DIALOG(dialog)); 834 break; 835 836 case GTK_RESPONSE_CANCEL: 837 mn_mailbox_properties_dialog_cancel(MN_MAILBOX_PROPERTIES_DIALOG(dialog)); 838 gtk_widget_destroy(GTK_WIDGET(dialog)); 839 break; 840 841 case GTK_RESPONSE_OK: 842 mn_mailbox_properties_dialog_apply(MN_MAILBOX_PROPERTIES_DIALOG(dialog)); 843 gtk_widget_destroy(GTK_WIDGET(dialog)); 844 break; 845 } 846 } 847 848 private void 849 popup_menu (self, unsigned int button, guint32 activate_time) 850 { 851 Self **self_box; 852 853 gtk_widget_set_sensitive(selfp->paste_item, FALSE); 854 855 /* do not crash if self is finalized before the request completes */ 856 self_box = g_new(Self *, 1); 857 *self_box = self; 858 mn_add_weak_pointer(self_box); 859 860 gtk_clipboard_request_targets(global_clipboard, self_popup_menu_targets_received_cb, self_box); 861 862 gtk_menu_popup(GTK_MENU(selfp->menu), NULL, NULL, NULL, NULL, button, activate_time); 863 } 864 865 private gboolean 866 can_paste (GdkAtom *atoms, int n_atoms) 867 { 868 int i; 869 870 for (i = 0; i < n_atoms; i++) 871 if (atoms[i] == clipboard_info[TARGET_MAILBOXES].atom 872 || atoms[i] == clipboard_info[TARGET_GNOME_COPIED_FILES].atom) 873 return TRUE; 874 875 return FALSE; 876 } 877 878 private void 879 popup_menu_targets_received_cb (GtkClipboard *clipboard, 880 GdkAtom *atoms, 881 int n_atoms, 882 gpointer data) 883 { 884 Self **self_box = data; 885 Self *self = *self_box; 886 887 if (self) 888 { 889 if (atoms) 890 gtk_widget_set_sensitive(selfp->paste_item, self_can_paste(atoms, n_atoms)); 891 892 mn_remove_weak_pointer(self_box); 893 } 894 895 g_free(self_box); 896 } 897 898 private gboolean 899 popup_menu_h (GtkWidget *widget, gpointer user_data) 900 { 901 Self *self = SELF(widget); 902 903 self_popup_menu(self, 0, gtk_get_current_event_time()); 904 gtk_menu_shell_select_first(GTK_MENU_SHELL(selfp->menu), FALSE); 905 906 return TRUE; /* a menu was activated */ 907 } 908 909 private gboolean 910 button_press_event_h (GtkWidget *widget, 911 GdkEventButton *event, 912 gpointer user_data) 913 { 914 if (event->button == 3) 915 self_popup_menu(SELF(widget), event->button, event->time); 916 917 return FALSE; /* propagate event */ 918 } 919 920 private void 921 row_activated_h (GtkTreeView *treeview, 922 GtkTreePath *path, 923 GtkTreeViewColumn *column, 924 gpointer user_data) 925 { 926 self_activate_properties(SELF(treeview)); 927 } 928 929 public GtkWidget * 930 new (void) 931 { 932 g_return_val_if_fail(mn_shell != NULL, NULL); 933 return GTK_WIDGET(GET_NEW); 934 } 935 }