Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
em-subscription-editor.c:769:3 | clang-analyzer | Value stored to 'found' is never read | ||
em-subscription-editor.c:769:3 | clang-analyzer | Value stored to 'found' is never read |
1 /*
2 * em-subscription-editor.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "em-subscription-editor.h"
24
25 #include <string.h>
26 #include <glib/gi18n-lib.h>
27
28 #include <libemail-utils/mail-mt.h>
29 #include <libemail-engine/mail-tools.h>
30 #include <libemail-engine/mail-ops.h>
31
32 #include <e-util/e-dialog-utils.h>
33 #include <e-util/e-util.h>
34 #include <e-util/e-util-private.h>
35
36 #include "em-folder-utils.h"
37
38 #define EM_SUBSCRIPTION_EDITOR_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE \
40 ((obj), EM_TYPE_SUBSCRIPTION_EDITOR, EMSubscriptionEditorPrivate))
41
42 #define FOLDER_CAN_SELECT(folder_info) \
43 ((folder_info) != NULL && \
44 ((folder_info)->flags & CAMEL_FOLDER_NOSELECT) == 0)
45 #define FOLDER_SUBSCRIBED(folder_info) \
46 ((folder_info) != NULL && \
47 ((folder_info)->flags & CAMEL_FOLDER_SUBSCRIBED) != 0)
48
49 #define EM_SUBSCRIPTION_EDITOR_GET_PRIVATE(obj) \
50 (G_TYPE_INSTANCE_GET_PRIVATE \
51 ((obj), EM_TYPE_SUBSCRIPTION_EDITOR, EMSubscriptionEditorPrivate))
52
53 typedef struct _AsyncContext AsyncContext;
54 typedef struct _TreeRowData TreeRowData;
55 typedef struct _StoreData StoreData;
56
57 struct _EMSubscriptionEditorPrivate {
58 EMailSession *session;
59 CamelStore *initial_store;
60
61 GtkWidget *combo_box; /* not referenced */
62 GtkWidget *entry; /* not referenced */
63 GtkWidget *notebook; /* not referenced */
64 GtkWidget *subscribe_button; /* not referenced */
65 GtkWidget *subscribe_arrow; /* not referenced */
66 GtkWidget *unsubscribe_button; /* not referenced */
67 GtkWidget *unsubscribe_arrow; /* not referenced */
68 GtkWidget *collapse_all_button; /* not referenced */
69 GtkWidget *expand_all_button; /* not referenced */
70 GtkWidget *refresh_button; /* not referenced */
71 GtkWidget *stop_button; /* not referenced */
72
73 /* Indicies coincide with the combo box. */
74 GPtrArray *stores;
75
76 /* Points at an item in the stores array. */
77 StoreData *active;
78
79 /* Casefolded search string. */
80 gchar *search_string;
81
82 guint timeout_id;
83 };
84
85 struct _TreeRowData {
86 CamelFolderInfo *folder_info;
87 GtkTreeRowReference *reference;
88 };
89
90 struct _AsyncContext {
91 EMSubscriptionEditor *editor;
92 GQueue *tree_rows;
93 };
94
95 struct _StoreData {
96 CamelStore *store;
97 GtkTreeView *tree_view;
98 GtkTreeModel *list_store;
99 GtkTreeModel *tree_store;
100 GCancellable *cancellable;
101 CamelFolderInfo *folder_info;
102 gboolean filtered_view;
103 gboolean needs_refresh;
104 };
105
106 enum {
107 PROP_0,
108 PROP_SESSION,
109 PROP_STORE
110 };
111
112 enum {
113 COL_CASEFOLDED, /* G_TYPE_STRING */
114 COL_FOLDER_NAME, /* G_TYPE_STRING */
115 COL_FOLDER_ICON, /* G_TYPE_STRING */
116 COL_FOLDER_INFO, /* G_TYPE_POINTER */
117 N_COLUMNS
118 };
119
120 G_DEFINE_TYPE (EMSubscriptionEditor, em_subscription_editor, GTK_TYPE_DIALOG)
121
122 static void
123 tree_row_data_free (TreeRowData *tree_row_data)
124 {
125 g_return_if_fail (tree_row_data != NULL);
126
127 gtk_tree_row_reference_free (tree_row_data->reference);
128 g_slice_free (TreeRowData, tree_row_data);
129 }
130
131 static AsyncContext *
132 async_context_new (EMSubscriptionEditor *editor,
133 GQueue *tree_rows)
134 {
135 AsyncContext *context;
136
137 context = g_slice_new0 (AsyncContext);
138 context->editor = g_object_ref (editor);
139
140 /* Transfer GQueue contents. */
141 context->tree_rows = g_queue_copy (tree_rows);
142 g_queue_clear (tree_rows);
143
144 return context;
145 }
146
147 static void
148 async_context_free (AsyncContext *context)
149 {
150 while (!g_queue_is_empty (context->tree_rows))
151 tree_row_data_free (g_queue_pop_head (context->tree_rows));
152
153 g_object_unref (context->editor);
154 g_queue_free (context->tree_rows);
155
156 g_slice_free (AsyncContext, context);
157 }
158
159 static void
160 store_data_free (StoreData *data)
161 {
162 if (data->store != NULL)
163 g_object_unref (data->store);
164
165 if (data->tree_view != NULL)
166 g_object_unref (data->tree_view);
167
168 if (data->list_store != NULL)
169 g_object_unref (data->list_store);
170
171 if (data->tree_store != NULL)
172 g_object_unref (data->tree_store);
173
174 if (data->cancellable != NULL) {
175 g_cancellable_cancel (data->cancellable);
176 g_object_unref (data->cancellable);
177 }
178
179 camel_folder_info_free (data->folder_info);
180
181 g_slice_free (StoreData, data);
182 }
183
184 static void
185 subscription_editor_populate (EMSubscriptionEditor *editor,
186 CamelFolderInfo *folder_info,
187 GtkTreeIter *parent,
188 GList **expand_paths)
189 {
190 GtkListStore *list_store;
191 GtkTreeStore *tree_store;
192
193 list_store = GTK_LIST_STORE (editor->priv->active->list_store);
194 tree_store = GTK_TREE_STORE (editor->priv->active->tree_store);
195
196 while (folder_info != NULL) {
197 GtkTreeIter iter;
198 const gchar *icon_name;
199 gchar *casefolded;
200
201 icon_name =
202 em_folder_utils_get_icon_name (folder_info->flags);
203
204 casefolded = g_utf8_casefold (folder_info->full_name, -1);
205
206 gtk_list_store_append (list_store, &iter);
207
208 gtk_list_store_set (
209 list_store, &iter,
210 COL_CASEFOLDED, casefolded,
211 COL_FOLDER_ICON, icon_name,
212 COL_FOLDER_NAME, folder_info->full_name,
213 COL_FOLDER_INFO, folder_info, -1);
214
215 gtk_tree_store_append (tree_store, &iter, parent);
216
217 gtk_tree_store_set (
218 tree_store, &iter,
219 COL_CASEFOLDED, NULL, /* not needed */
220 COL_FOLDER_ICON, icon_name,
221 COL_FOLDER_NAME, folder_info->display_name,
222 COL_FOLDER_INFO, folder_info, -1);
223
224 if (FOLDER_SUBSCRIBED (folder_info)) {
225 GtkTreePath *path;
226
227 path = gtk_tree_model_get_path (
228 GTK_TREE_MODEL (tree_store), &iter);
229 *expand_paths = g_list_prepend (*expand_paths, path);
230 }
231
232 g_free (casefolded);
233
234 if (folder_info->child != NULL)
235 subscription_editor_populate (
236 editor, folder_info->child,
237 &iter, expand_paths);
238
239 folder_info = folder_info->next;
240 }
241 }
242
243 static void
244 expand_paths_cb (gpointer path,
245 gpointer tree_view)
246 {
247 gtk_tree_view_expand_to_path (tree_view, path);
248 }
249
250 static void
251 subscription_editor_get_folder_info_done (CamelStore *store,
252 GAsyncResult *result,
253 EMSubscriptionEditor *editor)
254 {
255 GtkTreePath *path;
256 GtkTreeView *tree_view;
257 GtkTreeModel *list_store;
258 GtkTreeModel *tree_store;
259 GtkTreeModel *model;
260 GtkTreeSelection *selection;
261 CamelFolderInfo *folder_info;
262 GdkWindow *window;
263 GList *expand_paths = NULL;
264 GError *error = NULL;
265
266 folder_info = camel_store_get_folder_info_finish (
267 store, result, &error);
268
269 /* Just return quietly if we were cancelled. */
270 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
271 g_warn_if_fail (folder_info == NULL);
272 g_error_free (error);
273 goto exit;
274 }
275
276 gtk_widget_set_sensitive (editor->priv->notebook, TRUE);
277 gtk_widget_set_sensitive (editor->priv->refresh_button, TRUE);
278 gtk_widget_set_sensitive (editor->priv->stop_button, FALSE);
279
280 window = gtk_widget_get_window (GTK_WIDGET (editor));
281 gdk_window_set_cursor (window, NULL);
282
283 /* XXX Do something smarter with errors. */
284 if (error != NULL) {
285 g_warn_if_fail (folder_info == NULL);
286 e_notice (GTK_WINDOW (editor), GTK_MESSAGE_ERROR, "%s", error->message);
287 g_error_free (error);
288 goto exit;
289 }
290
291 g_return_if_fail (folder_info != NULL);
292
293 camel_folder_info_free (editor->priv->active->folder_info);
294 editor->priv->active->folder_info = folder_info;
295
296 tree_view = editor->priv->active->tree_view;
297 list_store = editor->priv->active->list_store;
298 tree_store = editor->priv->active->tree_store;
299
300 gtk_list_store_clear (GTK_LIST_STORE (list_store));
301 gtk_tree_store_clear (GTK_TREE_STORE (tree_store));
302
303 model = gtk_tree_view_get_model (tree_view);
304 gtk_tree_view_set_model (tree_view, NULL);
305 subscription_editor_populate (editor, folder_info, NULL, &expand_paths);
306 gtk_tree_view_set_model (tree_view, model);
307
308 g_list_foreach (expand_paths, expand_paths_cb, tree_view);
309 g_list_foreach (expand_paths, (GFunc) gtk_tree_path_free, NULL);
310 g_list_free (expand_paths);
311
312 path = gtk_tree_path_new_first ();
313 selection = gtk_tree_view_get_selection (tree_view);
314 gtk_tree_selection_select_path (selection, path);
315 gtk_tree_path_free (path);
316
317 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
318
319 exit:
320 g_object_unref (editor);
321 }
322
323 static void
324 subscription_editor_subscribe_folder_done (CamelSubscribable *subscribable,
325 GAsyncResult *result,
326 AsyncContext *context)
327 {
328 GtkTreeView *tree_view;
329 GtkTreeModel *tree_model;
330 GtkTreeSelection *selection;
331 GtkTreePath *path;
332 GtkTreeIter iter;
333 GdkWindow *window;
334 GError *error = NULL;
335 TreeRowData *tree_row_data;
336
337 camel_subscribable_subscribe_folder_finish (
338 subscribable, result, &error);
339
340 /* Just return quietly if we were cancelled. */
341 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
342 g_error_free (error);
343 goto exit;
344 }
345
346 tree_row_data = g_queue_pop_head (context->tree_rows);
347
348 /* XXX Do something smarter with errors. */
349 if (error == NULL)
350 tree_row_data->folder_info->flags |= CAMEL_FOLDER_SUBSCRIBED;
351 else {
352 e_notice (
353 GTK_WINDOW (context->editor),
354 GTK_MESSAGE_ERROR, "%s", error->message);
355 g_error_free (error);
356 tree_row_data_free (tree_row_data);
357 goto exit;
358 }
359
360 /* Update the toggle renderer in the selected row. */
361 tree_model = gtk_tree_row_reference_get_model (tree_row_data->reference);
362 path = gtk_tree_row_reference_get_path (tree_row_data->reference);
363 gtk_tree_model_get_iter (tree_model, &iter, path);
364 gtk_tree_model_row_changed (tree_model, path, &iter);
365 gtk_tree_path_free (path);
366
367 tree_row_data_free (tree_row_data);
368
369 if (!g_queue_is_empty (context->tree_rows)) {
370 GCancellable *cancellable;
371
372 /* continue with the next to subscribe */
373 tree_row_data = g_queue_peek_head (context->tree_rows);
374 g_return_if_fail (tree_row_data != NULL);
375
376 cancellable = context->editor->priv->active->cancellable;
377
378 camel_subscribable_subscribe_folder (
379 subscribable, tree_row_data->folder_info->full_name,
380 G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback)
381 subscription_editor_subscribe_folder_done, context);
382 return;
383 }
384
385 exit:
386 gtk_widget_set_sensitive (context->editor->priv->notebook, TRUE);
387 gtk_widget_set_sensitive (context->editor->priv->refresh_button, TRUE);
388 gtk_widget_set_sensitive (context->editor->priv->stop_button, FALSE);
389
390 window = gtk_widget_get_window (GTK_WIDGET (context->editor));
391 gdk_window_set_cursor (window, NULL);
392
393 /* Update the Subscription/Unsubscription buttons. */
394 tree_view = context->editor->priv->active->tree_view;
395 selection = gtk_tree_view_get_selection (tree_view);
396 g_signal_emit_by_name (selection, "changed");
397
398 async_context_free (context);
399
400 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
401 }
402
403 static void
404 subscription_editor_subscribe_many (EMSubscriptionEditor *editor,
405 GQueue *tree_rows)
406 {
407 TreeRowData *tree_row_data;
408 GCancellable *cancellable;
409 CamelStore *active_store;
410 AsyncContext *context;
411 GdkCursor *cursor;
412 GdkWindow *window;
413
414 g_return_if_fail (editor != NULL);
415
416 if (g_queue_is_empty (tree_rows))
417 return;
418
419 tree_row_data = g_queue_peek_head (tree_rows);
420 g_return_if_fail (tree_row_data != NULL);
421
422 /* Cancel any operation on this store still in progress. */
423 gtk_button_clicked (GTK_BUTTON (editor->priv->stop_button));
424
425 /* Start a new 'subscription' operation. */
426 editor->priv->active->cancellable = g_cancellable_new ();
427
428 gtk_widget_set_sensitive (editor->priv->notebook, FALSE);
429 gtk_widget_set_sensitive (editor->priv->subscribe_button, FALSE);
430 gtk_widget_set_sensitive (editor->priv->subscribe_arrow, FALSE);
431 gtk_widget_set_sensitive (editor->priv->unsubscribe_button, FALSE);
432 gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, FALSE);
433 gtk_widget_set_sensitive (editor->priv->refresh_button, FALSE);
434 gtk_widget_set_sensitive (editor->priv->stop_button, TRUE);
435
436 cursor = gdk_cursor_new (GDK_WATCH);
437 window = gtk_widget_get_window (GTK_WIDGET (editor));
438 gdk_window_set_cursor (window, cursor);
439 g_object_unref (cursor);
440
441 context = async_context_new (editor, tree_rows);
442
443 active_store = editor->priv->active->store;
444 cancellable = editor->priv->active->cancellable;
445
446 camel_subscribable_subscribe_folder (
447 CAMEL_SUBSCRIBABLE (active_store),
448 tree_row_data->folder_info->full_name,
449 G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback)
450 subscription_editor_subscribe_folder_done, context);
451 }
452
453 static void
454 subscription_editor_unsubscribe_folder_done (CamelSubscribable *subscribable,
455 GAsyncResult *result,
456 AsyncContext *context)
457 {
458 GtkTreeView *tree_view;
459 GtkTreeModel *tree_model;
460 GtkTreeSelection *selection;
461 GtkTreePath *path;
462 GtkTreeIter iter;
463 GdkWindow *window;
464 GError *error = NULL;
465 TreeRowData *tree_row_data;
466
467 camel_subscribable_unsubscribe_folder_finish (
468 subscribable, result, &error);
469
470 /* Just return quietly if we were cancelled. */
471 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
472 g_error_free (error);
473 goto exit;
474 }
475
476 tree_row_data = g_queue_pop_head (context->tree_rows);
477
478 /* XXX Do something smarter with errors. */
479 if (error == NULL)
480 tree_row_data->folder_info->flags &= ~CAMEL_FOLDER_SUBSCRIBED;
481 else {
482 e_notice (
483 GTK_WINDOW (context->editor),
484 GTK_MESSAGE_ERROR, "%s", error->message);
485 g_error_free (error);
486 tree_row_data_free (tree_row_data);
487 goto exit;
488 }
489
490 /* Update the toggle renderer in the selected row. */
491 tree_model = gtk_tree_row_reference_get_model (tree_row_data->reference);
492 path = gtk_tree_row_reference_get_path (tree_row_data->reference);
493 gtk_tree_model_get_iter (tree_model, &iter, path);
494 gtk_tree_model_row_changed (tree_model, path, &iter);
495 gtk_tree_path_free (path);
496
497 tree_row_data_free (tree_row_data);
498
499 if (!g_queue_is_empty (context->tree_rows)) {
500 GCancellable *cancellable;
501
502 /* continue with the next to unsubscribe */
503 tree_row_data = g_queue_peek_head (context->tree_rows);
504 g_return_if_fail (tree_row_data != NULL);
505
506 cancellable = context->editor->priv->active->cancellable;
507
508 camel_subscribable_unsubscribe_folder (
509 subscribable, tree_row_data->folder_info->full_name,
510 G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback)
511 subscription_editor_unsubscribe_folder_done, context);
512 return;
513 }
514
515 exit:
516 gtk_widget_set_sensitive (context->editor->priv->notebook, TRUE);
517 gtk_widget_set_sensitive (context->editor->priv->refresh_button, TRUE);
518 gtk_widget_set_sensitive (context->editor->priv->stop_button, FALSE);
519
520 window = gtk_widget_get_window (GTK_WIDGET (context->editor));
521 gdk_window_set_cursor (window, NULL);
522
523 /* Update the Subscription/Unsubscription buttons. */
524 tree_view = context->editor->priv->active->tree_view;
525 selection = gtk_tree_view_get_selection (tree_view);
526 g_signal_emit_by_name (selection, "changed");
527
528 async_context_free (context);
529
530 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
531 }
532
533 static void
534 subscription_editor_unsubscribe_many (EMSubscriptionEditor *editor,
535 GQueue *tree_rows)
536 {
537 TreeRowData *tree_row_data;
538 AsyncContext *context;
539 CamelStore *active_store;
540 GdkCursor *cursor;
541 GdkWindow *window;
542
543 g_return_if_fail (editor != NULL);
544
545 if (g_queue_is_empty (tree_rows))
546 return;
547
548 tree_row_data = g_queue_peek_head (tree_rows);
549 g_return_if_fail (tree_row_data != NULL);
550
551 /* Cancel any operation on this store still in progress. */
552 gtk_button_clicked (GTK_BUTTON (editor->priv->stop_button));
553
554 /* Start a new 'subscription' operation. */
555 editor->priv->active->cancellable = g_cancellable_new ();
556
557 gtk_widget_set_sensitive (editor->priv->notebook, FALSE);
558 gtk_widget_set_sensitive (editor->priv->subscribe_button, FALSE);
559 gtk_widget_set_sensitive (editor->priv->subscribe_arrow, FALSE);
560 gtk_widget_set_sensitive (editor->priv->unsubscribe_button, FALSE);
561 gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, FALSE);
562 gtk_widget_set_sensitive (editor->priv->refresh_button, FALSE);
563 gtk_widget_set_sensitive (editor->priv->stop_button, TRUE);
564
565 cursor = gdk_cursor_new (GDK_WATCH);
566 window = gtk_widget_get_window (GTK_WIDGET (editor));
567 gdk_window_set_cursor (window, cursor);
568 g_object_unref (cursor);
569
570 context = async_context_new (editor, tree_rows);
571
572 active_store = editor->priv->active->store;
573
574 camel_subscribable_unsubscribe_folder (
575 CAMEL_SUBSCRIBABLE (active_store),
576 tree_row_data->folder_info->full_name, G_PRIORITY_DEFAULT,
577 editor->priv->active->cancellable, (GAsyncReadyCallback)
578 subscription_editor_unsubscribe_folder_done, context);
579 }
580
581 static GtkWidget *
582 subscription_editor_create_menu_item (const gchar *label,
583 gboolean sensitive,
584 GCallback activate_cb,
585 EMSubscriptionEditor *editor)
586 {
587 GtkWidget *item;
588
589 item = gtk_menu_item_new_with_mnemonic (label);
590 gtk_widget_set_sensitive (item, sensitive);
591
592 gtk_widget_show (item);
593
594 g_signal_connect_swapped (
595 item, "activate", activate_cb, editor);
596
597 return item;
598 }
599
600 static void
601 position_below_widget_cb (GtkMenu *menu,
602 gint *x,
603 gint *y,
604 gboolean *push_in,
605 gpointer under_widget)
606 {
607 GtkRequisition menu_requisition;
608 GtkTextDirection direction;
609 GtkAllocation allocation;
610 GdkRectangle monitor;
611 GdkScreen *screen;
612 GdkWindow *window;
613 GtkWidget *widget;
614 gint monitor_num;
615
616 widget = under_widget;
617 gtk_widget_get_preferred_size (
618 GTK_WIDGET (menu), &menu_requisition, NULL);
619
620 window = gtk_widget_get_parent_window (widget);
621 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
622 monitor_num = gdk_screen_get_monitor_at_window (screen, window);
623 if (monitor_num < 0)
624 monitor_num = 0;
625 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
626
627 gtk_widget_get_allocation (widget, &allocation);
628
629 gdk_window_get_origin (window, x, y);
630 *x += allocation.x;
631 *y += allocation.y + 2 + gtk_widget_get_allocated_height (under_widget);
632
633 direction = gtk_widget_get_direction (widget);
634 if (direction == GTK_TEXT_DIR_LTR)
635 *x += MAX (allocation.width - menu_requisition.width, 0);
636 else if (menu_requisition.width > allocation.width)
637 *x -= menu_requisition.width - allocation.width;
638
639 *push_in = FALSE;
640 }
641
642 static TreeRowData *
643 subscription_editor_tree_row_data_from_iter (GtkTreeView *tree_view,
644 GtkTreeModel *model,
645 GtkTreeIter *iter,
646 gboolean *is_expanded)
647 {
648 TreeRowData *tree_row_data;
649 CamelFolderInfo *folder_info = NULL;
650 GtkTreeRowReference *reference;
651 GtkTreePath *path;
652
653 gtk_tree_model_get (
654 model, iter, COL_FOLDER_INFO, &folder_info, -1);
655
656 if (!FOLDER_CAN_SELECT (folder_info))
657 return NULL;
658
659 path = gtk_tree_model_get_path (model, iter);
660 reference = gtk_tree_row_reference_new (model, path);
661 if (is_expanded)
662 *is_expanded = gtk_tree_view_row_expanded (tree_view, path);
663 gtk_tree_path_free (path);
664
665 tree_row_data = g_slice_new0 (TreeRowData);
666 tree_row_data->folder_info = folder_info;
667 tree_row_data->reference = reference;
668
669 return tree_row_data;
670 }
671
672 typedef enum {
673 PICK_ALL,
674 PICK_SUBSCRIBED,
675 PICK_UNSUBSCRIBED
676 } EPickMode;
677
678 static gboolean
679 can_pick_folder_info (CamelFolderInfo *fi,
680 EPickMode mode)
681 {
682 if (!FOLDER_CAN_SELECT (fi))
683 return FALSE;
684
685 if (mode == PICK_ALL)
686 return TRUE;
687
688 return (FOLDER_SUBSCRIBED (fi) ? 1 : 0) == (mode == PICK_SUBSCRIBED ? 1 : 0);
689 }
690
691 struct PickAllData {
692 GtkTreeView *tree_view;
693 EPickMode mode;
694 GHashTable *skip_folder_infos;
695 GQueue *out_tree_rows;
696 };
697
698 static gboolean
699 pick_all_cb (GtkTreeModel *model,
700 GtkTreePath *path,
701 GtkTreeIter *iter,
702 gpointer user_data)
703 {
704 struct PickAllData *data = user_data;
705 TreeRowData *tree_row_data;
706
707 tree_row_data = subscription_editor_tree_row_data_from_iter (
708 data->tree_view, model, iter, NULL);
709 if (tree_row_data == NULL)
710 return FALSE;
711
712 if (can_pick_folder_info (tree_row_data->folder_info, data->mode) &&
713 (data->skip_folder_infos == NULL ||
714 !g_hash_table_lookup_extended (
715 data->skip_folder_infos,
716 tree_row_data->folder_info, NULL, NULL))) {
717 g_queue_push_tail (data->out_tree_rows, tree_row_data);
718 } else
719 tree_row_data_free (tree_row_data);
720
721 return FALSE;
722 }
723
724 /* skip_folder_infos contains CamelFolderInfo-s to skip;
725 * these should come from the tree view; can be NULL
726 * to include everything.
727 */
728 static void
729 subscription_editor_pick_all (EMSubscriptionEditor *editor,
730 EPickMode mode,
731 GHashTable *skip_folder_infos,
732 GQueue *out_tree_rows)
733 {
734 GtkTreeView *tree_view;
735 GtkTreeModel *tree_model;
736 struct PickAllData data;
737
738 tree_view = editor->priv->active->tree_view;
739 tree_model = gtk_tree_view_get_model (tree_view);
740
741 data.tree_view = tree_view;
742 data.mode = mode;
743 data.skip_folder_infos = skip_folder_infos;
744 data.out_tree_rows = out_tree_rows;
745
746 gtk_tree_model_foreach (tree_model, pick_all_cb, &data);
747 }
748
749 static void
750 subscription_editor_pick_shown (EMSubscriptionEditor *editor,
751 EPickMode mode,
752 GQueue *out_tree_rows)
753 {
754 GtkTreeView *tree_view;
755 GtkTreeModel *tree_model;
756 GtkTreeIter iter, iter2;
757 gboolean found = TRUE;
758
759 tree_view = editor->priv->active->tree_view;
760 tree_model = gtk_tree_view_get_model (tree_view);
761
762 if (!gtk_tree_model_get_iter_first (tree_model, &iter))
763 return;
764
765 while (found) {
766 TreeRowData *tree_row_data;
767 gboolean is_expanded = FALSE;
768
769 found = FALSE;
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
770 tree_row_data = subscription_editor_tree_row_data_from_iter (
771 tree_view, tree_model, &iter, &is_expanded);
772
773 if (tree_row_data != NULL) {
774 if (can_pick_folder_info (tree_row_data->folder_info, mode))
775 g_queue_push_tail (out_tree_rows, tree_row_data);
776 else
777 tree_row_data_free (tree_row_data);
778 }
779
780 if (is_expanded && gtk_tree_model_iter_children (
781 tree_model, &iter2, &iter)) {
782 iter = iter2;
783 found = TRUE;
784 } else {
785 iter2 = iter;
786 if (gtk_tree_model_iter_next (tree_model, &iter2)) {
787 iter = iter2;
788 found = TRUE;
789 } else {
790 while (found = gtk_tree_model_iter_parent (
791 tree_model, &iter2, &iter), found) {
792 iter = iter2;
793 if (gtk_tree_model_iter_next (
794 tree_model, &iter2)) {
795 iter = iter2;
796 break;
797 }
798 }
799 }
800 }
801 }
802 }
803
804 static void
805 subscription_editor_subscribe (EMSubscriptionEditor *editor)
806 {
807 GtkTreeSelection *selection;
808 GtkTreeModel *tree_model;
809 GtkTreeView *tree_view;
810 GtkTreeIter iter;
811 gboolean have_selection;
812 GQueue tree_rows = G_QUEUE_INIT;
813 TreeRowData *tree_row_data;
814
815 tree_view = editor->priv->active->tree_view;
816 selection = gtk_tree_view_get_selection (tree_view);
817
818 have_selection = gtk_tree_selection_get_selected (
819 selection, &tree_model, &iter);
820 g_return_if_fail (have_selection);
821
822 tree_row_data = subscription_editor_tree_row_data_from_iter (
823 tree_view, tree_model, &iter, NULL);
824
825 g_queue_push_tail (&tree_rows, tree_row_data);
826 subscription_editor_subscribe_many (editor, &tree_rows);
827 g_warn_if_fail (g_queue_is_empty (&tree_rows));
828 }
829
830 static void
831 subscription_editor_subscribe_shown (EMSubscriptionEditor *editor)
832 {
833 GQueue tree_rows = G_QUEUE_INIT;
834
835 subscription_editor_pick_shown (
836 editor, PICK_UNSUBSCRIBED, &tree_rows);
837 subscription_editor_subscribe_many (editor, &tree_rows);
838 }
839
840 static void
841 subscription_editor_subscribe_all (EMSubscriptionEditor *editor)
842 {
843 GQueue tree_rows = G_QUEUE_INIT;
844
845 subscription_editor_pick_all (
846 editor, PICK_UNSUBSCRIBED, NULL, &tree_rows);
847 subscription_editor_subscribe_many (editor, &tree_rows);
848 }
849
850 static void
851 subscription_editor_subscribe_popup_cb (EMSubscriptionEditor *editor)
852 {
853 GtkWidget *menu;
854 GtkTreeIter iter;
855 gboolean tree_filled;
856
857 tree_filled = editor->priv->active &&
858 gtk_tree_model_get_iter_first (
859 editor->priv->active->filtered_view
860 ? editor->priv->active->list_store
861 : editor->priv->active->tree_store,
862 &iter);
863
864 menu = gtk_menu_new ();
865
866 gtk_menu_shell_append (
867 GTK_MENU_SHELL (menu),
868 subscription_editor_create_menu_item (
869 _("_Subscribe"),
870 gtk_widget_get_sensitive (
871 editor->priv->subscribe_button),
872 G_CALLBACK (subscription_editor_subscribe),
873 editor));
874
875 gtk_menu_shell_append (
876 GTK_MENU_SHELL (menu),
877 subscription_editor_create_menu_item (
878 _("Su_bscribe To Shown"),
879 tree_filled,
880 G_CALLBACK (subscription_editor_subscribe_shown),
881 editor));
882
883 gtk_menu_shell_append (
884 GTK_MENU_SHELL (menu),
885 subscription_editor_create_menu_item (
886 _("Subscribe To _All"),
887 tree_filled,
888 G_CALLBACK (subscription_editor_subscribe_all),
889 editor));
890
891 gtk_menu_popup (
892 GTK_MENU (menu), NULL, NULL,
893 position_below_widget_cb,
894 editor->priv->subscribe_button,
895 0, gtk_get_current_event_time ());
896 }
897
898 static void
899 subscription_editor_unsubscribe_hidden (EMSubscriptionEditor *editor)
900 {
901 GQueue tree_rows = G_QUEUE_INIT;
902 GHashTable *skip_shown;
903
904 subscription_editor_pick_shown (editor, PICK_ALL, &tree_rows);
905 g_return_if_fail (!g_queue_is_empty (&tree_rows));
906
907 skip_shown = g_hash_table_new (g_direct_hash, g_direct_equal);
908
909 while (!g_queue_is_empty (&tree_rows)) {
910 TreeRowData *tree_row_data;
911
912 tree_row_data = g_queue_pop_head (&tree_rows);
913
914 if (tree_row_data == NULL)
915 continue;
916
917 g_hash_table_insert (
918 skip_shown,
919 tree_row_data->folder_info,
920 GINT_TO_POINTER (1));
921
922 tree_row_data_free (tree_row_data);
923 }
924
925 subscription_editor_pick_all (
926 editor, PICK_SUBSCRIBED, skip_shown, &tree_rows);
927 subscription_editor_unsubscribe_many (editor, &tree_rows);
928
929 g_hash_table_destroy (skip_shown);
930 }
931
932 static void
933 subscription_editor_unsubscribe_all (EMSubscriptionEditor *editor)
934 {
935 GQueue tree_rows = G_QUEUE_INIT;
936
937 subscription_editor_pick_all (
938 editor, PICK_SUBSCRIBED, NULL, &tree_rows);
939 subscription_editor_unsubscribe_many (editor, &tree_rows);
940 }
941
942 static void
943 subscription_editor_unsubscribe (EMSubscriptionEditor *editor)
944 {
945 GtkTreeSelection *selection;
946 GtkTreeModel *tree_model;
947 GtkTreeView *tree_view;
948 GtkTreeIter iter;
949 gboolean have_selection;
950 GQueue tree_rows = G_QUEUE_INIT;
951 TreeRowData *tree_row_data;
952
953 tree_view = editor->priv->active->tree_view;
954 selection = gtk_tree_view_get_selection (tree_view);
955
956 have_selection = gtk_tree_selection_get_selected (
957 selection, &tree_model, &iter);
958 g_return_if_fail (have_selection);
959
960 tree_row_data = subscription_editor_tree_row_data_from_iter (
961 tree_view, tree_model, &iter, NULL);
962
963 g_queue_push_tail (&tree_rows, tree_row_data);
964 subscription_editor_unsubscribe_many (editor, &tree_rows);
965 }
966
967 static void
968 subscription_editor_unsubscribe_popup_cb (EMSubscriptionEditor *editor)
969 {
970 GtkWidget *menu;
971 GtkTreeIter iter;
972 gboolean tree_filled;
973
974 tree_filled = editor->priv->active &&
975 gtk_tree_model_get_iter_first (
976 editor->priv->active->filtered_view
977 ? editor->priv->active->list_store
978 : editor->priv->active->tree_store,
979 &iter);
980
981 menu = gtk_menu_new ();
982
983 gtk_menu_shell_append (
984 GTK_MENU_SHELL (menu),
985 subscription_editor_create_menu_item (
986 _("_Unsubscribe"),
987 gtk_widget_get_sensitive (
988 editor->priv->unsubscribe_button),
989 G_CALLBACK (subscription_editor_unsubscribe),
990 editor));
991
992 gtk_menu_shell_append (
993 GTK_MENU_SHELL (menu),
994 subscription_editor_create_menu_item (
995 _("Unsu_bscribe From Hidden"),
996 tree_filled,
997 G_CALLBACK (subscription_editor_unsubscribe_hidden),
998 editor));
999
1000 gtk_menu_shell_append (
1001 GTK_MENU_SHELL (menu),
1002 subscription_editor_create_menu_item (
1003 _("Unsubscribe From _All"),
1004 tree_filled,
1005 G_CALLBACK (subscription_editor_unsubscribe_all),
1006 editor));
1007
1008 gtk_menu_popup (
1009 GTK_MENU (menu), NULL, NULL,
1010 position_below_widget_cb,
1011 editor->priv->unsubscribe_button,
1012 0, gtk_get_current_event_time ());
1013 }
1014
1015 static void
1016 subscription_editor_collapse_all (EMSubscriptionEditor *editor)
1017 {
1018 gtk_tree_view_collapse_all (editor->priv->active->tree_view);
1019 }
1020
1021 static void
1022 subscription_editor_expand_all (EMSubscriptionEditor *editor)
1023 {
1024 gtk_tree_view_expand_all (editor->priv->active->tree_view);
1025 }
1026
1027 static void
1028 subscription_editor_refresh (EMSubscriptionEditor *editor)
1029 {
1030 GdkCursor *cursor;
1031 GdkWindow *window;
1032
1033 /* Cancel any operation on this store still in progress. */
1034 gtk_button_clicked (GTK_BUTTON (editor->priv->stop_button));
1035
1036 /* Start a new 'refresh' operation. */
1037 editor->priv->active->cancellable = g_cancellable_new ();
1038
1039 gtk_widget_set_sensitive (editor->priv->notebook, FALSE);
1040 gtk_widget_set_sensitive (editor->priv->subscribe_button, FALSE);
1041 gtk_widget_set_sensitive (editor->priv->subscribe_arrow, FALSE);
1042 gtk_widget_set_sensitive (editor->priv->unsubscribe_button, FALSE);
1043 gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, FALSE);
1044 gtk_widget_set_sensitive (editor->priv->refresh_button, FALSE);
1045 gtk_widget_set_sensitive (editor->priv->stop_button, TRUE);
1046
1047 cursor = gdk_cursor_new (GDK_WATCH);
1048 window = gtk_widget_get_window (GTK_WIDGET (editor));
1049 gdk_window_set_cursor (window, cursor);
1050 g_object_unref (cursor);
1051
1052 camel_store_get_folder_info (
1053 editor->priv->active->store, NULL,
1054 CAMEL_STORE_FOLDER_INFO_RECURSIVE |
1055 CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL |
1056 CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST,
1057 G_PRIORITY_DEFAULT, editor->priv->active->cancellable,
1058 (GAsyncReadyCallback) subscription_editor_get_folder_info_done,
1059 g_object_ref (editor));
1060 }
1061
1062 static void
1063 subscription_editor_stop (EMSubscriptionEditor *editor)
1064 {
1065 GdkWindow *window;
1066
1067 if (editor->priv->active->cancellable != NULL) {
1068 g_cancellable_cancel (editor->priv->active->cancellable);
1069 g_object_unref (editor->priv->active->cancellable);
1070 editor->priv->active->cancellable = NULL;
1071 }
1072
1073 gtk_widget_set_sensitive (editor->priv->notebook, TRUE);
1074 gtk_widget_set_sensitive (editor->priv->subscribe_button, TRUE);
1075 gtk_widget_set_sensitive (editor->priv->subscribe_arrow, TRUE);
1076 gtk_widget_set_sensitive (editor->priv->unsubscribe_button, TRUE);
1077 gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, TRUE);
1078 gtk_widget_set_sensitive (editor->priv->refresh_button, TRUE);
1079 gtk_widget_set_sensitive (editor->priv->stop_button, FALSE);
1080 gtk_widget_grab_focus (GTK_WIDGET (editor->priv->active->tree_view));
1081
1082 window = gtk_widget_get_window (GTK_WIDGET (editor));
1083 gdk_window_set_cursor (window, NULL);
1084 }
1085
1086 static gboolean
1087 subscription_editor_filter_cb (GtkTreeModel *tree_model,
1088 GtkTreeIter *iter,
1089 EMSubscriptionEditor *editor)
1090 {
1091 CamelFolderInfo *folder_info;
1092 gchar *casefolded;
1093 gboolean match;
1094
1095 /* If there's no search string let everything through. */
1096 if (editor->priv->search_string == NULL)
1097 return TRUE;
1098
1099 gtk_tree_model_get (
1100 tree_model, iter,
1101 COL_CASEFOLDED, &casefolded,
1102 COL_FOLDER_INFO, &folder_info, -1);
1103
1104 match = FOLDER_CAN_SELECT (folder_info) &&
1105 (casefolded != NULL) && (*casefolded != '\0') &&
1106 (strstr (casefolded, editor->priv->search_string) != NULL);
1107
1108 g_free (casefolded);
1109
1110 return match;
1111 }
1112
1113 static void
1114 subscription_editor_update_view (EMSubscriptionEditor *editor)
1115 {
1116 GtkEntry *entry;
1117 GtkTreeView *tree_view;
1118 GtkTreeModel *tree_model;
1119 const gchar *text;
1120
1121 entry = GTK_ENTRY (editor->priv->entry);
1122 tree_view = editor->priv->active->tree_view;
1123
1124 editor->priv->timeout_id = 0;
1125
1126 text = gtk_entry_get_text (entry);
1127
1128 if (text != NULL && *text != '\0') {
1129 g_free (editor->priv->search_string);
1130 editor->priv->search_string = g_utf8_casefold (text, -1);
1131
1132 /* Install the list store in the tree view if needed. */
1133 if (!editor->priv->active->filtered_view) {
1134 GtkTreeSelection *selection;
1135 GtkTreePath *path;
1136
1137 tree_model = gtk_tree_model_filter_new (
1138 editor->priv->active->list_store, NULL);
1139 gtk_tree_model_filter_set_visible_func (
1140 GTK_TREE_MODEL_FILTER (tree_model),
1141 (GtkTreeModelFilterVisibleFunc)
1142 subscription_editor_filter_cb, editor,
1143 (GDestroyNotify) NULL);
1144 gtk_tree_view_set_model (tree_view, tree_model);
1145 g_object_unref (tree_model);
1146
1147 path = gtk_tree_path_new_first ();
1148 selection = gtk_tree_view_get_selection (tree_view);
1149 gtk_tree_selection_select_path (selection, path);
1150 gtk_tree_path_free (path);
1151
1152 editor->priv->active->filtered_view = TRUE;
1153 }
1154
1155 tree_model = gtk_tree_view_get_model (tree_view);
1156 gtk_tree_model_filter_refilter (
1157 GTK_TREE_MODEL_FILTER (tree_model));
1158
1159 gtk_entry_set_icon_sensitive (
1160 entry, GTK_ENTRY_ICON_SECONDARY, TRUE);
1161
1162 gtk_widget_set_sensitive (
1163 editor->priv->collapse_all_button, FALSE);
1164 gtk_widget_set_sensitive (
1165 editor->priv->expand_all_button, FALSE);
1166
1167 } else {
1168 /* Install the tree store in the tree view if needed. */
1169 if (editor->priv->active->filtered_view) {
1170 GtkTreeSelection *selection;
1171 GtkTreePath *path;
1172
1173 tree_model = editor->priv->active->tree_store;
1174 gtk_tree_view_set_model (tree_view, tree_model);
1175
1176 path = gtk_tree_path_new_first ();
1177 selection = gtk_tree_view_get_selection (tree_view);
1178 gtk_tree_selection_select_path (selection, path);
1179 gtk_tree_path_free (path);
1180
1181 editor->priv->active->filtered_view = FALSE;
1182 }
1183
1184 gtk_entry_set_icon_sensitive (
1185 entry, GTK_ENTRY_ICON_SECONDARY, FALSE);
1186
1187 gtk_widget_set_sensitive (
1188 editor->priv->collapse_all_button, TRUE);
1189 gtk_widget_set_sensitive (
1190 editor->priv->expand_all_button, TRUE);
1191 }
1192 }
1193
1194 static gboolean
1195 subscription_editor_timeout_cb (EMSubscriptionEditor *editor)
1196 {
1197 subscription_editor_update_view (editor);
1198 editor->priv->timeout_id = 0;
1199
1200 return FALSE;
1201 }
1202
1203 static void
1204 subscription_editor_combo_box_changed_cb (GtkComboBox *combo_box,
1205 EMSubscriptionEditor *editor)
1206 {
1207 StoreData *data;
1208 gint index;
1209
1210 index = gtk_combo_box_get_active (combo_box);
1211 g_return_if_fail (index < editor->priv->stores->len);
1212
1213 data = g_ptr_array_index (editor->priv->stores, index);
1214 g_return_if_fail (data != NULL);
1215
1216 editor->priv->active = data;
1217
1218 subscription_editor_stop (editor);
1219 subscription_editor_update_view (editor);
1220
1221 g_object_notify (G_OBJECT (editor), "store");
1222
1223 if (data->needs_refresh) {
1224 subscription_editor_refresh (editor);
1225 data->needs_refresh = FALSE;
1226 }
1227 }
1228
1229 static void
1230 subscription_editor_entry_changed_cb (GtkEntry *entry,
1231 EMSubscriptionEditor *editor)
1232 {
1233 const gchar *text;
1234
1235 if (editor->priv->timeout_id > 0) {
1236 g_source_remove (editor->priv->timeout_id);
1237 editor->priv->timeout_id = 0;
1238 }
1239
1240 text = gtk_entry_get_text (entry);
1241
1242 if (text != NULL && *text != '\0')
1243 editor->priv->timeout_id = g_timeout_add_seconds (
1244 1, (GSourceFunc) subscription_editor_timeout_cb, editor);
1245 else
1246 subscription_editor_update_view (editor);
1247 }
1248
1249 static void
1250 subscription_editor_icon_release_cb (GtkEntry *entry,
1251 GtkEntryIconPosition icon_pos,
1252 GdkEvent *event,
1253 EMSubscriptionEditor *editor)
1254 {
1255 if (icon_pos == GTK_ENTRY_ICON_SECONDARY)
1256 gtk_entry_set_text (entry, "");
1257 }
1258
1259 static void
1260 subscription_editor_renderer_toggled_cb (GtkCellRendererToggle *renderer,
1261 const gchar *path_string,
1262 EMSubscriptionEditor *editor)
1263 {
1264 GtkTreeSelection *selection;
1265 GtkTreeView *tree_view;
1266 GtkTreePath *path;
1267
1268 tree_view = editor->priv->active->tree_view;
1269 selection = gtk_tree_view_get_selection (tree_view);
1270
1271 path = gtk_tree_path_new_from_string (path_string);
1272 gtk_tree_selection_select_path (selection, path);
1273 gtk_tree_path_free (path);
1274
1275 if (gtk_cell_renderer_toggle_get_active (renderer))
1276 subscription_editor_unsubscribe (editor);
1277 else
1278 subscription_editor_subscribe (editor);
1279 }
1280
1281 static void
1282 subscription_editor_render_toggle_cb (GtkCellLayout *cell_layout,
1283 GtkCellRenderer *renderer,
1284 GtkTreeModel *tree_model,
1285 GtkTreeIter *iter)
1286 {
1287 CamelFolderInfo *folder_info;
1288
1289 gtk_tree_model_get (
1290 tree_model, iter, COL_FOLDER_INFO, &folder_info, -1);
1291
1292 g_object_set (
1293 renderer, "active", FOLDER_SUBSCRIBED (folder_info),
1294 "visible", FOLDER_CAN_SELECT (folder_info), NULL);
1295 }
1296
1297 static void
1298 subscription_editor_selection_changed_cb (GtkTreeSelection *selection,
1299 EMSubscriptionEditor *editor)
1300 {
1301 GtkTreeModel *tree_model;
1302 GtkTreeIter iter;
1303
1304 if (gtk_tree_selection_get_selected (selection, &tree_model, &iter)) {
1305 CamelFolderInfo *folder_info;
1306
1307 gtk_tree_model_get (
1308 tree_model, &iter,
1309 COL_FOLDER_INFO, &folder_info, -1);
1310 gtk_widget_set_sensitive (
1311 editor->priv->subscribe_button,
1312 FOLDER_CAN_SELECT (folder_info) &&
1313 !FOLDER_SUBSCRIBED (folder_info));
1314 gtk_widget_set_sensitive (
1315 editor->priv->unsubscribe_button,
1316 FOLDER_CAN_SELECT (folder_info) &&
1317 FOLDER_SUBSCRIBED (folder_info));
1318 } else {
1319 gtk_widget_set_sensitive (
1320 editor->priv->subscribe_button, FALSE);
1321 gtk_widget_set_sensitive (
1322 editor->priv->unsubscribe_button, FALSE);
1323 }
1324
1325 gtk_widget_set_sensitive (editor->priv->subscribe_arrow, TRUE);
1326 gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, TRUE);
1327 }
1328
1329 static void
1330 subscription_editor_add_store (EMSubscriptionEditor *editor,
1331 CamelStore *store)
1332 {
1333 StoreData *data;
1334 CamelService *service;
1335 GtkListStore *list_store;
1336 GtkTreeStore *tree_store;
1337 GtkTreeViewColumn *column;
1338 GtkTreeSelection *selection;
1339 GtkCellRenderer *renderer;
1340 GtkComboBoxText *combo_box;
1341 GtkWidget *container;
1342 GtkWidget *widget;
1343 const gchar *display_name;
1344
1345 service = CAMEL_SERVICE (store);
1346 display_name = camel_service_get_display_name (service);
1347
1348 combo_box = GTK_COMBO_BOX_TEXT (editor->priv->combo_box);
1349 gtk_combo_box_text_append_text (combo_box, display_name);
1350
1351 tree_store = gtk_tree_store_new (
1352 N_COLUMNS,
1353 /* COL_CASEFOLDED */ G_TYPE_STRING,
1354 /* COL_FOLDER_ICON */ G_TYPE_STRING,
1355 /* COL_FOLDER_NAME */ G_TYPE_STRING,
1356 /* COL_FOLDER_INFO */ G_TYPE_POINTER);
1357
1358 list_store = gtk_list_store_new (
1359 N_COLUMNS,
1360 /* COL_CASEFOLDED */ G_TYPE_STRING,
1361 /* COL_FOLDER_ICON */ G_TYPE_STRING,
1362 /* COL_FOLDER_NAME */ G_TYPE_STRING,
1363 /* COL_FOLDER_INFO */ G_TYPE_POINTER);
1364
1365 container = editor->priv->notebook;
1366
1367 widget = gtk_scrolled_window_new (NULL, NULL);
1368 gtk_scrolled_window_set_policy (
1369 GTK_SCROLLED_WINDOW (widget),
1370 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1371 gtk_scrolled_window_set_shadow_type (
1372 GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
1373 gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
1374 gtk_container_child_set (
1375 GTK_CONTAINER (container), widget,
1376 "tab-fill", FALSE, "tab-expand", FALSE, NULL);
1377 gtk_widget_show (widget);
1378
1379 container = widget;
1380
1381 widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store));
1382 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (widget), TRUE);
1383 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE);
1384 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (widget), TRUE);
1385 gtk_tree_view_set_search_column (
1386 GTK_TREE_VIEW (widget), COL_FOLDER_NAME);
1387 gtk_container_add (GTK_CONTAINER (container), widget);
1388 gtk_widget_show (widget);
1389
1390 column = gtk_tree_view_column_new ();
1391 gtk_tree_view_append_column (GTK_TREE_VIEW (widget), column);
1392
1393 renderer = gtk_cell_renderer_toggle_new ();
1394 g_object_set (renderer, "activatable", TRUE, NULL);
1395 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1396
1397 gtk_cell_layout_set_cell_data_func (
1398 GTK_CELL_LAYOUT (column), renderer,
1399 (GtkCellLayoutDataFunc) subscription_editor_render_toggle_cb,
1400 NULL, (GDestroyNotify) NULL);
1401
1402 g_signal_connect (
1403 renderer, "toggled",
1404 G_CALLBACK (subscription_editor_renderer_toggled_cb), editor);
1405
1406 column = gtk_tree_view_column_new ();
1407 gtk_tree_view_append_column (GTK_TREE_VIEW (widget), column);
1408 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (widget), column);
1409
1410 renderer = gtk_cell_renderer_pixbuf_new ();
1411 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1412 gtk_tree_view_column_add_attribute (
1413 column, renderer, "icon-name", COL_FOLDER_ICON);
1414
1415 renderer = gtk_cell_renderer_text_new ();
1416 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1417 gtk_tree_view_column_add_attribute (
1418 column, renderer, "text", COL_FOLDER_NAME);
1419
1420 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1421
1422 g_signal_connect (
1423 selection, "changed",
1424 G_CALLBACK (subscription_editor_selection_changed_cb), editor);
1425
1426 data = g_slice_new0 (StoreData);
1427 data->store = g_object_ref (store);
1428 data->tree_view = g_object_ref (widget);
1429 data->list_store = GTK_TREE_MODEL (list_store);
1430 data->tree_store = GTK_TREE_MODEL (tree_store);
1431 data->needs_refresh = TRUE;
1432
1433 g_ptr_array_add (editor->priv->stores, data);
1434 }
1435
1436 static void
1437 subscription_editor_set_store (EMSubscriptionEditor *editor,
1438 CamelStore *store)
1439 {
1440 g_return_if_fail (editor->priv->initial_store == NULL);
1441
1442 if (CAMEL_IS_SUBSCRIBABLE (store))
1443 editor->priv->initial_store = g_object_ref (store);
1444 }
1445
1446 static void
1447 subscription_editor_set_session (EMSubscriptionEditor *editor,
1448 EMailSession *session)
1449 {
1450 g_return_if_fail (E_IS_MAIL_SESSION (session));
1451 g_return_if_fail (editor->priv->session == NULL);
1452
1453 editor->priv->session = g_object_ref (session);
1454 }
1455
1456 static void
1457 subscription_editor_set_property (GObject *object,
1458 guint property_id,
1459 const GValue *value,
1460 GParamSpec *pspec)
1461 {
1462 switch (property_id) {
1463 case PROP_SESSION:
1464 subscription_editor_set_session (
1465 EM_SUBSCRIPTION_EDITOR (object),
1466 g_value_get_object (value));
1467 return;
1468
1469 case PROP_STORE:
1470 subscription_editor_set_store (
1471 EM_SUBSCRIPTION_EDITOR (object),
1472 g_value_get_object (value));
1473 return;
1474 }
1475
1476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1477 }
1478
1479 static void
1480 subscription_editor_get_property (GObject *object,
1481 guint property_id,
1482 GValue *value,
1483 GParamSpec *pspec)
1484 {
1485 switch (property_id) {
1486 case PROP_SESSION:
1487 g_value_set_object (
1488 value,
1489 em_subscription_editor_get_session (
1490 EM_SUBSCRIPTION_EDITOR (object)));
1491 return;
1492
1493 case PROP_STORE:
1494 g_value_set_object (
1495 value,
1496 em_subscription_editor_get_store (
1497 EM_SUBSCRIPTION_EDITOR (object)));
1498 return;
1499 }
1500
1501 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1502 }
1503
1504 static void
1505 subscription_editor_dispose (GObject *object)
1506 {
1507 EMSubscriptionEditorPrivate *priv;
1508
1509 priv = EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (object);
1510
1511 if (priv->session != NULL) {
1512 g_object_unref (priv->session);
1513 priv->session = NULL;
1514 }
1515
1516 if (priv->initial_store != NULL) {
1517 g_object_unref (priv->initial_store);
1518 priv->initial_store = NULL;
1519 }
1520
1521 if (priv->timeout_id > 0) {
1522 g_source_remove (priv->timeout_id);
1523 priv->timeout_id = 0;
1524 }
1525
1526 g_ptr_array_set_size (priv->stores, 0);
1527
1528 /* Chain up to parent's dispose() method. */
1529 G_OBJECT_CLASS (em_subscription_editor_parent_class)->dispose (object);
1530 }
1531
1532 static void
1533 subscription_editor_finalize (GObject *object)
1534 {
1535 EMSubscriptionEditorPrivate *priv;
1536
1537 priv = EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (object);
1538
1539 g_ptr_array_free (priv->stores, TRUE);
1540
1541 g_free (priv->search_string);
1542
1543 /* Chain up to parent's finalize() method. */
1544 G_OBJECT_CLASS (em_subscription_editor_parent_class)->finalize (object);
1545 }
1546
1547 static void
1548 subscription_editor_constructed (GObject *object)
1549 {
1550 EMSubscriptionEditor *editor;
1551
1552 editor = EM_SUBSCRIPTION_EDITOR (object);
1553
1554 /* Pick an initial store based on the default mail account, if
1555 * one wasn't already given in em_subscription_editor_new(). */
1556 if (editor->priv->initial_store == NULL) {
1557 ESource *source;
1558 ESourceRegistry *registry;
1559 CamelService *service;
1560 EMailSession *session;
1561
1562 session = em_subscription_editor_get_session (editor);
1563 registry = e_mail_session_get_registry (session);
1564
1565 source = e_source_registry_ref_default_mail_account (registry);
1566
1567 service = camel_session_ref_service (
1568 CAMEL_SESSION (session),
1569 e_source_get_uid (source));
1570
1571 if (CAMEL_IS_SUBSCRIBABLE (service))
1572 editor->priv->initial_store = g_object_ref (service);
1573
1574 if (service != NULL)
1575 g_object_unref (service);
1576
1577 g_object_unref (source);
1578 }
1579
1580 /* Chain up to parent's constructed() method. */
1581 G_OBJECT_CLASS (em_subscription_editor_parent_class)->constructed (object);
1582 }
1583
1584 static void
1585 subscription_editor_realize (GtkWidget *widget)
1586 {
1587 EMSubscriptionEditor *editor;
1588 EMFolderTreeModel *model;
1589 GtkComboBox *combo_box;
1590 GList *list, *link;
1591 gint initial_index = 0;
1592
1593 editor = EM_SUBSCRIPTION_EDITOR (widget);
1594
1595 /* Chain up to parent's realize() method. */
1596 GTK_WIDGET_CLASS (em_subscription_editor_parent_class)->realize (widget);
1597
1598 /* Find stores to display, and watch for the initial store. */
1599
1600 model = em_folder_tree_model_get_default ();
1601 list = em_folder_tree_model_list_stores (model);
1602
1603 for (link = list; link != NULL; link = g_list_next (link)) {
1604 CamelStore *store = CAMEL_STORE (link->data);
1605
1606 if (!CAMEL_IS_SUBSCRIBABLE (store))
1607 continue;
1608
1609 if (store == editor->priv->initial_store)
1610 initial_index = editor->priv->stores->len;
1611
1612 subscription_editor_add_store (editor, store);
1613 }
1614
1615 g_list_free (list);
1616
1617 /* The subscription editor should only be accessible if
1618 * at least one enabled store supports subscriptions. */
1619 g_return_if_fail (editor->priv->stores->len > 0);
1620
1621 combo_box = GTK_COMBO_BOX (editor->priv->combo_box);
1622 gtk_combo_box_set_active (combo_box, initial_index);
1623 }
1624
1625 static void
1626 em_subscription_editor_class_init (EMSubscriptionEditorClass *class)
1627 {
1628 GObjectClass *object_class;
1629 GtkWidgetClass *widget_class;
1630
1631 g_type_class_add_private (class, sizeof (EMSubscriptionEditorPrivate));
1632
1633 object_class = G_OBJECT_CLASS (class);
1634 object_class->set_property = subscription_editor_set_property;
1635 object_class->get_property = subscription_editor_get_property;
1636 object_class->dispose = subscription_editor_dispose;
1637 object_class->finalize = subscription_editor_finalize;
1638 object_class->constructed = subscription_editor_constructed;
1639
1640 widget_class = GTK_WIDGET_CLASS (class);
1641 widget_class->realize = subscription_editor_realize;
1642
1643 g_object_class_install_property (
1644 object_class,
1645 PROP_SESSION,
1646 g_param_spec_object (
1647 "session",
1648 NULL,
1649 NULL,
1650 E_TYPE_MAIL_SESSION,
1651 G_PARAM_READWRITE |
1652 G_PARAM_CONSTRUCT_ONLY |
1653 G_PARAM_STATIC_STRINGS));
1654
1655 g_object_class_install_property (
1656 object_class,
1657 PROP_STORE,
1658 g_param_spec_object (
1659 "store",
1660 NULL,
1661 NULL,
1662 CAMEL_TYPE_STORE,
1663 G_PARAM_READWRITE |
1664 G_PARAM_CONSTRUCT_ONLY |
1665 G_PARAM_STATIC_STRINGS));
1666 }
1667
1668 static void
1669 em_subscription_editor_init (EMSubscriptionEditor *editor)
1670 {
1671 GtkWidget *container;
1672 GtkWidget *widget;
1673 GtkWidget *box;
1674 const gchar *tooltip;
1675
1676 editor->priv = EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (editor);
1677
1678 editor->priv->stores = g_ptr_array_new_with_free_func (
1679 (GDestroyNotify) store_data_free);
1680
1681 gtk_container_set_border_width (GTK_CONTAINER (editor), 5);
1682 gtk_window_set_title (GTK_WINDOW (editor), _("Folder Subscriptions"));
1683 gtk_window_set_default_size (GTK_WINDOW (editor), 600, 400);
1684
1685 e_restore_window (
1686 GTK_WINDOW (editor),
1687 "/org/gnome/evolution/mail/subscription-window/",
1688 E_RESTORE_WINDOW_SIZE);
1689
1690 gtk_dialog_add_button (
1691 GTK_DIALOG (editor),
1692 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
1693
1694 container = gtk_dialog_get_content_area (GTK_DIALOG (editor));
1695
1696 widget = gtk_vbox_new (FALSE, 12);
1697 gtk_container_set_border_width (GTK_CONTAINER (widget), 5);
1698 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
1699 gtk_widget_show (widget);
1700
1701 container = box = widget;
1702
1703 widget = gtk_table_new (2, 3, FALSE);
1704 gtk_table_set_col_spacings (GTK_TABLE (widget), 6);
1705 gtk_table_set_row_spacings (GTK_TABLE (widget), 6);
1706 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
1707 gtk_widget_show (widget);
1708
1709 container = widget;
1710
1711 widget = gtk_combo_box_text_new ();
1712 gtk_table_attach (
1713 GTK_TABLE (container), widget,
1714 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1715 editor->priv->combo_box = widget;
1716 gtk_widget_show (widget);
1717
1718 g_signal_connect (
1719 widget, "changed",
1720 G_CALLBACK (subscription_editor_combo_box_changed_cb), editor);
1721
1722 widget = gtk_label_new_with_mnemonic (_("_Account:"));
1723 gtk_label_set_mnemonic_widget (
1724 GTK_LABEL (widget), editor->priv->combo_box);
1725 gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
1726 gtk_table_attach (
1727 GTK_TABLE (container), widget,
1728 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
1729 gtk_widget_show (widget);
1730
1731 widget = gtk_entry_new ();
1732 gtk_entry_set_icon_from_stock (
1733 GTK_ENTRY (widget),
1734 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1735 gtk_entry_set_icon_tooltip_text (
1736 GTK_ENTRY (widget),
1737 GTK_ENTRY_ICON_SECONDARY, _("Clear Search"));
1738 gtk_entry_set_icon_sensitive (
1739 GTK_ENTRY (widget),
1740 GTK_ENTRY_ICON_SECONDARY, FALSE);
1741 gtk_table_attach (
1742 GTK_TABLE (container), widget,
1743 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1744 editor->priv->entry = widget;
1745 gtk_widget_show (widget);
1746
1747 g_signal_connect (
1748 widget, "changed",
1749 G_CALLBACK (subscription_editor_entry_changed_cb), editor);
1750
1751 g_signal_connect (
1752 widget, "icon-release",
1753 G_CALLBACK (subscription_editor_icon_release_cb), editor);
1754
1755 widget = gtk_label_new_with_mnemonic (_("Sho_w items that contain:"));
1756 gtk_label_set_mnemonic_widget (
1757 GTK_LABEL (widget), editor->priv->entry);
1758 gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
1759 gtk_table_attach (
1760 GTK_TABLE (container), widget,
1761 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
1762 gtk_widget_show (widget);
1763
1764 container = box;
1765
1766 widget = gtk_hbox_new (FALSE, 6);
1767 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
1768 gtk_widget_show (widget);
1769
1770 container = widget;
1771
1772 widget = gtk_notebook_new ();
1773 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
1774 gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
1775 gtk_container_add (GTK_CONTAINER (container), widget);
1776 editor->priv->notebook = widget;
1777 gtk_widget_show (widget);
1778
1779 g_object_bind_property (
1780 editor->priv->combo_box, "active",
1781 editor->priv->notebook, "page",
1782 G_BINDING_BIDIRECTIONAL |
1783 G_BINDING_SYNC_CREATE);
1784
1785 widget = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
1786 gtk_box_set_spacing (GTK_BOX (widget), 6);
1787 gtk_button_box_set_layout (
1788 GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
1789 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
1790 gtk_widget_show (widget);
1791
1792 container = box = widget;
1793
1794 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
1795 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
1796 gtk_widget_show (widget);
1797
1798 container = widget;
1799
1800 tooltip = _("Subscribe to the selected folder");
1801 widget = gtk_button_new_with_mnemonic (_("Su_bscribe"));
1802 gtk_widget_set_sensitive (widget, FALSE);
1803 gtk_widget_set_tooltip_text (widget, tooltip);
1804 editor->priv->subscribe_button = widget;
1805 gtk_widget_show (widget);
1806
1807 g_signal_connect_swapped (
1808 widget, "clicked",
1809 G_CALLBACK (subscription_editor_subscribe), editor);
1810
1811 widget = gtk_button_new ();
1812 gtk_button_set_image (
1813 GTK_BUTTON (widget),
1814 gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
1815 editor->priv->subscribe_arrow = widget;
1816 gtk_widget_show (widget);
1817
1818 g_signal_connect_swapped (
1819 widget, "clicked",
1820 G_CALLBACK (subscription_editor_subscribe_popup_cb), editor);
1821
1822 if (gtk_widget_get_direction (container) == GTK_TEXT_DIR_LTR) {
1823 gtk_box_pack_start (
1824 GTK_BOX (container),
1825 editor->priv->subscribe_button, TRUE, TRUE, 0);
1826 gtk_box_pack_start (
1827 GTK_BOX (container),
1828 editor->priv->subscribe_arrow, FALSE, FALSE, 0);
1829 } else {
1830 gtk_box_pack_start (
1831 GTK_BOX (container),
1832 editor->priv->subscribe_arrow, FALSE, FALSE, 0);
1833 gtk_box_pack_start (
1834 GTK_BOX (container),
1835 editor->priv->subscribe_button, TRUE, TRUE, 0);
1836 }
1837
1838 container = box;
1839
1840 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
1841 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
1842 gtk_widget_show (widget);
1843
1844 container = widget;
1845
1846 tooltip = _("Unsubscribe from the selected folder");
1847 widget = gtk_button_new_with_mnemonic (_("_Unsubscribe"));
1848 gtk_widget_set_sensitive (widget, FALSE);
1849 gtk_widget_set_tooltip_text (widget, tooltip);
1850 editor->priv->unsubscribe_button = widget;
1851 gtk_widget_show (widget);
1852
1853 g_signal_connect_swapped (
1854 widget, "clicked",
1855 G_CALLBACK (subscription_editor_unsubscribe), editor);
1856
1857 widget = gtk_button_new ();
1858 gtk_button_set_image (
1859 GTK_BUTTON (widget),
1860 gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
1861 editor->priv->unsubscribe_arrow = widget;
1862 gtk_widget_show (widget);
1863
1864 g_signal_connect_swapped (
1865 widget, "clicked",
1866 G_CALLBACK (subscription_editor_unsubscribe_popup_cb), editor);
1867
1868 if (gtk_widget_get_direction (container) == GTK_TEXT_DIR_LTR) {
1869 gtk_box_pack_start (
1870 GTK_BOX (container),
1871 editor->priv->unsubscribe_button, TRUE, TRUE, 0);
1872 gtk_box_pack_start (
1873 GTK_BOX (container),
1874 editor->priv->unsubscribe_arrow, FALSE, FALSE, 0);
1875 } else {
1876 gtk_box_pack_start (
1877 GTK_BOX (container),
1878 editor->priv->unsubscribe_arrow, FALSE, FALSE, 0);
1879 gtk_box_pack_start (
1880 GTK_BOX (container),
1881 editor->priv->unsubscribe_button, TRUE, TRUE, 0);
1882 }
1883
1884 container = box;
1885
1886 tooltip = _("Collapse all folders");
1887 widget = gtk_button_new_with_mnemonic (_("C_ollapse All"));
1888 gtk_widget_set_tooltip_text (widget, tooltip);
1889 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
1890 editor->priv->collapse_all_button = widget;
1891 gtk_widget_show (widget);
1892
1893 g_signal_connect_swapped (
1894 widget, "clicked",
1895 G_CALLBACK (subscription_editor_collapse_all), editor);
1896
1897 tooltip = _("Expand all folders");
1898 widget = gtk_button_new_with_mnemonic (_("E_xpand All"));
1899 gtk_widget_set_tooltip_text (widget, tooltip);
1900 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
1901 editor->priv->expand_all_button = widget;
1902 gtk_widget_show (widget);
1903
1904 g_signal_connect_swapped (
1905 widget, "clicked",
1906 G_CALLBACK (subscription_editor_expand_all), editor);
1907
1908 tooltip = _("Refresh the folder list");
1909 widget = gtk_button_new_from_stock (GTK_STOCK_REFRESH);
1910 gtk_widget_set_tooltip_text (widget, tooltip);
1911 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
1912 gtk_widget_set_sensitive (widget, FALSE);
1913 editor->priv->refresh_button = widget;
1914 gtk_widget_show (widget);
1915
1916 g_signal_connect_swapped (
1917 widget, "clicked",
1918 G_CALLBACK (subscription_editor_refresh), editor);
1919
1920 tooltip = _("Stop the current operation");
1921 widget = gtk_button_new_from_stock (GTK_STOCK_STOP);
1922 gtk_widget_set_tooltip_text (widget, tooltip);
1923 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
1924 gtk_widget_set_sensitive (widget, FALSE);
1925 editor->priv->stop_button = widget;
1926 gtk_widget_show (widget);
1927
1928 g_signal_connect_swapped (
1929 widget, "clicked",
1930 G_CALLBACK (subscription_editor_stop), editor);
1931 }
1932
1933 GtkWidget *
1934 em_subscription_editor_new (GtkWindow *parent,
1935 EMailSession *session,
1936 CamelStore *initial_store)
1937 {
1938 g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
1939 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
1940
1941 return g_object_new (
1942 EM_TYPE_SUBSCRIPTION_EDITOR,
1943 "session", session,
1944 "store", initial_store,
1945 "transient-for", parent,
1946 NULL);
1947 }
1948
1949 EMailSession *
1950 em_subscription_editor_get_session (EMSubscriptionEditor *editor)
1951 {
1952 g_return_val_if_fail (EM_IS_SUBSCRIPTION_EDITOR (editor), NULL);
1953
1954 return editor->priv->session;
1955 }
1956
1957 CamelStore *
1958 em_subscription_editor_get_store (EMSubscriptionEditor *editor)
1959 {
1960 g_return_val_if_fail (EM_IS_SUBSCRIPTION_EDITOR (editor), NULL);
1961
1962 if (editor->priv->active == NULL)
1963 return NULL;
1964
1965 return editor->priv->active->store;
1966 }