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 }