2 * em-subscription-editor.c
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-config.h"
21 #include <glib/gi18n-lib.h>
23 #include <e-util/e-util.h>
25 #include "em-folder-utils.h"
26 #include "em-subscription-editor.h"
28 #define EM_SUBSCRIPTION_EDITOR_GET_PRIVATE(obj) \
29 (G_TYPE_INSTANCE_GET_PRIVATE \
30 ((obj), EM_TYPE_SUBSCRIPTION_EDITOR, EMSubscriptionEditorPrivate))
32 #define FOLDER_CAN_SELECT(folder_info) \
33 ((folder_info) != NULL && \
34 ((folder_info)->flags & CAMEL_FOLDER_NOSELECT) == 0)
35 #define FOLDER_SUBSCRIBED(folder_info) \
36 ((folder_info) != NULL && \
37 ((folder_info)->flags & CAMEL_FOLDER_SUBSCRIBED) != 0)
39 typedef struct _AsyncContext AsyncContext
;
40 typedef struct _TreeRowData TreeRowData
;
41 typedef struct _StoreData StoreData
;
43 struct _EMSubscriptionEditorPrivate
{
44 EMailSession
*session
;
45 CamelStore
*initial_store
;
47 GtkWidget
*combo_box
; /* not referenced */
48 GtkWidget
*entry
; /* not referenced */
49 GtkWidget
*notebook
; /* not referenced */
50 GtkWidget
*subscribe_button
; /* not referenced */
51 GtkWidget
*subscribe_arrow
; /* not referenced */
52 GtkWidget
*unsubscribe_button
; /* not referenced */
53 GtkWidget
*unsubscribe_arrow
; /* not referenced */
54 GtkWidget
*collapse_all_button
; /* not referenced */
55 GtkWidget
*expand_all_button
; /* not referenced */
56 GtkWidget
*refresh_button
; /* not referenced */
57 GtkWidget
*stop_button
; /* not referenced */
59 /* Indicies coincide with the combo box. */
62 /* Points at an item in the stores array. */
65 /* Casefolded search string. */
72 CamelFolderInfo
*folder_info
;
73 GtkTreeRowReference
*reference
;
76 struct _AsyncContext
{
77 EMSubscriptionEditor
*editor
;
83 GtkTreeView
*tree_view
;
84 GtkTreeModel
*list_store
;
85 GtkTreeModel
*tree_store
;
86 GCancellable
*cancellable
;
87 CamelFolderInfo
*folder_info
;
88 gboolean filtered_view
;
89 gboolean needs_refresh
;
99 COL_CASEFOLDED
, /* G_TYPE_STRING */
100 COL_FOLDER_NAME
, /* G_TYPE_STRING */
101 COL_FOLDER_ICON
, /* G_TYPE_STRING */
102 COL_FOLDER_INFO
, /* G_TYPE_POINTER */
106 G_DEFINE_TYPE (EMSubscriptionEditor
, em_subscription_editor
, GTK_TYPE_DIALOG
)
109 tree_row_data_free (TreeRowData
*tree_row_data
)
111 g_return_if_fail (tree_row_data
!= NULL
);
113 gtk_tree_row_reference_free (tree_row_data
->reference
);
114 g_slice_free (TreeRowData
, tree_row_data
);
117 static AsyncContext
*
118 async_context_new (EMSubscriptionEditor
*editor
,
121 AsyncContext
*context
;
123 context
= g_slice_new0 (AsyncContext
);
124 context
->editor
= g_object_ref (editor
);
126 /* Transfer GQueue contents. */
127 context
->tree_rows
= g_queue_copy (tree_rows
);
128 g_queue_clear (tree_rows
);
134 async_context_free (AsyncContext
*context
)
136 while (!g_queue_is_empty (context
->tree_rows
))
137 tree_row_data_free (g_queue_pop_head (context
->tree_rows
));
139 g_object_unref (context
->editor
);
140 g_queue_free (context
->tree_rows
);
142 g_slice_free (AsyncContext
, context
);
146 store_data_free (StoreData
*data
)
148 if (data
->store
!= NULL
)
149 g_object_unref (data
->store
);
151 if (data
->tree_view
!= NULL
)
152 g_object_unref (data
->tree_view
);
154 if (data
->list_store
!= NULL
)
155 g_object_unref (data
->list_store
);
157 if (data
->tree_store
!= NULL
)
158 g_object_unref (data
->tree_store
);
160 if (data
->cancellable
!= NULL
) {
161 g_cancellable_cancel (data
->cancellable
);
162 g_object_unref (data
->cancellable
);
165 camel_folder_info_free (data
->folder_info
);
167 g_slice_free (StoreData
, data
);
171 subscription_editor_populate (EMSubscriptionEditor
*editor
,
172 CamelFolderInfo
*folder_info
,
174 GList
**expand_paths
)
176 GtkListStore
*list_store
;
177 GtkTreeStore
*tree_store
;
179 list_store
= GTK_LIST_STORE (editor
->priv
->active
->list_store
);
180 tree_store
= GTK_TREE_STORE (editor
->priv
->active
->tree_store
);
182 while (folder_info
!= NULL
) {
184 const gchar
*icon_name
;
188 em_folder_utils_get_icon_name (folder_info
->flags
);
190 casefolded
= g_utf8_casefold (folder_info
->full_name
, -1);
192 gtk_list_store_append (list_store
, &iter
);
196 COL_CASEFOLDED
, casefolded
,
197 COL_FOLDER_ICON
, icon_name
,
198 COL_FOLDER_NAME
, folder_info
->full_name
,
199 COL_FOLDER_INFO
, folder_info
, -1);
201 gtk_tree_store_append (tree_store
, &iter
, parent
);
205 COL_CASEFOLDED
, NULL
, /* not needed */
206 COL_FOLDER_ICON
, icon_name
,
207 COL_FOLDER_NAME
, folder_info
->display_name
,
208 COL_FOLDER_INFO
, folder_info
, -1);
210 if (FOLDER_SUBSCRIBED (folder_info
)) {
213 path
= gtk_tree_model_get_path (
214 GTK_TREE_MODEL (tree_store
), &iter
);
215 *expand_paths
= g_list_prepend (*expand_paths
, path
);
220 if (folder_info
->child
!= NULL
)
221 subscription_editor_populate (
222 editor
, folder_info
->child
,
223 &iter
, expand_paths
);
225 folder_info
= folder_info
->next
;
230 expand_paths_cb (gpointer path
,
233 gtk_tree_view_expand_to_path (tree_view
, path
);
237 subscription_editor_get_folder_info_done (CamelStore
*store
,
238 GAsyncResult
*result
,
239 EMSubscriptionEditor
*editor
)
242 GtkTreeView
*tree_view
;
243 GtkTreeModel
*list_store
;
244 GtkTreeModel
*tree_store
;
246 GtkTreeSelection
*selection
;
247 CamelFolderInfo
*folder_info
;
249 GList
*expand_paths
= NULL
;
250 GError
*error
= NULL
;
252 folder_info
= camel_store_get_folder_info_finish (
253 store
, result
, &error
);
255 /* Just return quietly if we were cancelled. */
256 if (g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
257 g_warn_if_fail (folder_info
== NULL
);
258 g_error_free (error
);
262 gtk_widget_set_sensitive (editor
->priv
->notebook
, TRUE
);
263 gtk_widget_set_sensitive (editor
->priv
->refresh_button
, TRUE
);
264 gtk_widget_set_sensitive (editor
->priv
->stop_button
, FALSE
);
266 window
= gtk_widget_get_window (GTK_WIDGET (editor
));
267 gdk_window_set_cursor (window
, NULL
);
269 /* XXX Do something smarter with errors. */
271 g_warn_if_fail (folder_info
== NULL
);
272 e_notice (GTK_WINDOW (editor
), GTK_MESSAGE_ERROR
, "%s", error
->message
);
273 g_error_free (error
);
277 g_return_if_fail (folder_info
!= NULL
);
279 camel_folder_info_free (editor
->priv
->active
->folder_info
);
280 editor
->priv
->active
->folder_info
= folder_info
;
282 tree_view
= editor
->priv
->active
->tree_view
;
283 list_store
= editor
->priv
->active
->list_store
;
284 tree_store
= editor
->priv
->active
->tree_store
;
286 gtk_list_store_clear (GTK_LIST_STORE (list_store
));
287 gtk_tree_store_clear (GTK_TREE_STORE (tree_store
));
289 model
= gtk_tree_view_get_model (tree_view
);
290 gtk_tree_view_set_model (tree_view
, NULL
);
291 subscription_editor_populate (editor
, folder_info
, NULL
, &expand_paths
);
292 gtk_tree_view_set_model (tree_view
, model
);
294 g_list_foreach (expand_paths
, expand_paths_cb
, tree_view
);
295 g_list_foreach (expand_paths
, (GFunc
) gtk_tree_path_free
, NULL
);
296 g_list_free (expand_paths
);
298 path
= gtk_tree_path_new_first ();
299 selection
= gtk_tree_view_get_selection (tree_view
);
300 gtk_tree_selection_select_path (selection
, path
);
301 gtk_tree_path_free (path
);
303 gtk_widget_grab_focus (GTK_WIDGET (tree_view
));
306 g_object_unref (editor
);
310 subscription_editor_subscribe_folder_done (CamelSubscribable
*subscribable
,
311 GAsyncResult
*result
,
312 AsyncContext
*context
)
314 GtkTreeView
*tree_view
;
315 GtkTreeModel
*tree_model
;
316 GtkTreeSelection
*selection
;
320 GError
*error
= NULL
;
321 TreeRowData
*tree_row_data
;
323 camel_subscribable_subscribe_folder_finish (
324 subscribable
, result
, &error
);
326 /* Just return quietly if we were cancelled. */
327 if (g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
328 g_error_free (error
);
332 tree_row_data
= g_queue_pop_head (context
->tree_rows
);
334 /* XXX Do something smarter with errors. */
336 tree_row_data
->folder_info
->flags
|= CAMEL_FOLDER_SUBSCRIBED
;
339 GTK_WINDOW (context
->editor
),
340 GTK_MESSAGE_ERROR
, "%s", error
->message
);
341 g_error_free (error
);
342 tree_row_data_free (tree_row_data
);
346 /* Update the toggle renderer in the selected row. */
347 tree_model
= gtk_tree_row_reference_get_model (tree_row_data
->reference
);
348 path
= gtk_tree_row_reference_get_path (tree_row_data
->reference
);
349 gtk_tree_model_get_iter (tree_model
, &iter
, path
);
350 gtk_tree_model_row_changed (tree_model
, path
, &iter
);
351 gtk_tree_path_free (path
);
353 tree_row_data_free (tree_row_data
);
355 if (!g_queue_is_empty (context
->tree_rows
)) {
356 GCancellable
*cancellable
;
358 /* continue with the next to subscribe */
359 tree_row_data
= g_queue_peek_head (context
->tree_rows
);
360 g_return_if_fail (tree_row_data
!= NULL
);
362 cancellable
= context
->editor
->priv
->active
->cancellable
;
364 camel_subscribable_subscribe_folder (
365 subscribable
, tree_row_data
->folder_info
->full_name
,
366 G_PRIORITY_DEFAULT
, cancellable
, (GAsyncReadyCallback
)
367 subscription_editor_subscribe_folder_done
, context
);
372 gtk_widget_set_sensitive (context
->editor
->priv
->notebook
, TRUE
);
373 gtk_widget_set_sensitive (context
->editor
->priv
->refresh_button
, TRUE
);
374 gtk_widget_set_sensitive (context
->editor
->priv
->stop_button
, FALSE
);
376 window
= gtk_widget_get_window (GTK_WIDGET (context
->editor
));
377 gdk_window_set_cursor (window
, NULL
);
379 /* Update the Subscription/Unsubscription buttons. */
380 tree_view
= context
->editor
->priv
->active
->tree_view
;
381 selection
= gtk_tree_view_get_selection (tree_view
);
382 g_signal_emit_by_name (selection
, "changed");
384 async_context_free (context
);
386 gtk_widget_grab_focus (GTK_WIDGET (tree_view
));
390 subscription_editor_subscribe_many (EMSubscriptionEditor
*editor
,
393 TreeRowData
*tree_row_data
;
394 GCancellable
*cancellable
;
395 CamelStore
*active_store
;
396 AsyncContext
*context
;
400 g_return_if_fail (editor
!= NULL
);
402 if (g_queue_is_empty (tree_rows
))
405 tree_row_data
= g_queue_peek_head (tree_rows
);
406 g_return_if_fail (tree_row_data
!= NULL
);
408 /* Cancel any operation on this store still in progress. */
409 gtk_button_clicked (GTK_BUTTON (editor
->priv
->stop_button
));
411 /* Start a new 'subscription' operation. */
412 editor
->priv
->active
->cancellable
= g_cancellable_new ();
414 gtk_widget_set_sensitive (editor
->priv
->notebook
, FALSE
);
415 gtk_widget_set_sensitive (editor
->priv
->subscribe_button
, FALSE
);
416 gtk_widget_set_sensitive (editor
->priv
->subscribe_arrow
, FALSE
);
417 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_button
, FALSE
);
418 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_arrow
, FALSE
);
419 gtk_widget_set_sensitive (editor
->priv
->refresh_button
, FALSE
);
420 gtk_widget_set_sensitive (editor
->priv
->stop_button
, TRUE
);
422 cursor
= gdk_cursor_new (GDK_WATCH
);
423 window
= gtk_widget_get_window (GTK_WIDGET (editor
));
424 gdk_window_set_cursor (window
, cursor
);
425 g_object_unref (cursor
);
427 context
= async_context_new (editor
, tree_rows
);
429 active_store
= editor
->priv
->active
->store
;
430 cancellable
= editor
->priv
->active
->cancellable
;
432 camel_subscribable_subscribe_folder (
433 CAMEL_SUBSCRIBABLE (active_store
),
434 tree_row_data
->folder_info
->full_name
,
435 G_PRIORITY_DEFAULT
, cancellable
, (GAsyncReadyCallback
)
436 subscription_editor_subscribe_folder_done
, context
);
440 subscription_editor_unsubscribe_folder_done (CamelSubscribable
*subscribable
,
441 GAsyncResult
*result
,
442 AsyncContext
*context
)
444 GtkTreeView
*tree_view
;
445 GtkTreeModel
*tree_model
;
446 GtkTreeSelection
*selection
;
450 GError
*error
= NULL
;
451 TreeRowData
*tree_row_data
;
453 camel_subscribable_unsubscribe_folder_finish (
454 subscribable
, result
, &error
);
456 /* Just return quietly if we were cancelled. */
457 if (g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
458 g_error_free (error
);
462 tree_row_data
= g_queue_pop_head (context
->tree_rows
);
464 /* XXX Do something smarter with errors. */
466 tree_row_data
->folder_info
->flags
&= ~CAMEL_FOLDER_SUBSCRIBED
;
469 GTK_WINDOW (context
->editor
),
470 GTK_MESSAGE_ERROR
, "%s", error
->message
);
471 g_error_free (error
);
472 tree_row_data_free (tree_row_data
);
476 /* Update the toggle renderer in the selected row. */
477 tree_model
= gtk_tree_row_reference_get_model (tree_row_data
->reference
);
478 path
= gtk_tree_row_reference_get_path (tree_row_data
->reference
);
479 gtk_tree_model_get_iter (tree_model
, &iter
, path
);
480 gtk_tree_model_row_changed (tree_model
, path
, &iter
);
481 gtk_tree_path_free (path
);
483 tree_row_data_free (tree_row_data
);
485 if (!g_queue_is_empty (context
->tree_rows
)) {
486 GCancellable
*cancellable
;
488 /* continue with the next to unsubscribe */
489 tree_row_data
= g_queue_peek_head (context
->tree_rows
);
490 g_return_if_fail (tree_row_data
!= NULL
);
492 cancellable
= context
->editor
->priv
->active
->cancellable
;
494 camel_subscribable_unsubscribe_folder (
495 subscribable
, tree_row_data
->folder_info
->full_name
,
496 G_PRIORITY_DEFAULT
, cancellable
, (GAsyncReadyCallback
)
497 subscription_editor_unsubscribe_folder_done
, context
);
502 gtk_widget_set_sensitive (context
->editor
->priv
->notebook
, TRUE
);
503 gtk_widget_set_sensitive (context
->editor
->priv
->refresh_button
, TRUE
);
504 gtk_widget_set_sensitive (context
->editor
->priv
->stop_button
, FALSE
);
506 window
= gtk_widget_get_window (GTK_WIDGET (context
->editor
));
507 gdk_window_set_cursor (window
, NULL
);
509 /* Update the Subscription/Unsubscription buttons. */
510 tree_view
= context
->editor
->priv
->active
->tree_view
;
511 selection
= gtk_tree_view_get_selection (tree_view
);
512 g_signal_emit_by_name (selection
, "changed");
514 async_context_free (context
);
516 gtk_widget_grab_focus (GTK_WIDGET (tree_view
));
520 subscription_editor_unsubscribe_many (EMSubscriptionEditor
*editor
,
523 TreeRowData
*tree_row_data
;
524 AsyncContext
*context
;
525 CamelStore
*active_store
;
529 g_return_if_fail (editor
!= NULL
);
531 if (g_queue_is_empty (tree_rows
))
534 tree_row_data
= g_queue_peek_head (tree_rows
);
535 g_return_if_fail (tree_row_data
!= NULL
);
537 /* Cancel any operation on this store still in progress. */
538 gtk_button_clicked (GTK_BUTTON (editor
->priv
->stop_button
));
540 /* Start a new 'subscription' operation. */
541 editor
->priv
->active
->cancellable
= g_cancellable_new ();
543 gtk_widget_set_sensitive (editor
->priv
->notebook
, FALSE
);
544 gtk_widget_set_sensitive (editor
->priv
->subscribe_button
, FALSE
);
545 gtk_widget_set_sensitive (editor
->priv
->subscribe_arrow
, FALSE
);
546 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_button
, FALSE
);
547 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_arrow
, FALSE
);
548 gtk_widget_set_sensitive (editor
->priv
->refresh_button
, FALSE
);
549 gtk_widget_set_sensitive (editor
->priv
->stop_button
, TRUE
);
551 cursor
= gdk_cursor_new (GDK_WATCH
);
552 window
= gtk_widget_get_window (GTK_WIDGET (editor
));
553 gdk_window_set_cursor (window
, cursor
);
554 g_object_unref (cursor
);
556 context
= async_context_new (editor
, tree_rows
);
558 active_store
= editor
->priv
->active
->store
;
560 camel_subscribable_unsubscribe_folder (
561 CAMEL_SUBSCRIBABLE (active_store
),
562 tree_row_data
->folder_info
->full_name
, G_PRIORITY_DEFAULT
,
563 editor
->priv
->active
->cancellable
, (GAsyncReadyCallback
)
564 subscription_editor_unsubscribe_folder_done
, context
);
568 subscription_editor_create_menu_item (const gchar
*label
,
570 GCallback activate_cb
,
571 EMSubscriptionEditor
*editor
)
575 item
= gtk_menu_item_new_with_mnemonic (label
);
576 gtk_widget_set_sensitive (item
, sensitive
);
578 gtk_widget_show (item
);
580 g_signal_connect_swapped (
581 item
, "activate", activate_cb
, editor
);
587 subscription_editor_tree_row_data_from_iter (GtkTreeView
*tree_view
,
590 gboolean
*is_expanded
)
592 TreeRowData
*tree_row_data
;
593 CamelFolderInfo
*folder_info
= NULL
;
594 GtkTreeRowReference
*reference
;
598 model
, iter
, COL_FOLDER_INFO
, &folder_info
, -1);
600 if (!FOLDER_CAN_SELECT (folder_info
))
603 path
= gtk_tree_model_get_path (model
, iter
);
604 reference
= gtk_tree_row_reference_new (model
, path
);
606 *is_expanded
= gtk_tree_view_row_expanded (tree_view
, path
);
607 gtk_tree_path_free (path
);
609 tree_row_data
= g_slice_new0 (TreeRowData
);
610 tree_row_data
->folder_info
= folder_info
;
611 tree_row_data
->reference
= reference
;
613 return tree_row_data
;
623 can_pick_folder_info (CamelFolderInfo
*fi
,
626 if (!FOLDER_CAN_SELECT (fi
))
629 if (mode
== PICK_ALL
)
632 return (FOLDER_SUBSCRIBED (fi
) ? 1 : 0) == (mode
== PICK_SUBSCRIBED
? 1 : 0);
636 GtkTreeView
*tree_view
;
638 GHashTable
*skip_folder_infos
;
639 GQueue
*out_tree_rows
;
643 pick_all_cb (GtkTreeModel
*model
,
648 struct PickAllData
*data
= user_data
;
649 TreeRowData
*tree_row_data
;
651 tree_row_data
= subscription_editor_tree_row_data_from_iter (
652 data
->tree_view
, model
, iter
, NULL
);
653 if (tree_row_data
== NULL
)
656 if (can_pick_folder_info (tree_row_data
->folder_info
, data
->mode
) &&
657 (data
->skip_folder_infos
== NULL
||
658 !g_hash_table_contains (
659 data
->skip_folder_infos
,
660 tree_row_data
->folder_info
))) {
661 g_queue_push_tail (data
->out_tree_rows
, tree_row_data
);
663 tree_row_data_free (tree_row_data
);
668 /* skip_folder_infos contains CamelFolderInfo-s to skip;
669 * these should come from the tree view; can be NULL
670 * to include everything.
673 subscription_editor_pick_all (EMSubscriptionEditor
*editor
,
675 GHashTable
*skip_folder_infos
,
676 GQueue
*out_tree_rows
)
678 GtkTreeView
*tree_view
;
679 GtkTreeModel
*tree_model
;
680 struct PickAllData data
;
682 tree_view
= editor
->priv
->active
->tree_view
;
683 tree_model
= gtk_tree_view_get_model (tree_view
);
685 data
.tree_view
= tree_view
;
687 data
.skip_folder_infos
= skip_folder_infos
;
688 data
.out_tree_rows
= out_tree_rows
;
690 gtk_tree_model_foreach (tree_model
, pick_all_cb
, &data
);
694 subscription_editor_pick_shown (EMSubscriptionEditor
*editor
,
696 GQueue
*out_tree_rows
)
698 GtkTreeView
*tree_view
;
699 GtkTreeModel
*tree_model
;
700 GtkTreeIter iter
, iter2
;
701 gboolean found
= TRUE
;
703 tree_view
= editor
->priv
->active
->tree_view
;
704 tree_model
= gtk_tree_view_get_model (tree_view
);
706 if (!gtk_tree_model_get_iter_first (tree_model
, &iter
))
710 TreeRowData
*tree_row_data
;
711 gboolean is_expanded
= FALSE
;
714 tree_row_data
= subscription_editor_tree_row_data_from_iter (
715 tree_view
, tree_model
, &iter
, &is_expanded
);
717 if (tree_row_data
!= NULL
) {
718 if (can_pick_folder_info (tree_row_data
->folder_info
, mode
))
719 g_queue_push_tail (out_tree_rows
, tree_row_data
);
721 tree_row_data_free (tree_row_data
);
724 if (is_expanded
&& gtk_tree_model_iter_children (
725 tree_model
, &iter2
, &iter
)) {
730 if (gtk_tree_model_iter_next (tree_model
, &iter2
)) {
734 while (found
= gtk_tree_model_iter_parent (
735 tree_model
, &iter2
, &iter
), found
) {
737 if (gtk_tree_model_iter_next (
738 tree_model
, &iter2
)) {
749 subscription_editor_subscribe (EMSubscriptionEditor
*editor
)
751 GtkTreeSelection
*selection
;
752 GtkTreeModel
*tree_model
;
753 GtkTreeView
*tree_view
;
755 gboolean have_selection
;
756 GQueue tree_rows
= G_QUEUE_INIT
;
757 TreeRowData
*tree_row_data
;
759 tree_view
= editor
->priv
->active
->tree_view
;
760 selection
= gtk_tree_view_get_selection (tree_view
);
762 have_selection
= gtk_tree_selection_get_selected (
763 selection
, &tree_model
, &iter
);
764 g_return_if_fail (have_selection
);
766 tree_row_data
= subscription_editor_tree_row_data_from_iter (
767 tree_view
, tree_model
, &iter
, NULL
);
769 g_queue_push_tail (&tree_rows
, tree_row_data
);
770 subscription_editor_subscribe_many (editor
, &tree_rows
);
771 g_warn_if_fail (g_queue_is_empty (&tree_rows
));
775 subscription_editor_subscribe_shown (EMSubscriptionEditor
*editor
)
777 GQueue tree_rows
= G_QUEUE_INIT
;
779 subscription_editor_pick_shown (
780 editor
, PICK_UNSUBSCRIBED
, &tree_rows
);
781 subscription_editor_subscribe_many (editor
, &tree_rows
);
785 subscription_editor_subscribe_all (EMSubscriptionEditor
*editor
)
787 GQueue tree_rows
= G_QUEUE_INIT
;
789 subscription_editor_pick_all (
790 editor
, PICK_UNSUBSCRIBED
, NULL
, &tree_rows
);
791 subscription_editor_subscribe_many (editor
, &tree_rows
);
795 subscription_editor_subscribe_popup_cb (EMSubscriptionEditor
*editor
)
799 gboolean tree_filled
;
801 tree_filled
= editor
->priv
->active
&&
802 gtk_tree_model_get_iter_first (
803 editor
->priv
->active
->filtered_view
804 ? editor
->priv
->active
->list_store
805 : editor
->priv
->active
->tree_store
,
808 menu
= gtk_menu_new ();
810 gtk_menu_shell_append (
811 GTK_MENU_SHELL (menu
),
812 subscription_editor_create_menu_item (
814 gtk_widget_get_sensitive (
815 editor
->priv
->subscribe_button
),
816 G_CALLBACK (subscription_editor_subscribe
),
819 gtk_menu_shell_append (
820 GTK_MENU_SHELL (menu
),
821 subscription_editor_create_menu_item (
822 _("Su_bscribe To Shown"),
824 G_CALLBACK (subscription_editor_subscribe_shown
),
827 gtk_menu_shell_append (
828 GTK_MENU_SHELL (menu
),
829 subscription_editor_create_menu_item (
830 _("Subscribe To _All"),
832 G_CALLBACK (subscription_editor_subscribe_all
),
835 gtk_menu_attach_to_widget (GTK_MENU (menu
), GTK_WIDGET (editor
), NULL
);
836 g_signal_connect (menu
, "deactivate", G_CALLBACK (gtk_menu_detach
), NULL
);
839 "anchor-hints", (GDK_ANCHOR_FLIP_Y
|
844 gtk_menu_popup_at_widget (GTK_MENU (menu
),
845 editor
->priv
->subscribe_button
,
846 GDK_GRAVITY_SOUTH_WEST
,
847 GDK_GRAVITY_NORTH_WEST
,
852 subscription_editor_unsubscribe_hidden (EMSubscriptionEditor
*editor
)
854 GQueue tree_rows
= G_QUEUE_INIT
;
855 GHashTable
*skip_shown
;
857 subscription_editor_pick_shown (editor
, PICK_ALL
, &tree_rows
);
858 g_return_if_fail (!g_queue_is_empty (&tree_rows
));
860 skip_shown
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
862 while (!g_queue_is_empty (&tree_rows
)) {
863 TreeRowData
*tree_row_data
;
865 tree_row_data
= g_queue_pop_head (&tree_rows
);
867 if (tree_row_data
== NULL
)
870 g_hash_table_add (skip_shown
, tree_row_data
->folder_info
);
872 tree_row_data_free (tree_row_data
);
875 subscription_editor_pick_all (
876 editor
, PICK_SUBSCRIBED
, skip_shown
, &tree_rows
);
877 subscription_editor_unsubscribe_many (editor
, &tree_rows
);
879 g_hash_table_destroy (skip_shown
);
883 subscription_editor_unsubscribe_all (EMSubscriptionEditor
*editor
)
885 GQueue tree_rows
= G_QUEUE_INIT
;
887 subscription_editor_pick_all (
888 editor
, PICK_SUBSCRIBED
, NULL
, &tree_rows
);
889 subscription_editor_unsubscribe_many (editor
, &tree_rows
);
893 subscription_editor_unsubscribe (EMSubscriptionEditor
*editor
)
895 GtkTreeSelection
*selection
;
896 GtkTreeModel
*tree_model
;
897 GtkTreeView
*tree_view
;
899 gboolean have_selection
;
900 GQueue tree_rows
= G_QUEUE_INIT
;
901 TreeRowData
*tree_row_data
;
903 tree_view
= editor
->priv
->active
->tree_view
;
904 selection
= gtk_tree_view_get_selection (tree_view
);
906 have_selection
= gtk_tree_selection_get_selected (
907 selection
, &tree_model
, &iter
);
908 g_return_if_fail (have_selection
);
910 tree_row_data
= subscription_editor_tree_row_data_from_iter (
911 tree_view
, tree_model
, &iter
, NULL
);
913 g_queue_push_tail (&tree_rows
, tree_row_data
);
914 subscription_editor_unsubscribe_many (editor
, &tree_rows
);
918 subscription_editor_unsubscribe_popup_cb (EMSubscriptionEditor
*editor
)
922 gboolean tree_filled
;
924 tree_filled
= editor
->priv
->active
&&
925 gtk_tree_model_get_iter_first (
926 editor
->priv
->active
->filtered_view
927 ? editor
->priv
->active
->list_store
928 : editor
->priv
->active
->tree_store
,
931 menu
= gtk_menu_new ();
933 gtk_menu_shell_append (
934 GTK_MENU_SHELL (menu
),
935 subscription_editor_create_menu_item (
937 gtk_widget_get_sensitive (
938 editor
->priv
->unsubscribe_button
),
939 G_CALLBACK (subscription_editor_unsubscribe
),
942 gtk_menu_shell_append (
943 GTK_MENU_SHELL (menu
),
944 subscription_editor_create_menu_item (
945 _("Unsu_bscribe From Hidden"),
947 G_CALLBACK (subscription_editor_unsubscribe_hidden
),
950 gtk_menu_shell_append (
951 GTK_MENU_SHELL (menu
),
952 subscription_editor_create_menu_item (
953 _("Unsubscribe From _All"),
955 G_CALLBACK (subscription_editor_unsubscribe_all
),
958 gtk_menu_attach_to_widget (GTK_MENU (menu
), GTK_WIDGET (editor
), NULL
);
959 g_signal_connect (menu
, "deactivate", G_CALLBACK (gtk_menu_detach
), NULL
);
962 "anchor-hints", (GDK_ANCHOR_FLIP_Y
|
967 gtk_menu_popup_at_widget (GTK_MENU (menu
),
968 editor
->priv
->unsubscribe_button
,
969 GDK_GRAVITY_SOUTH_WEST
,
970 GDK_GRAVITY_NORTH_WEST
,
975 subscription_editor_collapse_all (EMSubscriptionEditor
*editor
)
977 gtk_tree_view_collapse_all (editor
->priv
->active
->tree_view
);
981 subscription_editor_expand_all (EMSubscriptionEditor
*editor
)
983 gtk_tree_view_expand_all (editor
->priv
->active
->tree_view
);
987 subscription_editor_refresh (EMSubscriptionEditor
*editor
)
992 /* Cancel any operation on this store still in progress. */
993 gtk_button_clicked (GTK_BUTTON (editor
->priv
->stop_button
));
995 /* Start a new 'refresh' operation. */
996 editor
->priv
->active
->cancellable
= g_cancellable_new ();
998 gtk_widget_set_sensitive (editor
->priv
->notebook
, FALSE
);
999 gtk_widget_set_sensitive (editor
->priv
->subscribe_button
, FALSE
);
1000 gtk_widget_set_sensitive (editor
->priv
->subscribe_arrow
, FALSE
);
1001 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_button
, FALSE
);
1002 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_arrow
, FALSE
);
1003 gtk_widget_set_sensitive (editor
->priv
->refresh_button
, FALSE
);
1004 gtk_widget_set_sensitive (editor
->priv
->stop_button
, TRUE
);
1006 cursor
= gdk_cursor_new (GDK_WATCH
);
1007 window
= gtk_widget_get_window (GTK_WIDGET (editor
));
1008 gdk_window_set_cursor (window
, cursor
);
1009 g_object_unref (cursor
);
1011 camel_store_get_folder_info (
1012 editor
->priv
->active
->store
, NULL
,
1013 CAMEL_STORE_FOLDER_INFO_RECURSIVE
|
1014 CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL
|
1015 CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST
,
1016 G_PRIORITY_DEFAULT
, editor
->priv
->active
->cancellable
,
1017 (GAsyncReadyCallback
) subscription_editor_get_folder_info_done
,
1018 g_object_ref (editor
));
1022 subscription_editor_stop (EMSubscriptionEditor
*editor
)
1026 if (editor
->priv
->active
->cancellable
!= NULL
) {
1027 g_cancellable_cancel (editor
->priv
->active
->cancellable
);
1028 g_object_unref (editor
->priv
->active
->cancellable
);
1029 editor
->priv
->active
->cancellable
= NULL
;
1032 gtk_widget_set_sensitive (editor
->priv
->notebook
, TRUE
);
1033 gtk_widget_set_sensitive (editor
->priv
->subscribe_button
, TRUE
);
1034 gtk_widget_set_sensitive (editor
->priv
->subscribe_arrow
, TRUE
);
1035 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_button
, TRUE
);
1036 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_arrow
, TRUE
);
1037 gtk_widget_set_sensitive (editor
->priv
->refresh_button
, TRUE
);
1038 gtk_widget_set_sensitive (editor
->priv
->stop_button
, FALSE
);
1039 gtk_widget_grab_focus (GTK_WIDGET (editor
->priv
->active
->tree_view
));
1041 window
= gtk_widget_get_window (GTK_WIDGET (editor
));
1042 gdk_window_set_cursor (window
, NULL
);
1046 subscription_editor_filter_cb (GtkTreeModel
*tree_model
,
1048 EMSubscriptionEditor
*editor
)
1050 CamelFolderInfo
*folder_info
;
1054 /* If there's no search string let everything through. */
1055 if (editor
->priv
->search_string
== NULL
)
1058 gtk_tree_model_get (
1060 COL_CASEFOLDED
, &casefolded
,
1061 COL_FOLDER_INFO
, &folder_info
, -1);
1063 match
= FOLDER_CAN_SELECT (folder_info
) &&
1064 (casefolded
!= NULL
) && (*casefolded
!= '\0') &&
1065 (strstr (casefolded
, editor
->priv
->search_string
) != NULL
);
1067 g_free (casefolded
);
1073 subscription_editor_update_view (EMSubscriptionEditor
*editor
)
1076 GtkTreeView
*tree_view
;
1077 GtkTreeModel
*tree_model
;
1080 entry
= GTK_ENTRY (editor
->priv
->entry
);
1081 tree_view
= editor
->priv
->active
->tree_view
;
1083 editor
->priv
->timeout_id
= 0;
1085 text
= gtk_entry_get_text (entry
);
1087 if (text
!= NULL
&& *text
!= '\0') {
1088 g_free (editor
->priv
->search_string
);
1089 editor
->priv
->search_string
= g_utf8_casefold (text
, -1);
1091 /* Install the list store in the tree view if needed. */
1092 if (!editor
->priv
->active
->filtered_view
) {
1093 GtkTreeSelection
*selection
;
1096 tree_model
= gtk_tree_model_filter_new (
1097 editor
->priv
->active
->list_store
, NULL
);
1098 gtk_tree_model_filter_set_visible_func (
1099 GTK_TREE_MODEL_FILTER (tree_model
),
1100 (GtkTreeModelFilterVisibleFunc
)
1101 subscription_editor_filter_cb
, editor
,
1102 (GDestroyNotify
) NULL
);
1103 gtk_tree_view_set_model (tree_view
, tree_model
);
1104 g_object_unref (tree_model
);
1106 path
= gtk_tree_path_new_first ();
1107 selection
= gtk_tree_view_get_selection (tree_view
);
1108 gtk_tree_selection_select_path (selection
, path
);
1109 gtk_tree_path_free (path
);
1111 editor
->priv
->active
->filtered_view
= TRUE
;
1114 tree_model
= gtk_tree_view_get_model (tree_view
);
1115 gtk_tree_model_filter_refilter (
1116 GTK_TREE_MODEL_FILTER (tree_model
));
1118 gtk_entry_set_icon_sensitive (
1119 entry
, GTK_ENTRY_ICON_SECONDARY
, TRUE
);
1121 gtk_widget_set_sensitive (
1122 editor
->priv
->collapse_all_button
, FALSE
);
1123 gtk_widget_set_sensitive (
1124 editor
->priv
->expand_all_button
, FALSE
);
1127 /* Install the tree store in the tree view if needed. */
1128 if (editor
->priv
->active
->filtered_view
) {
1129 GtkTreeSelection
*selection
;
1132 tree_model
= editor
->priv
->active
->tree_store
;
1133 gtk_tree_view_set_model (tree_view
, tree_model
);
1135 path
= gtk_tree_path_new_first ();
1136 selection
= gtk_tree_view_get_selection (tree_view
);
1137 gtk_tree_selection_select_path (selection
, path
);
1138 gtk_tree_path_free (path
);
1140 editor
->priv
->active
->filtered_view
= FALSE
;
1143 gtk_entry_set_icon_sensitive (
1144 entry
, GTK_ENTRY_ICON_SECONDARY
, FALSE
);
1146 gtk_widget_set_sensitive (
1147 editor
->priv
->collapse_all_button
, TRUE
);
1148 gtk_widget_set_sensitive (
1149 editor
->priv
->expand_all_button
, TRUE
);
1154 subscription_editor_timeout_cb (gpointer user_data
)
1156 EMSubscriptionEditor
*editor
;
1158 editor
= EM_SUBSCRIPTION_EDITOR (user_data
);
1159 subscription_editor_update_view (editor
);
1160 editor
->priv
->timeout_id
= 0;
1166 subscription_editor_combo_box_changed_cb (GtkComboBox
*combo_box
,
1167 EMSubscriptionEditor
*editor
)
1172 index
= gtk_combo_box_get_active (combo_box
);
1173 g_return_if_fail (index
< editor
->priv
->stores
->len
);
1175 data
= g_ptr_array_index (editor
->priv
->stores
, index
);
1176 g_return_if_fail (data
!= NULL
);
1178 editor
->priv
->active
= data
;
1180 subscription_editor_stop (editor
);
1181 subscription_editor_update_view (editor
);
1183 g_object_notify (G_OBJECT (editor
), "store");
1185 if (data
->needs_refresh
) {
1186 subscription_editor_refresh (editor
);
1187 data
->needs_refresh
= FALSE
;
1192 subscription_editor_entry_changed_cb (GtkEntry
*entry
,
1193 EMSubscriptionEditor
*editor
)
1197 if (editor
->priv
->timeout_id
> 0) {
1198 g_source_remove (editor
->priv
->timeout_id
);
1199 editor
->priv
->timeout_id
= 0;
1202 text
= gtk_entry_get_text (entry
);
1204 if (text
!= NULL
&& *text
!= '\0') {
1205 editor
->priv
->timeout_id
= e_named_timeout_add_seconds (
1206 1, subscription_editor_timeout_cb
, editor
);
1208 subscription_editor_update_view (editor
);
1213 subscription_editor_icon_release_cb (GtkEntry
*entry
,
1214 GtkEntryIconPosition icon_pos
,
1216 EMSubscriptionEditor
*editor
)
1218 if (icon_pos
== GTK_ENTRY_ICON_SECONDARY
)
1219 gtk_entry_set_text (entry
, "");
1223 subscription_editor_renderer_toggled_cb (GtkCellRendererToggle
*renderer
,
1224 const gchar
*path_string
,
1225 EMSubscriptionEditor
*editor
)
1227 GtkTreeSelection
*selection
;
1228 GtkTreeView
*tree_view
;
1231 tree_view
= editor
->priv
->active
->tree_view
;
1232 selection
= gtk_tree_view_get_selection (tree_view
);
1234 path
= gtk_tree_path_new_from_string (path_string
);
1235 gtk_tree_selection_select_path (selection
, path
);
1236 gtk_tree_path_free (path
);
1238 if (gtk_cell_renderer_toggle_get_active (renderer
))
1239 subscription_editor_unsubscribe (editor
);
1241 subscription_editor_subscribe (editor
);
1245 subscription_editor_render_toggle_cb (GtkCellLayout
*cell_layout
,
1246 GtkCellRenderer
*renderer
,
1247 GtkTreeModel
*tree_model
,
1250 CamelFolderInfo
*folder_info
;
1252 gtk_tree_model_get (
1253 tree_model
, iter
, COL_FOLDER_INFO
, &folder_info
, -1);
1256 renderer
, "active", FOLDER_SUBSCRIBED (folder_info
),
1257 "visible", FOLDER_CAN_SELECT (folder_info
), NULL
);
1261 subscription_editor_selection_changed_cb (GtkTreeSelection
*selection
,
1262 EMSubscriptionEditor
*editor
)
1264 GtkTreeModel
*tree_model
;
1267 if (gtk_tree_selection_get_selected (selection
, &tree_model
, &iter
)) {
1268 CamelFolderInfo
*folder_info
;
1270 gtk_tree_model_get (
1272 COL_FOLDER_INFO
, &folder_info
, -1);
1273 gtk_widget_set_sensitive (
1274 editor
->priv
->subscribe_button
,
1275 FOLDER_CAN_SELECT (folder_info
) &&
1276 !FOLDER_SUBSCRIBED (folder_info
));
1277 gtk_widget_set_sensitive (
1278 editor
->priv
->unsubscribe_button
,
1279 FOLDER_CAN_SELECT (folder_info
) &&
1280 FOLDER_SUBSCRIBED (folder_info
));
1282 gtk_widget_set_sensitive (
1283 editor
->priv
->subscribe_button
, FALSE
);
1284 gtk_widget_set_sensitive (
1285 editor
->priv
->unsubscribe_button
, FALSE
);
1288 gtk_widget_set_sensitive (editor
->priv
->subscribe_arrow
, TRUE
);
1289 gtk_widget_set_sensitive (editor
->priv
->unsubscribe_arrow
, TRUE
);
1293 em_subscription_editor_get_unread_total_text_cb (GtkTreeViewColumn
*tree_column
,
1294 GtkCellRenderer
*cell
,
1295 GtkTreeModel
*tree_model
,
1299 CamelFolderInfo
*folder_info
= NULL
;
1300 GString
*text
= NULL
;
1302 g_return_if_fail (GTK_IS_CELL_RENDERER_TEXT (cell
));
1303 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model
));
1304 g_return_if_fail (iter
!= NULL
);
1306 gtk_tree_model_get (tree_model
, iter
, COL_FOLDER_INFO
, &folder_info
, -1);
1308 if (folder_info
&& folder_info
->total
> 0 && folder_info
->unread
>= 0 && folder_info
->unread
<= folder_info
->total
) {
1309 text
= g_string_new ("");
1311 if (folder_info
->unread
> 0)
1312 g_string_append_printf (
1313 text
, ngettext ("%d unread, ",
1314 "%d unread, ", folder_info
->unread
), folder_info
->unread
);
1316 g_string_append_printf (
1317 text
, ngettext ("%d total", "%d total",
1318 folder_info
->total
), folder_info
->total
);
1321 g_object_set (G_OBJECT (cell
), "text", text
? text
->str
: NULL
, NULL
);
1324 g_string_free (text
, TRUE
);
1328 subscription_editor_add_store (EMSubscriptionEditor
*editor
,
1332 CamelService
*service
;
1333 GtkListStore
*list_store
;
1334 GtkTreeStore
*tree_store
;
1335 GtkTreeViewColumn
*column
;
1336 GtkTreeSelection
*selection
;
1337 GtkCellRenderer
*renderer
;
1338 GtkComboBoxText
*combo_box
;
1339 GtkWidget
*container
;
1341 const gchar
*display_name
;
1343 service
= CAMEL_SERVICE (store
);
1344 display_name
= camel_service_get_display_name (service
);
1346 combo_box
= GTK_COMBO_BOX_TEXT (editor
->priv
->combo_box
);
1347 gtk_combo_box_text_append_text (combo_box
, display_name
);
1349 tree_store
= gtk_tree_store_new (
1351 /* COL_CASEFOLDED */ G_TYPE_STRING
,
1352 /* COL_FOLDER_ICON */ G_TYPE_STRING
,
1353 /* COL_FOLDER_NAME */ G_TYPE_STRING
,
1354 /* COL_FOLDER_INFO */ G_TYPE_POINTER
);
1356 list_store
= gtk_list_store_new (
1358 /* COL_CASEFOLDED */ G_TYPE_STRING
,
1359 /* COL_FOLDER_ICON */ G_TYPE_STRING
,
1360 /* COL_FOLDER_NAME */ G_TYPE_STRING
,
1361 /* COL_FOLDER_INFO */ G_TYPE_POINTER
);
1363 container
= editor
->priv
->notebook
;
1365 widget
= gtk_scrolled_window_new (NULL
, NULL
);
1366 gtk_scrolled_window_set_policy (
1367 GTK_SCROLLED_WINDOW (widget
),
1368 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1369 gtk_scrolled_window_set_shadow_type (
1370 GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_IN
);
1371 gtk_notebook_append_page (GTK_NOTEBOOK (container
), widget
, NULL
);
1372 gtk_container_child_set (
1373 GTK_CONTAINER (container
), widget
,
1374 "tab-fill", FALSE
, "tab-expand", FALSE
, NULL
);
1375 gtk_widget_show (widget
);
1379 widget
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store
));
1380 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (widget
), TRUE
);
1381 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget
), FALSE
);
1382 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (widget
), TRUE
);
1383 gtk_tree_view_set_search_column (
1384 GTK_TREE_VIEW (widget
), COL_FOLDER_NAME
);
1385 gtk_container_add (GTK_CONTAINER (container
), widget
);
1386 gtk_widget_show (widget
);
1388 column
= gtk_tree_view_column_new ();
1389 gtk_tree_view_append_column (GTK_TREE_VIEW (widget
), column
);
1391 renderer
= gtk_cell_renderer_toggle_new ();
1392 g_object_set (renderer
, "activatable", TRUE
, NULL
);
1393 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
1395 gtk_cell_layout_set_cell_data_func (
1396 GTK_CELL_LAYOUT (column
), renderer
,
1397 (GtkCellLayoutDataFunc
) subscription_editor_render_toggle_cb
,
1398 NULL
, (GDestroyNotify
) NULL
);
1401 renderer
, "toggled",
1402 G_CALLBACK (subscription_editor_renderer_toggled_cb
), editor
);
1404 column
= gtk_tree_view_column_new ();
1405 gtk_tree_view_append_column (GTK_TREE_VIEW (widget
), column
);
1406 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (widget
), column
);
1408 renderer
= gtk_cell_renderer_pixbuf_new ();
1409 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
1410 gtk_tree_view_column_add_attribute (
1411 column
, renderer
, "icon-name", COL_FOLDER_ICON
);
1413 renderer
= gtk_cell_renderer_text_new ();
1414 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
1415 gtk_tree_view_column_add_attribute (
1416 column
, renderer
, "text", COL_FOLDER_NAME
);
1418 column
= gtk_tree_view_column_new ();
1419 gtk_tree_view_append_column (GTK_TREE_VIEW (widget
), column
);
1421 renderer
= gtk_cell_renderer_text_new ();
1422 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
1423 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
1424 em_subscription_editor_get_unread_total_text_cb
, NULL
, NULL
);
1426 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (widget
));
1429 selection
, "changed",
1430 G_CALLBACK (subscription_editor_selection_changed_cb
), editor
);
1432 data
= g_slice_new0 (StoreData
);
1433 data
->store
= g_object_ref (store
);
1434 data
->tree_view
= g_object_ref (widget
);
1435 data
->list_store
= GTK_TREE_MODEL (list_store
);
1436 data
->tree_store
= GTK_TREE_MODEL (tree_store
);
1437 data
->needs_refresh
= TRUE
;
1439 g_ptr_array_add (editor
->priv
->stores
, data
);
1443 emse_notebook_sensitive_changed_cb (GtkWidget
*notebook
,
1447 gtk_dialog_set_response_sensitive (
1448 editor
, GTK_RESPONSE_CLOSE
,
1449 gtk_widget_get_sensitive (notebook
));
1453 subscription_editor_delete_event_cb (EMSubscriptionEditor
*editor
,
1457 /* stop processing if the button is insensitive */
1458 return !gtk_widget_get_sensitive (editor
->priv
->notebook
);
1462 subscription_editor_response_cb (EMSubscriptionEditor
*editor
,
1466 if (!gtk_widget_get_sensitive (editor
->priv
->notebook
))
1467 g_signal_stop_emission_by_name (editor
, "response");
1471 subscription_editor_set_store (EMSubscriptionEditor
*editor
,
1474 g_return_if_fail (editor
->priv
->initial_store
== NULL
);
1476 if (CAMEL_IS_SUBSCRIBABLE (store
))
1477 editor
->priv
->initial_store
= g_object_ref (store
);
1481 subscription_editor_set_session (EMSubscriptionEditor
*editor
,
1482 EMailSession
*session
)
1484 g_return_if_fail (E_IS_MAIL_SESSION (session
));
1485 g_return_if_fail (editor
->priv
->session
== NULL
);
1487 editor
->priv
->session
= g_object_ref (session
);
1491 subscription_editor_set_property (GObject
*object
,
1493 const GValue
*value
,
1496 switch (property_id
) {
1498 subscription_editor_set_session (
1499 EM_SUBSCRIPTION_EDITOR (object
),
1500 g_value_get_object (value
));
1504 subscription_editor_set_store (
1505 EM_SUBSCRIPTION_EDITOR (object
),
1506 g_value_get_object (value
));
1510 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1514 subscription_editor_get_property (GObject
*object
,
1519 switch (property_id
) {
1521 g_value_set_object (
1523 em_subscription_editor_get_session (
1524 EM_SUBSCRIPTION_EDITOR (object
)));
1528 g_value_set_object (
1530 em_subscription_editor_get_store (
1531 EM_SUBSCRIPTION_EDITOR (object
)));
1535 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1539 subscription_editor_dispose (GObject
*object
)
1541 EMSubscriptionEditorPrivate
*priv
;
1543 priv
= EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (object
);
1545 if (priv
->session
!= NULL
) {
1546 g_object_unref (priv
->session
);
1547 priv
->session
= NULL
;
1550 if (priv
->initial_store
!= NULL
) {
1551 g_object_unref (priv
->initial_store
);
1552 priv
->initial_store
= NULL
;
1555 if (priv
->timeout_id
> 0) {
1556 g_source_remove (priv
->timeout_id
);
1557 priv
->timeout_id
= 0;
1560 g_ptr_array_set_size (priv
->stores
, 0);
1562 /* Chain up to parent's dispose() method. */
1563 G_OBJECT_CLASS (em_subscription_editor_parent_class
)->dispose (object
);
1567 subscription_editor_finalize (GObject
*object
)
1569 EMSubscriptionEditorPrivate
*priv
;
1571 priv
= EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (object
);
1573 g_ptr_array_free (priv
->stores
, TRUE
);
1575 g_free (priv
->search_string
);
1577 /* Chain up to parent's finalize() method. */
1578 G_OBJECT_CLASS (em_subscription_editor_parent_class
)->finalize (object
);
1582 subscription_editor_constructed (GObject
*object
)
1584 EMSubscriptionEditor
*editor
;
1586 editor
= EM_SUBSCRIPTION_EDITOR (object
);
1588 /* Pick an initial store based on the default mail account, if
1589 * one wasn't already given in em_subscription_editor_new(). */
1590 if (editor
->priv
->initial_store
== NULL
) {
1592 ESourceRegistry
*registry
;
1593 CamelService
*service
;
1594 EMailSession
*session
;
1596 session
= em_subscription_editor_get_session (editor
);
1597 registry
= e_mail_session_get_registry (session
);
1599 source
= e_source_registry_ref_default_mail_account (registry
);
1601 service
= camel_session_ref_service (
1602 CAMEL_SESSION (session
),
1603 e_source_get_uid (source
));
1605 if (CAMEL_IS_SUBSCRIBABLE (service
))
1606 editor
->priv
->initial_store
= g_object_ref (service
);
1608 if (service
!= NULL
)
1609 g_object_unref (service
);
1611 g_object_unref (source
);
1614 /* Chain up to parent's constructed() method. */
1615 G_OBJECT_CLASS (em_subscription_editor_parent_class
)->constructed (object
);
1618 editor
, "delete-event",
1619 G_CALLBACK (subscription_editor_delete_event_cb
), NULL
);
1622 G_CALLBACK (subscription_editor_response_cb
), NULL
);
1626 subscription_editor_realize (GtkWidget
*widget
)
1628 EMSubscriptionEditor
*editor
;
1629 EMFolderTreeModel
*model
;
1630 GtkComboBox
*combo_box
;
1632 gint initial_index
= 0;
1634 editor
= EM_SUBSCRIPTION_EDITOR (widget
);
1636 /* Chain up to parent's realize() method. */
1637 GTK_WIDGET_CLASS (em_subscription_editor_parent_class
)->realize (widget
);
1639 /* Find stores to display, and watch for the initial store. */
1641 model
= em_folder_tree_model_get_default ();
1642 list
= em_folder_tree_model_list_stores (model
);
1644 for (link
= list
; link
!= NULL
; link
= g_list_next (link
)) {
1645 CamelStore
*store
= CAMEL_STORE (link
->data
);
1647 if (!CAMEL_IS_SUBSCRIBABLE (store
))
1650 if (store
== editor
->priv
->initial_store
)
1651 initial_index
= editor
->priv
->stores
->len
;
1653 subscription_editor_add_store (editor
, store
);
1658 /* The subscription editor should only be accessible if
1659 * at least one enabled store supports subscriptions. */
1660 g_return_if_fail (editor
->priv
->stores
->len
> 0);
1662 combo_box
= GTK_COMBO_BOX (editor
->priv
->combo_box
);
1663 gtk_combo_box_set_active (combo_box
, initial_index
);
1666 combo_box
, "changed",
1667 G_CALLBACK (subscription_editor_combo_box_changed_cb
), editor
);
1669 subscription_editor_combo_box_changed_cb (combo_box
, editor
);
1673 em_subscription_editor_class_init (EMSubscriptionEditorClass
*class)
1675 GObjectClass
*object_class
;
1676 GtkWidgetClass
*widget_class
;
1678 g_type_class_add_private (class, sizeof (EMSubscriptionEditorPrivate
));
1680 object_class
= G_OBJECT_CLASS (class);
1681 object_class
->set_property
= subscription_editor_set_property
;
1682 object_class
->get_property
= subscription_editor_get_property
;
1683 object_class
->dispose
= subscription_editor_dispose
;
1684 object_class
->finalize
= subscription_editor_finalize
;
1685 object_class
->constructed
= subscription_editor_constructed
;
1687 widget_class
= GTK_WIDGET_CLASS (class);
1688 widget_class
->realize
= subscription_editor_realize
;
1690 g_object_class_install_property (
1693 g_param_spec_object (
1697 E_TYPE_MAIL_SESSION
,
1699 G_PARAM_CONSTRUCT_ONLY
|
1700 G_PARAM_STATIC_STRINGS
));
1702 g_object_class_install_property (
1705 g_param_spec_object (
1711 G_PARAM_CONSTRUCT_ONLY
|
1712 G_PARAM_STATIC_STRINGS
));
1716 em_subscription_editor_init (EMSubscriptionEditor
*editor
)
1718 GtkWidget
*container
;
1721 const gchar
*tooltip
;
1723 editor
->priv
= EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (editor
);
1725 editor
->priv
->stores
= g_ptr_array_new_with_free_func (
1726 (GDestroyNotify
) store_data_free
);
1728 gtk_container_set_border_width (GTK_CONTAINER (editor
), 5);
1729 gtk_window_set_title (GTK_WINDOW (editor
), _("Folder Subscriptions"));
1730 gtk_window_set_default_size (GTK_WINDOW (editor
), 600, 400);
1733 GTK_WINDOW (editor
),
1734 "/org/gnome/evolution/mail/subscription-window/",
1735 E_RESTORE_WINDOW_SIZE
);
1737 gtk_dialog_add_button (
1738 GTK_DIALOG (editor
),
1739 _("_Close"), GTK_RESPONSE_CLOSE
);
1741 container
= gtk_dialog_get_content_area (GTK_DIALOG (editor
));
1743 widget
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 12);
1744 gtk_container_set_border_width (GTK_CONTAINER (widget
), 5);
1745 gtk_box_pack_start (GTK_BOX (container
), widget
, TRUE
, TRUE
, 0);
1746 gtk_widget_show (widget
);
1748 container
= box
= widget
;
1750 widget
= gtk_grid_new ();
1751 gtk_grid_set_row_spacing (GTK_GRID (widget
), 6);
1752 gtk_grid_set_column_spacing (GTK_GRID (widget
), 6);
1753 gtk_box_pack_start (GTK_BOX (container
), widget
, FALSE
, FALSE
, 0);
1754 gtk_widget_show (widget
);
1758 widget
= gtk_combo_box_text_new ();
1759 gtk_widget_set_hexpand (widget
, TRUE
);
1760 gtk_grid_attach (GTK_GRID (container
), widget
, 1, 0, 1, 1);
1761 editor
->priv
->combo_box
= widget
;
1762 gtk_widget_show (widget
);
1764 widget
= gtk_label_new_with_mnemonic (_("_Account:"));
1765 gtk_label_set_mnemonic_widget (
1766 GTK_LABEL (widget
), editor
->priv
->combo_box
);
1767 gtk_misc_set_alignment (GTK_MISC (widget
), 1.0, 0.5);
1768 gtk_grid_attach (GTK_GRID (container
), widget
, 0, 0, 1, 1);
1769 gtk_widget_show (widget
);
1771 widget
= gtk_entry_new ();
1772 gtk_entry_set_icon_from_icon_name (
1774 GTK_ENTRY_ICON_SECONDARY
, "edit-clear");
1775 gtk_entry_set_icon_tooltip_text (
1777 GTK_ENTRY_ICON_SECONDARY
, _("Clear Search"));
1778 gtk_entry_set_icon_sensitive (
1780 GTK_ENTRY_ICON_SECONDARY
, FALSE
);
1781 gtk_widget_set_hexpand (widget
, TRUE
);
1782 gtk_grid_attach (GTK_GRID (container
), widget
, 1, 1, 1, 1);
1783 editor
->priv
->entry
= widget
;
1784 gtk_widget_show (widget
);
1788 G_CALLBACK (subscription_editor_entry_changed_cb
), editor
);
1791 widget
, "icon-release",
1792 G_CALLBACK (subscription_editor_icon_release_cb
), editor
);
1794 widget
= gtk_label_new_with_mnemonic (_("Sho_w items that contain:"));
1795 gtk_label_set_mnemonic_widget (
1796 GTK_LABEL (widget
), editor
->priv
->entry
);
1797 gtk_misc_set_alignment (GTK_MISC (widget
), 1.0, 0.5);
1798 gtk_grid_attach (GTK_GRID (container
), widget
, 0, 1, 1, 1);
1799 gtk_widget_show (widget
);
1803 widget
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 6);
1804 gtk_box_pack_start (GTK_BOX (container
), widget
, TRUE
, TRUE
, 0);
1805 gtk_widget_show (widget
);
1809 widget
= gtk_notebook_new ();
1810 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget
), FALSE
);
1811 gtk_notebook_set_show_border (GTK_NOTEBOOK (widget
), FALSE
);
1812 gtk_box_pack_start (GTK_BOX (container
), widget
, TRUE
, TRUE
, 0);
1813 editor
->priv
->notebook
= widget
;
1814 gtk_widget_show (widget
);
1816 e_binding_bind_property (
1817 editor
->priv
->combo_box
, "active",
1818 editor
->priv
->notebook
, "page",
1819 G_BINDING_BIDIRECTIONAL
|
1820 G_BINDING_SYNC_CREATE
);
1822 e_signal_connect_notify (
1823 widget
, "notify::sensitive",
1824 G_CALLBACK (emse_notebook_sensitive_changed_cb
), editor
);
1826 widget
= gtk_button_box_new (GTK_ORIENTATION_VERTICAL
);
1827 gtk_box_set_spacing (GTK_BOX (widget
), 6);
1828 gtk_button_box_set_layout (
1829 GTK_BUTTON_BOX (widget
), GTK_BUTTONBOX_START
);
1830 gtk_box_pack_start (GTK_BOX (container
), widget
, FALSE
, TRUE
, 0);
1831 gtk_widget_show (widget
);
1833 container
= box
= widget
;
1835 widget
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 2);
1836 gtk_box_pack_start (GTK_BOX (container
), widget
, FALSE
, TRUE
, 0);
1837 gtk_widget_show (widget
);
1841 tooltip
= _("Subscribe to the selected folder");
1842 widget
= gtk_button_new_with_mnemonic (_("Su_bscribe"));
1843 gtk_widget_set_sensitive (widget
, FALSE
);
1844 gtk_widget_set_tooltip_text (widget
, tooltip
);
1845 editor
->priv
->subscribe_button
= widget
;
1846 gtk_widget_show (widget
);
1848 g_signal_connect_swapped (
1850 G_CALLBACK (subscription_editor_subscribe
), editor
);
1852 widget
= gtk_button_new ();
1853 gtk_button_set_image (
1854 GTK_BUTTON (widget
),
1855 gtk_arrow_new (GTK_ARROW_DOWN
, GTK_SHADOW_NONE
));
1856 editor
->priv
->subscribe_arrow
= widget
;
1857 gtk_widget_show (widget
);
1859 g_signal_connect_swapped (
1861 G_CALLBACK (subscription_editor_subscribe_popup_cb
), editor
);
1863 if (gtk_widget_get_direction (container
) == GTK_TEXT_DIR_LTR
) {
1864 gtk_box_pack_start (
1865 GTK_BOX (container
),
1866 editor
->priv
->subscribe_button
, TRUE
, TRUE
, 0);
1867 gtk_box_pack_start (
1868 GTK_BOX (container
),
1869 editor
->priv
->subscribe_arrow
, FALSE
, FALSE
, 0);
1871 gtk_box_pack_start (
1872 GTK_BOX (container
),
1873 editor
->priv
->subscribe_arrow
, FALSE
, FALSE
, 0);
1874 gtk_box_pack_start (
1875 GTK_BOX (container
),
1876 editor
->priv
->subscribe_button
, TRUE
, TRUE
, 0);
1881 widget
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 2);
1882 gtk_box_pack_start (GTK_BOX (container
), widget
, FALSE
, TRUE
, 0);
1883 gtk_widget_show (widget
);
1887 tooltip
= _("Unsubscribe from the selected folder");
1888 widget
= gtk_button_new_with_mnemonic (_("_Unsubscribe"));
1889 gtk_widget_set_sensitive (widget
, FALSE
);
1890 gtk_widget_set_tooltip_text (widget
, tooltip
);
1891 editor
->priv
->unsubscribe_button
= widget
;
1892 gtk_widget_show (widget
);
1894 g_signal_connect_swapped (
1896 G_CALLBACK (subscription_editor_unsubscribe
), editor
);
1898 widget
= gtk_button_new ();
1899 gtk_button_set_image (
1900 GTK_BUTTON (widget
),
1901 gtk_arrow_new (GTK_ARROW_DOWN
, GTK_SHADOW_NONE
));
1902 editor
->priv
->unsubscribe_arrow
= widget
;
1903 gtk_widget_show (widget
);
1905 g_signal_connect_swapped (
1907 G_CALLBACK (subscription_editor_unsubscribe_popup_cb
), editor
);
1909 if (gtk_widget_get_direction (container
) == GTK_TEXT_DIR_LTR
) {
1910 gtk_box_pack_start (
1911 GTK_BOX (container
),
1912 editor
->priv
->unsubscribe_button
, TRUE
, TRUE
, 0);
1913 gtk_box_pack_start (
1914 GTK_BOX (container
),
1915 editor
->priv
->unsubscribe_arrow
, FALSE
, FALSE
, 0);
1917 gtk_box_pack_start (
1918 GTK_BOX (container
),
1919 editor
->priv
->unsubscribe_arrow
, FALSE
, FALSE
, 0);
1920 gtk_box_pack_start (
1921 GTK_BOX (container
),
1922 editor
->priv
->unsubscribe_button
, TRUE
, TRUE
, 0);
1927 tooltip
= _("Collapse all folders");
1928 widget
= gtk_button_new_with_mnemonic (_("C_ollapse All"));
1929 gtk_widget_set_tooltip_text (widget
, tooltip
);
1930 gtk_box_pack_start (GTK_BOX (container
), widget
, FALSE
, FALSE
, 0);
1931 editor
->priv
->collapse_all_button
= widget
;
1932 gtk_widget_show (widget
);
1934 g_signal_connect_swapped (
1936 G_CALLBACK (subscription_editor_collapse_all
), editor
);
1938 tooltip
= _("Expand all folders");
1939 widget
= gtk_button_new_with_mnemonic (_("E_xpand All"));
1940 gtk_widget_set_tooltip_text (widget
, tooltip
);
1941 gtk_box_pack_start (GTK_BOX (container
), widget
, FALSE
, FALSE
, 0);
1942 editor
->priv
->expand_all_button
= widget
;
1943 gtk_widget_show (widget
);
1945 g_signal_connect_swapped (
1947 G_CALLBACK (subscription_editor_expand_all
), editor
);
1949 tooltip
= _("Refresh the folder list");
1950 widget
= e_dialog_button_new_with_icon ("view-refresh", _("_Refresh"));
1951 gtk_widget_set_tooltip_text (widget
, tooltip
);
1952 gtk_box_pack_start (GTK_BOX (container
), widget
, FALSE
, FALSE
, 0);
1953 gtk_widget_set_sensitive (widget
, FALSE
);
1954 editor
->priv
->refresh_button
= widget
;
1955 gtk_widget_show (widget
);
1957 g_signal_connect_swapped (
1959 G_CALLBACK (subscription_editor_refresh
), editor
);
1961 tooltip
= _("Stop the current operation");
1962 widget
= e_dialog_button_new_with_icon ("process-stop", _("_Stop"));
1963 gtk_widget_set_tooltip_text (widget
, tooltip
);
1964 gtk_box_pack_start (GTK_BOX (container
), widget
, FALSE
, FALSE
, 0);
1965 gtk_widget_set_sensitive (widget
, FALSE
);
1966 editor
->priv
->stop_button
= widget
;
1967 gtk_widget_show (widget
);
1969 g_signal_connect_swapped (
1971 G_CALLBACK (subscription_editor_stop
), editor
);
1975 em_subscription_editor_new (GtkWindow
*parent
,
1976 EMailSession
*session
,
1977 CamelStore
*initial_store
)
1979 g_return_val_if_fail (GTK_IS_WINDOW (parent
), NULL
);
1980 g_return_val_if_fail (E_IS_MAIL_SESSION (session
), NULL
);
1982 return g_object_new (
1983 EM_TYPE_SUBSCRIPTION_EDITOR
,
1985 "store", initial_store
,
1986 "transient-for", parent
,
1991 em_subscription_editor_get_session (EMSubscriptionEditor
*editor
)
1993 g_return_val_if_fail (EM_IS_SUBSCRIPTION_EDITOR (editor
), NULL
);
1995 return editor
->priv
->session
;
1999 em_subscription_editor_get_store (EMSubscriptionEditor
*editor
)
2001 g_return_val_if_fail (EM_IS_SUBSCRIPTION_EDITOR (editor
), NULL
);
2003 if (editor
->priv
->active
== NULL
)
2006 return editor
->priv
->active
->store
;