1 /*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful, but
7 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9 * for more details.
10 *
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, see <http://www.gnu.org/licenses/>.
13 *
14 *
15 * Authors:
16 * Not Zed <notzed@lostzed.mmc.com.au>
17 * Jeffrey Stedfast <fejj@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #include "evolution-config.h"
24
25 #include <string.h>
26
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29
30 #include <shell/e-shell.h>
31
32 #include <e-util/e-util.h>
33 #include <e-util/e-util-private.h>
34
35 #include "em-folder-selector.h"
36 #include "em-folder-tree.h"
37 #include "em-utils.h"
38 #include "em-vfolder-editor-context.h"
39
40 #include "em-vfolder-editor-rule.h"
41
42 #define EM_VFOLDER_EDITOR_RULE_GET_PRIVATE(obj) \
43 (G_TYPE_INSTANCE_GET_PRIVATE \
44 ((obj), EM_TYPE_VFOLDER_EDITOR_RULE, EMVFolderEditorRulePrivate))
45
46 #define EM_VFOLDER_EDITOR_RULE_GET_PRIVATE(obj) \
47 (G_TYPE_INSTANCE_GET_PRIVATE \
48 ((obj), EM_TYPE_VFOLDER_EDITOR_RULE, EMVFolderEditorRulePrivate))
49
50 struct _EMVFolderEditorRulePrivate {
51 EMailSession *session;
52 };
53
54 enum {
55 PROP_0,
56 PROP_SESSION
57 };
58
59 static GtkWidget *get_widget (EFilterRule *fr, ERuleContext *f);
60
G_DEFINE_TYPE(EMVFolderEditorRule,em_vfolder_editor_rule,EM_TYPE_VFOLDER_RULE)61 G_DEFINE_TYPE (
62 EMVFolderEditorRule,
63 em_vfolder_editor_rule,
64 EM_TYPE_VFOLDER_RULE)
65
66 static void
67 vfolder_editor_rule_set_session (EMVFolderEditorRule *rule,
68 EMailSession *session)
69 {
70 if (session == NULL) {
71 EShell *shell;
72 EShellBackend *shell_backend;
73 EMailBackend *backend;
74
75 shell = e_shell_get_default ();
76 shell_backend = e_shell_get_backend_by_name (shell, "mail");
77
78 backend = E_MAIL_BACKEND (shell_backend);
79 session = e_mail_backend_get_session (backend);
80 }
81
82 g_return_if_fail (E_IS_MAIL_SESSION (session));
83 g_return_if_fail (rule->priv->session == NULL);
84
85 rule->priv->session = g_object_ref (session);
86 }
87
88 static void
vfolder_editor_rule_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)89 vfolder_editor_rule_set_property (GObject *object,
90 guint property_id,
91 const GValue *value,
92 GParamSpec *pspec)
93 {
94 switch (property_id) {
95 case PROP_SESSION:
96 vfolder_editor_rule_set_session (
97 EM_VFOLDER_EDITOR_RULE (object),
98 g_value_get_object (value));
99 return;
100 }
101
102 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
103 }
104
105 static void
vfolder_editor_rule_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)106 vfolder_editor_rule_get_property (GObject *object,
107 guint property_id,
108 GValue *value,
109 GParamSpec *pspec)
110 {
111 switch (property_id) {
112 case PROP_SESSION:
113 g_value_set_object (
114 value,
115 em_vfolder_editor_rule_get_session (
116 EM_VFOLDER_EDITOR_RULE (object)));
117 return;
118 }
119
120 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
121 }
122
123 static void
vfolder_editor_rule_dispose(GObject * object)124 vfolder_editor_rule_dispose (GObject *object)
125 {
126 EMVFolderEditorRulePrivate *priv;
127
128 priv = EM_VFOLDER_EDITOR_RULE_GET_PRIVATE (object);
129 g_clear_object (&priv->session);
130
131 /* Chain up to parent's dispose() method. */
132 G_OBJECT_CLASS (em_vfolder_editor_rule_parent_class)->dispose (object);
133 }
134
135 static void
vfolder_editor_rule_finalize(GObject * object)136 vfolder_editor_rule_finalize (GObject *object)
137 {
138 /* EMVFolderEditorRule *rule = EM_VFOLDER_EDITOR_RULE (object); */
139
140 /* Chain up to parent's finalize() method. */
141 G_OBJECT_CLASS (em_vfolder_editor_rule_parent_class)->finalize (object);
142 }
143
144 static void
em_vfolder_editor_rule_class_init(EMVFolderEditorRuleClass * class)145 em_vfolder_editor_rule_class_init (EMVFolderEditorRuleClass *class)
146 {
147 GObjectClass *object_class;
148 EFilterRuleClass *filter_rule_class;
149
150 g_type_class_add_private (class, sizeof (EMVFolderEditorRulePrivate));
151
152 object_class = G_OBJECT_CLASS (class);
153 object_class->set_property = vfolder_editor_rule_set_property;
154 object_class->get_property = vfolder_editor_rule_get_property;
155 object_class->dispose = vfolder_editor_rule_dispose;
156 object_class->finalize = vfolder_editor_rule_finalize;
157
158 filter_rule_class = E_FILTER_RULE_CLASS (class);
159 filter_rule_class->get_widget = get_widget;
160
161 g_object_class_install_property (
162 object_class,
163 PROP_SESSION,
164 g_param_spec_object (
165 "session",
166 NULL,
167 NULL,
168 E_TYPE_MAIL_SESSION,
169 G_PARAM_READWRITE |
170 G_PARAM_CONSTRUCT_ONLY));
171 }
172
173 static void
em_vfolder_editor_rule_init(EMVFolderEditorRule * rule)174 em_vfolder_editor_rule_init (EMVFolderEditorRule *rule)
175 {
176 rule->priv = EM_VFOLDER_EDITOR_RULE_GET_PRIVATE (rule);
177 }
178
179 EFilterRule *
em_vfolder_editor_rule_new(EMailSession * session)180 em_vfolder_editor_rule_new (EMailSession *session)
181 {
182 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
183
184 return g_object_new (
185 EM_TYPE_VFOLDER_EDITOR_RULE, "session", session, NULL);
186 }
187
188 EMailSession *
em_vfolder_editor_rule_get_session(EMVFolderEditorRule * rule)189 em_vfolder_editor_rule_get_session (EMVFolderEditorRule *rule)
190 {
191 g_return_val_if_fail (EM_IS_VFOLDER_RULE (rule), NULL);
192
193 return rule->priv->session;
194 }
195
196 enum {
197 BUTTON_ADD,
198 BUTTON_REMOVE,
199 BUTTON_LAST
200 };
201
202 struct _source_data {
203 ERuleContext *rc;
204 EMVFolderRule *vr;
205 GtkListStore *model;
206 GtkTreeView *tree_view;
207 GtkWidget *source_selector;
208 GtkWidget *buttons[BUTTON_LAST];
209 };
210
211 static void
source_data_free(gpointer ptr)212 source_data_free (gpointer ptr)
213 {
214 struct _source_data *sd = ptr;
215
216 if (sd) {
217 g_clear_object (&sd->model);
218 g_free (sd);
219 }
220 }
221
222 static void
set_sensitive(struct _source_data * data)223 set_sensitive (struct _source_data *data)
224 {
225 GtkTreeSelection *selection;
226
227 selection = gtk_tree_view_get_selection (data->tree_view);
228
229 gtk_widget_set_sensitive (
230 GTK_WIDGET (data->buttons[BUTTON_ADD]), TRUE);
231 gtk_widget_set_sensitive (
232 GTK_WIDGET (data->buttons[BUTTON_REMOVE]),
233 selection && gtk_tree_selection_count_selected_rows (selection) > 0);
234 }
235
236 static void
selection_changed_cb(GtkTreeSelection * selection,struct _source_data * data)237 selection_changed_cb (GtkTreeSelection *selection,
238 struct _source_data *data)
239 {
240 set_sensitive (data);
241 }
242
243 static void
select_source_with_changed(GtkWidget * widget,struct _source_data * data)244 select_source_with_changed (GtkWidget *widget,
245 struct _source_data *data)
246 {
247 em_vfolder_rule_with_t with;
248
249 with = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
250 if (with > EM_VFOLDER_RULE_WITH_LOCAL)
251 with = 0;
252
253 with = 3 - with;
254
255 gtk_widget_set_sensitive (data->source_selector, !with);
256
257 em_vfolder_rule_set_with (data->vr, with);
258 }
259
260 static void
autoupdate_toggled_cb(GtkToggleButton * toggle,struct _source_data * data)261 autoupdate_toggled_cb (GtkToggleButton *toggle,
262 struct _source_data *data)
263 {
264 em_vfolder_rule_set_autoupdate (data->vr, gtk_toggle_button_get_active (toggle));
265 }
266
267 static void
include_subfolders_toggled_cb(GtkCellRendererToggle * cell_renderer,const gchar * path_string,struct _source_data * data)268 include_subfolders_toggled_cb (GtkCellRendererToggle *cell_renderer,
269 const gchar *path_string,
270 struct _source_data *data)
271 {
272 GtkTreeModel *model;
273 GtkTreePath *path;
274 GtkTreeIter iter;
275
276 gtk_cell_renderer_toggle_set_active (
277 cell_renderer,
278 !gtk_cell_renderer_toggle_get_active (cell_renderer));
279
280 model = gtk_tree_view_get_model (data->tree_view);
281 path = gtk_tree_path_new_from_string (path_string);
282
283 if (gtk_tree_model_get_iter (model, &iter, path)) {
284 gchar *source = NULL;
285
286 gtk_list_store_set (
287 GTK_LIST_STORE (model), &iter,
288 2, gtk_cell_renderer_toggle_get_active (cell_renderer),
289 -1);
290
291 gtk_tree_model_get (model, &iter, 1, &source, -1);
292 if (source) {
293 em_vfolder_rule_source_set_include_subfolders (
294 data->vr, source,
295 gtk_cell_renderer_toggle_get_active (cell_renderer));
296 g_free (source);
297 }
298 }
299
300 gtk_tree_path_free (path);
301 }
302
303 static void
vfr_folder_response(EMFolderSelector * selector,gint button,struct _source_data * data)304 vfr_folder_response (EMFolderSelector *selector,
305 gint button,
306 struct _source_data *data)
307 {
308 EMFolderTreeModel *model;
309 EMFolderTree *folder_tree;
310 CamelSession *session;
311 GList *selected_uris;
312
313 folder_tree = em_folder_selector_get_folder_tree (selector);
314 model = em_folder_selector_get_model (selector);
315 session = CAMEL_SESSION (em_folder_tree_model_get_session (model));
316
317 selected_uris = em_folder_tree_get_selected_uris (folder_tree);
318
319 if (button == GTK_RESPONSE_OK && selected_uris != NULL) {
320 GList *uris_iter;
321 GHashTable *known_uris;
322 GtkTreeIter iter;
323 GtkTreeSelection *selection;
324 gboolean changed = FALSE;
325
326 selection = gtk_tree_view_get_selection (data->tree_view);
327 gtk_tree_selection_unselect_all (selection);
328
329 known_uris = g_hash_table_new_full (
330 (GHashFunc) g_str_hash,
331 (GEqualFunc) g_str_equal,
332 (GDestroyNotify) g_free,
333 (GDestroyNotify) NULL);
334
335 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (data->model), &iter)) {
336 GtkTreeModel *model = GTK_TREE_MODEL (data->model);
337 do {
338 gchar *known = NULL;
339
340 gtk_tree_model_get (model, &iter, 1, &known, -1);
341
342 if (known)
343 g_hash_table_add (known_uris, known);
344 } while (gtk_tree_model_iter_next (model, &iter));
345 }
346
347 for (uris_iter = selected_uris; uris_iter != NULL; uris_iter = uris_iter->next) {
348 const gchar *uri = uris_iter->data;
349 gchar *markup;
350
351 if (uri == NULL)
352 continue;
353
354 if (g_hash_table_contains (known_uris, uri))
355 continue;
356
357 g_hash_table_add (known_uris, g_strdup (uri));
358
359 changed = TRUE;
360 g_queue_push_tail (em_vfolder_rule_get_sources (data->vr), g_strdup (uri));
361
362 markup = e_mail_folder_uri_to_markup (session, uri, NULL);
363
364 gtk_list_store_append (data->model, &iter);
365 gtk_list_store_set (data->model, &iter, 0, markup, 1, uri, -1);
366 g_free (markup);
367
368 /* select all newly added folders */
369 gtk_tree_selection_select_iter (selection, &iter);
370 }
371
372 g_hash_table_destroy (known_uris);
373 if (changed)
374 em_vfolder_rule_sources_changed (data->vr);
375
376 set_sensitive (data);
377 }
378
379 gtk_widget_destroy (GTK_WIDGET (selector));
380 g_list_free_full (selected_uris, g_free);
381 }
382
383 static void
source_add(GtkWidget * widget,struct _source_data * data)384 source_add (GtkWidget *widget,
385 struct _source_data *data)
386 {
387 EMFolderTree *folder_tree;
388 EMFolderTreeModel *model;
389 EMFolderSelector *selector;
390 GtkTreeSelection *selection;
391 GtkWidget *dialog;
392 gpointer parent;
393
394 parent = gtk_widget_get_toplevel (widget);
395 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
396
397 model = em_folder_tree_model_get_default ();
398
399 dialog = em_folder_selector_new (parent, model);
400
401 gtk_window_set_title (GTK_WINDOW (dialog), _("Add Folder"));
402
403 selector = EM_FOLDER_SELECTOR (dialog);
404 em_folder_selector_set_can_create (selector, TRUE);
405 em_folder_selector_set_default_button_label (selector, _("_Add"));
406
407 folder_tree = em_folder_selector_get_folder_tree (selector);
408
409 em_folder_tree_set_excluded (folder_tree, EMFT_EXCLUDE_NOSELECT);
410
411 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_tree));
412 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
413
414 g_signal_connect (
415 dialog, "response",
416 G_CALLBACK (vfr_folder_response), data);
417
418 gtk_widget_show (dialog);
419 }
420
421 static void
source_remove(GtkWidget * widget,struct _source_data * data)422 source_remove (GtkWidget *widget,
423 struct _source_data *data)
424 {
425 GtkTreeSelection *selection;
426 const gchar *source, *prev_source;
427 GtkTreePath *path;
428 GtkTreeIter iter;
429 GHashTable *to_remove;
430 gint index = 0, first_selected = -1, removed;
431 gint n;
432
433 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->tree_view));
434 to_remove = g_hash_table_new (g_direct_hash, g_direct_equal);
435
436 source = NULL;
437 while ((source = em_vfolder_rule_next_source (data->vr, source))) {
438 path = gtk_tree_path_new ();
439 gtk_tree_path_append_index (path, index);
440
441 if (gtk_tree_selection_path_is_selected (selection, path)) {
442 g_hash_table_add (to_remove, GINT_TO_POINTER (index));
443
444 if (first_selected == -1)
445 first_selected = index;
446 }
447
448 index++;
449
450 gtk_tree_path_free (path);
451 }
452
453 /* do not depend on selection when removing */
454 gtk_tree_selection_unselect_all (selection);
455
456 index = 0;
457 source = NULL;
458 removed = 0;
459 prev_source = NULL;
460 while ((source = em_vfolder_rule_next_source (data->vr, source))) {
461 if (g_hash_table_contains (to_remove, GINT_TO_POINTER (index + removed))) {
462 path = gtk_tree_path_new ();
463 gtk_tree_path_append_index (path, index);
464 gtk_tree_model_get_iter (
465 GTK_TREE_MODEL (data->model), &iter, path);
466
467 em_vfolder_rule_remove_source (data->vr, source);
468 gtk_list_store_remove (data->model, &iter);
469 gtk_tree_path_free (path);
470
471 /* try again from the previous source */
472 removed++;
473 source = prev_source;
474 } else {
475 index++;
476 prev_source = source;
477 }
478 }
479
480 g_hash_table_destroy (to_remove);
481
482 /* now select the next rule */
483 n = gtk_tree_model_iter_n_children (
484 GTK_TREE_MODEL (data->model), NULL);
485 index = first_selected >= n ? n - 1 : first_selected;
486
487 if (index >= 0) {
488 path = gtk_tree_path_new ();
489 gtk_tree_path_append_index (path, index);
490 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (data->model), &iter, path)) {
491 gtk_tree_selection_select_iter (selection, &iter);
492 gtk_tree_view_set_cursor (data->tree_view, path, NULL, FALSE);
493 }
494 gtk_tree_path_free (path);
495 }
496
497 set_sensitive (data);
498 }
499
500 static GtkWidget *
get_widget(EFilterRule * fr,ERuleContext * rc)501 get_widget (EFilterRule *fr,
502 ERuleContext *rc)
503 {
504 EMVFolderRule *vr = (EMVFolderRule *) fr;
505 EMailSession *session;
506 GtkWidget *widget, *frame, *label, *combobox, *hgrid, *vgrid, *tree_view, *scrolled_window;
507 GtkWidget *autoupdate;
508 GtkListStore *model;
509 GtkCellRenderer *renderer;
510 GtkTreeViewColumn *column;
511 struct _source_data *data;
512 const gchar *source;
513 gchar *tmp;
514 GtkTreeIter iter;
515 GtkTreeSelection *selection;
516
517 widget = E_FILTER_RULE_CLASS (em_vfolder_editor_rule_parent_class)->
518 get_widget (fr, rc);
519
520 data = g_malloc0 (sizeof (*data));
521 data->rc = rc;
522 data->vr = vr;
523
524 frame = gtk_grid_new ();
525 gtk_orientable_set_orientation (GTK_ORIENTABLE (frame), GTK_ORIENTATION_VERTICAL);
526 gtk_grid_set_row_spacing (GTK_GRID (frame), 6);
527
528 g_object_set_data_full (G_OBJECT (frame), "data", data, source_data_free);
529
530 tmp = g_strdup_printf ("<b>%s</b>", _("Search Folder Sources"));
531 label = gtk_label_new (tmp);
532 g_free (tmp);
533 g_object_set (
534 G_OBJECT (label),
535 "use-markup", TRUE,
536 "xalign", 0.0,
537 NULL);
538
539 gtk_container_add (GTK_CONTAINER (frame), label);
540
541 hgrid = gtk_grid_new ();
542 gtk_orientable_set_orientation (GTK_ORIENTABLE (hgrid), GTK_ORIENTATION_HORIZONTAL);
543 gtk_container_add (GTK_CONTAINER (frame), hgrid);
544
545 label = gtk_label_new (" ");
546 gtk_container_add (GTK_CONTAINER (hgrid), label);
547
548 vgrid = gtk_grid_new ();
549 g_object_set (
550 G_OBJECT (vgrid),
551 "orientation", GTK_ORIENTATION_VERTICAL,
552 "border-width", 6,
553 "row-spacing", 6,
554 NULL);
555 gtk_container_add (GTK_CONTAINER (hgrid), vgrid);
556
557 hgrid = gtk_grid_new ();
558 gtk_orientable_set_orientation (GTK_ORIENTABLE (hgrid), GTK_ORIENTATION_HORIZONTAL);
559 gtk_grid_set_column_spacing (GTK_GRID (hgrid), 6);
560 gtk_container_add (GTK_CONTAINER (vgrid), hgrid);
561
562 autoupdate = gtk_check_button_new_with_mnemonic (_("Automatically update on any _source folder change"));
563 gtk_container_add (GTK_CONTAINER (hgrid), autoupdate);
564
565 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (autoupdate), em_vfolder_rule_get_autoupdate (vr));
566 g_signal_connect (autoupdate, "toggled", G_CALLBACK (autoupdate_toggled_cb), data);
567
568 hgrid = gtk_grid_new ();
569 gtk_orientable_set_orientation (GTK_ORIENTABLE (hgrid), GTK_ORIENTATION_HORIZONTAL);
570 gtk_grid_set_column_spacing (GTK_GRID (hgrid), 6);
571 gtk_container_add (GTK_CONTAINER (vgrid), hgrid);
572
573 combobox = gtk_combo_box_text_new ();
574 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combobox), NULL, _("All local folders"));
575 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combobox), NULL, _("All active remote folders"));
576 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combobox), NULL, _("All local and active remote folders"));
577 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combobox), NULL, _("Specific folders"));
578 gtk_container_add (GTK_CONTAINER (hgrid), combobox);
579
580 hgrid = gtk_grid_new ();
581 gtk_orientable_set_orientation (GTK_ORIENTABLE (hgrid), GTK_ORIENTATION_HORIZONTAL);
582 gtk_grid_set_column_spacing (GTK_GRID (hgrid), 6);
583 gtk_container_add (GTK_CONTAINER (vgrid), hgrid);
584
585 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
586 g_object_set (
587 G_OBJECT (scrolled_window),
588 "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
589 "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
590 "shadow-type", GTK_SHADOW_IN,
591 "halign", GTK_ALIGN_FILL,
592 "hexpand", TRUE,
593 "valign", GTK_ALIGN_FILL,
594 "vexpand", TRUE,
595 NULL);
596 gtk_container_add (GTK_CONTAINER (hgrid), scrolled_window);
597
598 model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
599 renderer = gtk_cell_renderer_text_new ();
600 tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
601 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
602 gtk_tree_view_insert_column_with_attributes (
603 GTK_TREE_VIEW (tree_view),
604 -1, "column", renderer, "markup", 0, NULL);
605
606 renderer = gtk_cell_renderer_toggle_new ();
607 column = gtk_tree_view_column_new_with_attributes (
608 "include subfolders", renderer, "active", 2, NULL);
609 g_signal_connect (renderer, "toggled", G_CALLBACK (include_subfolders_toggled_cb), data);
610
611 renderer = gtk_cell_renderer_text_new ();
612 g_object_set (
613 G_OBJECT (renderer),
614 "editable", FALSE,
615 "text", _("include subfolders"),
616 NULL);
617 gtk_tree_view_column_pack_start (column, renderer, TRUE);
618 gtk_tree_view_insert_column (GTK_TREE_VIEW (tree_view), column, -1);
619
620 column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 0);
621 gtk_tree_view_column_set_expand (column, TRUE);
622
623 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), tree_view);
624
625 vgrid = gtk_grid_new ();
626 g_object_set (
627 G_OBJECT (vgrid),
628 "orientation", GTK_ORIENTATION_VERTICAL,
629 "border-width", 6,
630 "row-spacing", 6,
631 NULL);
632 gtk_container_add (GTK_CONTAINER (hgrid), vgrid);
633
634 data->buttons[BUTTON_ADD] = e_dialog_button_new_with_icon ("list-add", _("_Add"));
635 g_signal_connect (
636 data->buttons[BUTTON_ADD], "clicked",
637 G_CALLBACK (source_add), data);
638
639 data->buttons[BUTTON_REMOVE] = e_dialog_button_new_with_icon ("list-remove", _("_Remove"));
640 g_signal_connect (
641 data->buttons[BUTTON_REMOVE], "clicked",
642 G_CALLBACK (source_remove), data);
643
644 gtk_container_add (GTK_CONTAINER (vgrid), data->buttons[BUTTON_ADD]);
645 gtk_container_add (GTK_CONTAINER (vgrid), data->buttons[BUTTON_REMOVE]);
646
647 data->tree_view = GTK_TREE_VIEW (tree_view);
648 data->model = model;
649
650 session = em_vfolder_editor_context_get_session (EM_VFOLDER_EDITOR_CONTEXT (rc));
651
652 source = NULL;
653 while ((source = em_vfolder_rule_next_source (vr, source))) {
654 gchar *markup;
655
656 markup = e_mail_folder_uri_to_markup (
657 CAMEL_SESSION (session), source, NULL);
658
659 gtk_list_store_append (data->model, &iter);
660 gtk_list_store_set (
661 data->model, &iter,
662 0, markup,
663 1, source,
664 2, em_vfolder_rule_source_get_include_subfolders (vr, source),
665 -1);
666 g_free (markup);
667 }
668
669 selection = gtk_tree_view_get_selection (data->tree_view);
670 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
671
672 g_signal_connect (
673 selection, "changed",
674 G_CALLBACK (selection_changed_cb), data);
675
676 data->source_selector = hgrid;
677
678 gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 3 - em_vfolder_rule_get_with (vr));
679 g_signal_connect (
680 combobox, "changed",
681 G_CALLBACK (select_source_with_changed), data);
682 select_source_with_changed (combobox, data);
683
684 set_sensitive (data);
685
686 gtk_widget_set_valign (frame, GTK_ALIGN_FILL);
687 gtk_widget_set_vexpand (frame, TRUE);
688 gtk_widget_show_all (frame);
689
690 gtk_container_add (GTK_CONTAINER (widget), frame);
691
692 return widget;
693 }
694