1 /*
2 *
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10 * for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program; if not, see <http://www.gnu.org/licenses/>.
14 *
15 *
16 * Authors:
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 #include <glib/gi18n-lib.h>
27
28 #include <e-util/e-util.h>
29 #include <libemail-engine/libemail-engine.h>
30
31 #include "e-mail-folder-create-dialog.h"
32 #include "em-folder-tree.h"
33 #include "em-folder-utils.h"
34 #include "em-utils.h"
35
36 #include "em-folder-selector.h"
37
38 #define d(x)
39
40 #define EM_FOLDER_SELECTOR_GET_PRIVATE(obj) \
41 (G_TYPE_INSTANCE_GET_PRIVATE \
42 ((obj), EM_TYPE_FOLDER_SELECTOR, EMFolderSelectorPrivate))
43
44 #define DEFAULT_BUTTON_LABEL N_("_OK")
45
46 struct _EMFolderSelectorPrivate {
47 EMFolderTreeModel *model;
48 GtkWidget *alert_bar;
49 GtkWidget *activity_bar;
50 GtkWidget *caption_label;
51 GtkWidget *content_area;
52 GtkWidget *tree_view_frame;
53
54 gchar *selected_uri;
55
56 gboolean can_create;
57 gboolean can_none;
58 gchar *caption;
59 gchar *default_button_label;
60 };
61
62 enum {
63 PROP_0,
64 PROP_CAN_CREATE,
65 PROP_CAN_NONE,
66 PROP_CAPTION,
67 PROP_DEFAULT_BUTTON_LABEL,
68 PROP_MODEL
69 };
70
71 enum {
72 FOLDER_SELECTED,
73 LAST_SIGNAL
74 };
75
76 static guint signals[LAST_SIGNAL];
77
78 /* Forward Declarations */
79 static void em_folder_selector_alert_sink_init
80 (EAlertSinkInterface *interface);
81
G_DEFINE_TYPE_WITH_CODE(EMFolderSelector,em_folder_selector,GTK_TYPE_DIALOG,G_IMPLEMENT_INTERFACE (E_TYPE_ALERT_SINK,em_folder_selector_alert_sink_init))82 G_DEFINE_TYPE_WITH_CODE (
83 EMFolderSelector,
84 em_folder_selector,
85 GTK_TYPE_DIALOG,
86 G_IMPLEMENT_INTERFACE (
87 E_TYPE_ALERT_SINK,
88 em_folder_selector_alert_sink_init))
89
90 static void
91 folder_selector_selected_cb (EMFolderTree *emft,
92 CamelStore *store,
93 const gchar *folder_name,
94 CamelFolderInfoFlags flags,
95 EMFolderSelector *selector)
96 {
97 g_signal_emit (
98 selector, signals[FOLDER_SELECTED], 0, store, folder_name);
99 }
100
101 static void
folder_selector_activated_cb(EMFolderTree * emft,CamelStore * store,const gchar * folder_name,EMFolderSelector * selector)102 folder_selector_activated_cb (EMFolderTree *emft,
103 CamelStore *store,
104 const gchar *folder_name,
105 EMFolderSelector *selector)
106 {
107 gtk_dialog_response (GTK_DIALOG (selector), GTK_RESPONSE_OK);
108 }
109
110 static void
folder_selector_folder_created_cb(EMailFolderCreateDialog * dialog,CamelStore * store,const gchar * folder_name,GWeakRef * folder_tree_weak_ref)111 folder_selector_folder_created_cb (EMailFolderCreateDialog *dialog,
112 CamelStore *store,
113 const gchar *folder_name,
114 GWeakRef *folder_tree_weak_ref)
115 {
116 EMFolderTree *folder_tree;
117
118 folder_tree = g_weak_ref_get (folder_tree_weak_ref);
119
120 if (folder_tree != NULL) {
121 gchar *folder_uri;
122
123 /* Select the newly created folder. */
124 folder_uri = e_mail_folder_uri_build (store, folder_name);
125 em_folder_tree_set_selected (folder_tree, folder_uri, TRUE);
126 g_free (folder_uri);
127
128 g_object_unref (folder_tree);
129 }
130 }
131
132 static void
folder_selector_action_add_cb(ETreeViewFrame * tree_view_frame,GtkAction * action,EMFolderSelector * selector)133 folder_selector_action_add_cb (ETreeViewFrame *tree_view_frame,
134 GtkAction *action,
135 EMFolderSelector *selector)
136 {
137 GtkWidget *new_dialog;
138 EMailSession *session;
139 EMFolderTree *folder_tree;
140 const gchar *initial_uri;
141
142 folder_tree = em_folder_selector_get_folder_tree (selector);
143 session = em_folder_tree_get_session (folder_tree);
144
145 new_dialog = e_mail_folder_create_dialog_new (
146 GTK_WINDOW (selector),
147 E_MAIL_UI_SESSION (session));
148
149 gtk_window_set_modal (GTK_WINDOW (new_dialog), TRUE);
150
151 g_signal_connect_data (
152 new_dialog, "folder-created",
153 G_CALLBACK (folder_selector_folder_created_cb),
154 e_weak_ref_new (folder_tree),
155 (GClosureNotify) e_weak_ref_free, 0);
156
157 initial_uri = em_folder_selector_get_selected_uri (selector);
158
159 folder_tree = em_folder_selector_get_folder_tree (
160 EM_FOLDER_SELECTOR (new_dialog));
161
162 em_folder_tree_set_selected (folder_tree, initial_uri, FALSE);
163
164 gtk_widget_show (new_dialog);
165 }
166
167 static void
folder_selector_set_model(EMFolderSelector * selector,EMFolderTreeModel * model)168 folder_selector_set_model (EMFolderSelector *selector,
169 EMFolderTreeModel *model)
170 {
171 g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
172 g_return_if_fail (selector->priv->model == NULL);
173
174 selector->priv->model = g_object_ref (model);
175 }
176
177 static void
folder_selector_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)178 folder_selector_set_property (GObject *object,
179 guint property_id,
180 const GValue *value,
181 GParamSpec *pspec)
182 {
183 switch (property_id) {
184 case PROP_CAN_CREATE:
185 em_folder_selector_set_can_create (
186 EM_FOLDER_SELECTOR (object),
187 g_value_get_boolean (value));
188 return;
189
190 case PROP_CAN_NONE:
191 em_folder_selector_set_can_none (
192 EM_FOLDER_SELECTOR (object),
193 g_value_get_boolean (value));
194 return;
195
196 case PROP_CAPTION:
197 em_folder_selector_set_caption (
198 EM_FOLDER_SELECTOR (object),
199 g_value_get_string (value));
200 return;
201
202 case PROP_DEFAULT_BUTTON_LABEL:
203 em_folder_selector_set_default_button_label (
204 EM_FOLDER_SELECTOR (object),
205 g_value_get_string (value));
206 return;
207
208 case PROP_MODEL:
209 folder_selector_set_model (
210 EM_FOLDER_SELECTOR (object),
211 g_value_get_object (value));
212 return;
213 }
214
215 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
216 }
217
218 static void
folder_selector_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)219 folder_selector_get_property (GObject *object,
220 guint property_id,
221 GValue *value,
222 GParamSpec *pspec)
223 {
224 switch (property_id) {
225 case PROP_CAN_CREATE:
226 g_value_set_boolean (
227 value,
228 em_folder_selector_get_can_create (
229 EM_FOLDER_SELECTOR (object)));
230 return;
231
232 case PROP_CAN_NONE:
233 g_value_set_boolean (
234 value,
235 em_folder_selector_get_can_none (
236 EM_FOLDER_SELECTOR (object)));
237 return;
238
239 case PROP_CAPTION:
240 g_value_set_string (
241 value,
242 em_folder_selector_get_caption (
243 EM_FOLDER_SELECTOR (object)));
244 return;
245
246 case PROP_DEFAULT_BUTTON_LABEL:
247 g_value_set_string (
248 value,
249 em_folder_selector_get_default_button_label (
250 EM_FOLDER_SELECTOR (object)));
251 return;
252
253 case PROP_MODEL:
254 g_value_set_object (
255 value,
256 em_folder_selector_get_model (
257 EM_FOLDER_SELECTOR (object)));
258 return;
259 }
260
261 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
262 }
263
264 static void
folder_selector_dispose(GObject * object)265 folder_selector_dispose (GObject *object)
266 {
267 EMFolderSelectorPrivate *priv;
268
269 priv = EM_FOLDER_SELECTOR_GET_PRIVATE (object);
270
271 if (priv->model && priv->model != em_folder_tree_model_get_default ())
272 em_folder_tree_model_remove_all_stores (priv->model);
273
274 g_clear_object (&priv->model);
275 g_clear_object (&priv->alert_bar);
276 g_clear_object (&priv->activity_bar);
277 g_clear_object (&priv->caption_label);
278 g_clear_object (&priv->content_area);
279 g_clear_object (&priv->tree_view_frame);
280
281 /* Chain up to parent's dispose() method. */
282 G_OBJECT_CLASS (em_folder_selector_parent_class)->dispose (object);
283 }
284
285 static void
folder_selector_finalize(GObject * object)286 folder_selector_finalize (GObject *object)
287 {
288 EMFolderSelectorPrivate *priv;
289
290 priv = EM_FOLDER_SELECTOR_GET_PRIVATE (object);
291
292 g_free (priv->selected_uri);
293 g_free (priv->caption);
294 g_free (priv->default_button_label);
295
296 /* Chain up to parent's finalize() method. */
297 G_OBJECT_CLASS (em_folder_selector_parent_class)->finalize (object);
298 }
299
300 static void
folder_selector_constructed(GObject * object)301 folder_selector_constructed (GObject *object)
302 {
303 EMFolderSelector *selector;
304 EMailSession *session;
305 EMFolderTreeModel *model;
306 GtkAction *action;
307 GtkWidget *content_area;
308 GtkWidget *container;
309 GtkWidget *widget;
310
311 /* Chain up to parent's constructed() method. */
312 G_OBJECT_CLASS (em_folder_selector_parent_class)->constructed (object);
313
314 selector = EM_FOLDER_SELECTOR (object);
315 model = em_folder_selector_get_model (selector);
316 session = em_folder_tree_model_get_session (model);
317
318 gtk_window_set_default_size (GTK_WINDOW (selector), 400, 500);
319 gtk_container_set_border_width (GTK_CONTAINER (selector), 5);
320
321 content_area = gtk_dialog_get_content_area (GTK_DIALOG (selector));
322
323 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
324 gtk_container_set_border_width (GTK_CONTAINER (widget), 5);
325 gtk_box_pack_start (GTK_BOX (content_area), widget, TRUE, TRUE, 0);
326 selector->priv->content_area = g_object_ref (widget);
327 gtk_widget_show (widget);
328
329 container = widget;
330
331 gtk_dialog_add_buttons (
332 GTK_DIALOG (selector),
333 _("_Cancel"), GTK_RESPONSE_CANCEL,
334 _("_None"), GTK_RESPONSE_NO,
335 selector->priv->default_button_label, GTK_RESPONSE_OK, NULL);
336
337 gtk_dialog_set_response_sensitive (
338 GTK_DIALOG (selector), GTK_RESPONSE_OK, FALSE);
339 gtk_dialog_set_default_response (
340 GTK_DIALOG (selector), GTK_RESPONSE_OK);
341
342 widget = gtk_dialog_get_widget_for_response (GTK_DIALOG (selector), GTK_RESPONSE_NO);
343
344 e_binding_bind_property (
345 selector, "can-none",
346 widget, "visible",
347 G_BINDING_SYNC_CREATE);
348
349 widget = gtk_dialog_get_widget_for_response (
350 GTK_DIALOG (selector), GTK_RESPONSE_OK);
351
352 /* No need to synchronize properties. */
353 e_binding_bind_property (
354 selector, "default-button-label",
355 widget, "label",
356 G_BINDING_DEFAULT);
357
358 widget = e_alert_bar_new ();
359 gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
360 selector->priv->alert_bar = g_object_ref (widget);
361 /* EAlertBar controls its own visibility. */
362
363 widget = e_activity_bar_new ();
364 gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
365 selector->priv->activity_bar = g_object_ref (widget);
366 /* EActivityBar controls its own visibility. */
367
368 widget = e_tree_view_frame_new ();
369 gtk_box_pack_end (GTK_BOX (container), widget, TRUE, TRUE, 0);
370 selector->priv->tree_view_frame = g_object_ref (widget);
371 gtk_widget_set_size_request (widget, -1, 240);
372 gtk_widget_show (widget);
373
374 g_signal_connect (
375 widget,
376 "toolbar-action-activate::"
377 E_TREE_VIEW_FRAME_ACTION_ADD,
378 G_CALLBACK (folder_selector_action_add_cb),
379 selector);
380
381 e_binding_bind_property (
382 selector, "can-create",
383 widget, "toolbar-visible",
384 G_BINDING_SYNC_CREATE);
385
386 container = widget;
387
388 widget = em_folder_tree_new_with_model (
389 session, E_ALERT_SINK (selector), model);
390 emu_restore_folder_tree_state (EM_FOLDER_TREE (widget));
391 e_tree_view_frame_set_tree_view (
392 E_TREE_VIEW_FRAME (container),
393 GTK_TREE_VIEW (widget));
394 gtk_widget_grab_focus (widget);
395 gtk_widget_show (widget);
396
397 g_signal_connect (
398 widget, "folder-selected",
399 G_CALLBACK (folder_selector_selected_cb), selector);
400 g_signal_connect (
401 widget, "folder-activated",
402 G_CALLBACK (folder_selector_activated_cb), selector);
403
404 container = selector->priv->content_area;
405
406 /* This can be made visible by setting the "caption" property. */
407 widget = gtk_label_new (NULL);
408 gtk_widget_set_margin_top (widget, 6);
409 gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_LEFT);
410 gtk_box_pack_end (GTK_BOX (container), widget, FALSE, TRUE, 0);
411 selector->priv->caption_label = g_object_ref (widget);
412 gtk_widget_hide (widget);
413
414 e_binding_bind_property (
415 selector, "caption",
416 widget, "label",
417 G_BINDING_DEFAULT);
418
419 action = e_tree_view_frame_lookup_toolbar_action (
420 E_TREE_VIEW_FRAME (selector->priv->tree_view_frame),
421 E_TREE_VIEW_FRAME_ACTION_ADD);
422 gtk_action_set_tooltip (action, _("Create a new folder"));
423
424 action = e_tree_view_frame_lookup_toolbar_action (
425 E_TREE_VIEW_FRAME (selector->priv->tree_view_frame),
426 E_TREE_VIEW_FRAME_ACTION_REMOVE);
427 gtk_action_set_visible (action, FALSE);
428 }
429
430 static void
folder_selector_folder_selected(EMFolderSelector * selector,CamelStore * store,const gchar * folder_name)431 folder_selector_folder_selected (EMFolderSelector *selector,
432 CamelStore *store,
433 const gchar *folder_name)
434 {
435 gtk_dialog_set_response_sensitive (
436 GTK_DIALOG (selector), GTK_RESPONSE_OK,
437 (store != NULL) && (folder_name != NULL));
438 }
439
440 static void
folder_selector_submit_alert(EAlertSink * alert_sink,EAlert * alert)441 folder_selector_submit_alert (EAlertSink *alert_sink,
442 EAlert *alert)
443 {
444 EMFolderSelectorPrivate *priv;
445
446 priv = EM_FOLDER_SELECTOR_GET_PRIVATE (alert_sink);
447
448 e_alert_bar_submit_alert (E_ALERT_BAR (priv->alert_bar), alert);
449 }
450
451 static void
em_folder_selector_class_init(EMFolderSelectorClass * class)452 em_folder_selector_class_init (EMFolderSelectorClass *class)
453 {
454 GObjectClass *object_class;
455
456 g_type_class_add_private (class, sizeof (EMFolderSelectorPrivate));
457
458 object_class = G_OBJECT_CLASS (class);
459 object_class->set_property = folder_selector_set_property;
460 object_class->get_property = folder_selector_get_property;
461 object_class->dispose = folder_selector_dispose;
462 object_class->finalize = folder_selector_finalize;
463 object_class->constructed = folder_selector_constructed;
464
465 class->folder_selected = folder_selector_folder_selected;
466
467 g_object_class_install_property (
468 object_class,
469 PROP_CAN_CREATE,
470 g_param_spec_boolean (
471 "can-create",
472 "Can Create",
473 "Allow the user to create a new folder "
474 "before making a final selection",
475 FALSE,
476 G_PARAM_READWRITE |
477 G_PARAM_CONSTRUCT |
478 G_PARAM_STATIC_STRINGS));
479
480 g_object_class_install_property (
481 object_class,
482 PROP_CAN_NONE,
483 g_param_spec_boolean (
484 "can-none",
485 "Can None",
486 "Whether can show 'None' button, to be able to unselect folder",
487 FALSE,
488 G_PARAM_READWRITE |
489 G_PARAM_CONSTRUCT |
490 G_PARAM_STATIC_STRINGS));
491
492 g_object_class_install_property (
493 object_class,
494 PROP_CAPTION,
495 g_param_spec_string (
496 "caption",
497 "Caption",
498 "Brief description above folder tree",
499 NULL,
500 G_PARAM_READWRITE |
501 G_PARAM_STATIC_STRINGS));
502
503 g_object_class_install_property (
504 object_class,
505 PROP_DEFAULT_BUTTON_LABEL,
506 g_param_spec_string (
507 "default-button-label",
508 "Default Button Label",
509 "Label for the dialog's default button",
510 NULL,
511 G_PARAM_READWRITE |
512 G_PARAM_STATIC_STRINGS));
513
514 g_object_class_install_property (
515 object_class,
516 PROP_MODEL,
517 g_param_spec_object (
518 "model",
519 NULL,
520 NULL,
521 EM_TYPE_FOLDER_TREE_MODEL,
522 G_PARAM_READWRITE |
523 G_PARAM_CONSTRUCT_ONLY |
524 G_PARAM_STATIC_STRINGS));
525
526 signals[FOLDER_SELECTED] = g_signal_new (
527 "folder-selected",
528 G_OBJECT_CLASS_TYPE (object_class),
529 G_SIGNAL_RUN_LAST,
530 G_STRUCT_OFFSET (EMFolderSelectorClass, folder_selected),
531 NULL, NULL, NULL,
532 G_TYPE_NONE, 2,
533 CAMEL_TYPE_STORE,
534 G_TYPE_STRING);
535 }
536
537 static void
em_folder_selector_alert_sink_init(EAlertSinkInterface * interface)538 em_folder_selector_alert_sink_init (EAlertSinkInterface *interface)
539 {
540 interface->submit_alert = folder_selector_submit_alert;
541 }
542
543 static void
em_folder_selector_init(EMFolderSelector * selector)544 em_folder_selector_init (EMFolderSelector *selector)
545 {
546 selector->priv = EM_FOLDER_SELECTOR_GET_PRIVATE (selector);
547
548 selector->priv->default_button_label =
549 g_strdup (gettext (DEFAULT_BUTTON_LABEL));
550 }
551
552 GtkWidget *
em_folder_selector_new(GtkWindow * parent,EMFolderTreeModel * model)553 em_folder_selector_new (GtkWindow *parent,
554 EMFolderTreeModel *model)
555 {
556 g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), NULL);
557
558 return g_object_new (
559 EM_TYPE_FOLDER_SELECTOR,
560 "transient-for", parent,
561 "model", model, NULL);
562 }
563
564 /**
565 * em_folder_selector_get_can_create:
566 * @selector: an #EMFolderSelector
567 *
568 * Returns whether the user can create a new folder before making a final
569 * selection. When %TRUE, the action area of the dialog will show a "New"
570 * button.
571 *
572 * Returns: whether folder creation is allowed
573 **/
574 gboolean
em_folder_selector_get_can_create(EMFolderSelector * selector)575 em_folder_selector_get_can_create (EMFolderSelector *selector)
576 {
577 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), FALSE);
578
579 return selector->priv->can_create;
580 }
581
582 /**
583 * em_folder_selector_set_can_create:
584 * @selector: an #EMFolderSelector
585 * @can_create: whether folder creation is allowed
586 *
587 * Sets whether the user can create a new folder before making a final
588 * selection. When %TRUE, the action area of the dialog will show a "New"
589 * button.
590 **/
591 void
em_folder_selector_set_can_create(EMFolderSelector * selector,gboolean can_create)592 em_folder_selector_set_can_create (EMFolderSelector *selector,
593 gboolean can_create)
594 {
595 g_return_if_fail (EM_IS_FOLDER_SELECTOR (selector));
596
597 if (can_create == selector->priv->can_create)
598 return;
599
600 selector->priv->can_create = can_create;
601
602 g_object_notify (G_OBJECT (selector), "can-create");
603 }
604
605 /**
606 * em_folder_selector_get_can_none:
607 * @selector: an #EMFolderSelector
608 *
609 * Returns whether the user can unselect folder by using a 'None' button.
610 *
611 * Returns: whether can unselect folder
612 *
613 * Since: 3.36
614 **/
615 gboolean
em_folder_selector_get_can_none(EMFolderSelector * selector)616 em_folder_selector_get_can_none (EMFolderSelector *selector)
617 {
618 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), FALSE);
619
620 return selector->priv->can_none;
621 }
622
623 /**
624 * em_folder_selector_set_can_none:
625 * @selector: an #EMFolderSelector
626 * @can_none: whether can unselect folder
627 *
628 * Sets whether the user can unselect folder using a 'None' button.
629 *
630 * Since: 3.36
631 **/
632 void
em_folder_selector_set_can_none(EMFolderSelector * selector,gboolean can_none)633 em_folder_selector_set_can_none (EMFolderSelector *selector,
634 gboolean can_none)
635 {
636 g_return_if_fail (EM_IS_FOLDER_SELECTOR (selector));
637
638 if (can_none == selector->priv->can_none)
639 return;
640
641 selector->priv->can_none = can_none;
642
643 g_object_notify (G_OBJECT (selector), "can-none");
644 }
645
646 /**
647 * em_folder_selector_get_caption:
648 * @selector: an #EMFolderSelector
649 *
650 * Returns the folder tree caption, which is an optional brief message
651 * instructing the user what to do. If no caption has been set, the
652 * function returns %NULL.
653 *
654 * Returns: the folder tree caption, or %NULL
655 **/
656 const gchar *
em_folder_selector_get_caption(EMFolderSelector * selector)657 em_folder_selector_get_caption (EMFolderSelector *selector)
658 {
659 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), NULL);
660
661 return selector->priv->caption;
662 }
663
664 /**
665 * em_folder_selector_set_caption:
666 * @selector: an #EMFolderSelector
667 * @caption: the folder tree caption, or %NULL
668 *
669 * Sets the folder tree caption, which is an optional brief message
670 * instructing the user what to do. If @caption is %NULL or empty,
671 * the label widget is hidden so as not to waste vertical space.
672 **/
673 void
em_folder_selector_set_caption(EMFolderSelector * selector,const gchar * caption)674 em_folder_selector_set_caption (EMFolderSelector *selector,
675 const gchar *caption)
676 {
677 gboolean visible;
678
679 g_return_if_fail (EM_IS_FOLDER_SELECTOR (selector));
680
681 if (g_strcmp0 (caption, selector->priv->caption) == 0)
682 return;
683
684 g_free (selector->priv->caption);
685 selector->priv->caption = e_util_strdup_strip (caption);
686
687 visible = (selector->priv->caption != NULL);
688 gtk_widget_set_visible (selector->priv->caption_label, visible);
689
690 g_object_notify (G_OBJECT (selector), "caption");
691 }
692
693 /**
694 * em_folder_selector_get_default_button_label:
695 * @selector: an #EMFolderSelector
696 *
697 * Returns the label for the dialog's default button, which triggers a
698 * #GTK_RESPONSE_OK response ID.
699 *
700 * Returns: the label for the default button
701 **/
702 const gchar *
em_folder_selector_get_default_button_label(EMFolderSelector * selector)703 em_folder_selector_get_default_button_label (EMFolderSelector *selector)
704 {
705 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), NULL);
706
707 return selector->priv->default_button_label;
708 }
709
710 /**
711 * em_folder_selector_set_default_button_label:
712 * @selector: an #EMFolderSelector
713 * @button_label: the label for the default button, or %NULL
714 *
715 * Sets the label for the dialog's default button, which triggers a
716 * #GTK_RESPONSE_OK response ID. If @button_label is %NULL, the default
717 * button's label is reset to "OK".
718 **/
719 void
em_folder_selector_set_default_button_label(EMFolderSelector * selector,const gchar * button_label)720 em_folder_selector_set_default_button_label (EMFolderSelector *selector,
721 const gchar *button_label)
722 {
723 g_return_if_fail (EM_IS_FOLDER_SELECTOR (selector));
724
725 if (button_label == NULL)
726 button_label = gettext (DEFAULT_BUTTON_LABEL);
727
728 if (g_strcmp0 (button_label, selector->priv->default_button_label) == 0)
729 return;
730
731 g_free (selector->priv->default_button_label);
732 selector->priv->default_button_label = g_strdup (button_label);
733
734 g_object_notify (G_OBJECT (selector), "default-button-label");
735 }
736
737 EMFolderTreeModel *
em_folder_selector_get_model(EMFolderSelector * selector)738 em_folder_selector_get_model (EMFolderSelector *selector)
739 {
740 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), NULL);
741
742 return selector->priv->model;
743 }
744
745 /**
746 * em_folder_selector_get_content_area:
747 * @selector: an #EMFolderSelector
748 *
749 * Returns the #GtkBox widget containing the dialog's content, including
750 * the #EMFolderTree widget. This is intended to help extend the dialog
751 * with additional widgets.
752 *
753 * Note, the returned #GtkBox is a child of the #GtkBox returned by
754 * gtk_dialog_get_content_area(), but with a properly set border width
755 * and 6 pixel spacing.
756 *
757 * Returns: a #GtkBox widget
758 **/
759 GtkWidget *
em_folder_selector_get_content_area(EMFolderSelector * selector)760 em_folder_selector_get_content_area (EMFolderSelector *selector)
761 {
762 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), NULL);
763
764 return selector->priv->content_area;
765 }
766
767 EMFolderTree *
em_folder_selector_get_folder_tree(EMFolderSelector * selector)768 em_folder_selector_get_folder_tree (EMFolderSelector *selector)
769 {
770 ETreeViewFrame *tree_view_frame;
771 GtkTreeView *tree_view;
772
773 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), NULL);
774
775 tree_view_frame = E_TREE_VIEW_FRAME (selector->priv->tree_view_frame);
776 tree_view = e_tree_view_frame_get_tree_view (tree_view_frame);
777
778 return EM_FOLDER_TREE (tree_view);
779 }
780
781 /**
782 * em_folder_selector_get_selected:
783 * @selector: an #EMFolderSelector
784 * @out_store: return location for a #CamelStore, or %NULL
785 * @out_folder_name: return location for a folder name string, or %NULL
786 *
787 * Sets @out_store and @out_folder_name to the currently selected folder
788 * in the @selector dialog and returns %TRUE. If only a #CamelStore row
789 * is selected, the function returns the #CamelStore through @out_store,
790 * sets @out_folder_name to %NULL and returns %TRUE.
791 *
792 * If the dialog has no selection, the function leaves @out_store and
793 * @out_folder_name unset and returns %FALSE.
794 *
795 * Unreference the returned #CamelStore with g_object_unref() and free
796 * the returned folder name with g_free() when finished with them.
797 *
798 * Returns: whether a row is selected in the @selector dialog
799 **/
800 gboolean
em_folder_selector_get_selected(EMFolderSelector * selector,CamelStore ** out_store,gchar ** out_folder_name)801 em_folder_selector_get_selected (EMFolderSelector *selector,
802 CamelStore **out_store,
803 gchar **out_folder_name)
804 {
805 EMFolderTree *folder_tree;
806
807 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), FALSE);
808
809 folder_tree = em_folder_selector_get_folder_tree (selector);
810
811 if (em_folder_tree_store_root_selected (folder_tree, out_store)) {
812 if (out_folder_name != NULL)
813 *out_folder_name = NULL;
814 return TRUE;
815 }
816
817 return em_folder_tree_get_selected (
818 folder_tree, out_store, out_folder_name);
819 }
820
821 /**
822 * em_folder_selector_set_selected:
823 * @selector: an #EMFolderSelector
824 * @store: a #CamelStore
825 * @folder_name: a folder name
826 *
827 * Selects the folder given by @store and @folder_name in the @selector
828 * dialog.
829 **/
830 void
em_folder_selector_set_selected(EMFolderSelector * selector,CamelStore * store,const gchar * folder_name)831 em_folder_selector_set_selected (EMFolderSelector *selector,
832 CamelStore *store,
833 const gchar *folder_name)
834 {
835 EMFolderTree *folder_tree;
836 gchar *folder_uri;
837
838 g_return_if_fail (EM_IS_FOLDER_SELECTOR (selector));
839 g_return_if_fail (CAMEL_IS_STORE (store));
840 g_return_if_fail (folder_name != NULL);
841
842 folder_tree = em_folder_selector_get_folder_tree (selector);
843 folder_uri = e_mail_folder_uri_build (store, folder_name);
844
845 em_folder_tree_set_selected (folder_tree, folder_uri, FALSE);
846
847 g_free (folder_uri);
848 }
849
850 const gchar *
em_folder_selector_get_selected_uri(EMFolderSelector * selector)851 em_folder_selector_get_selected_uri (EMFolderSelector *selector)
852 {
853 EMFolderTree *folder_tree;
854 gchar *uri;
855
856 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), NULL);
857
858 folder_tree = em_folder_selector_get_folder_tree (selector);
859 uri = em_folder_tree_get_selected_uri (folder_tree);
860
861 if (uri == NULL)
862 return NULL;
863
864 g_free (selector->priv->selected_uri);
865 selector->priv->selected_uri = uri; /* takes ownership */
866
867 return uri;
868 }
869
870 /**
871 * em_folder_selector_new_activity:
872 * @selector: an #EMFolderSelector
873 *
874 * Returns a new #EActivity configured to display status and error messages
875 * directly in the @selector dialog.
876 *
877 * Returns: an #EActivity
878 **/
879 EActivity *
em_folder_selector_new_activity(EMFolderSelector * selector)880 em_folder_selector_new_activity (EMFolderSelector *selector)
881 {
882 EActivity *activity;
883 EActivityBar *activity_bar;
884 EAlertSink *alert_sink;
885 GCancellable *cancellable;
886
887 g_return_val_if_fail (EM_IS_FOLDER_SELECTOR (selector), NULL);
888
889 activity = e_activity_new ();
890
891 alert_sink = E_ALERT_SINK (selector);
892 e_activity_set_alert_sink (activity, alert_sink);
893
894 cancellable = camel_operation_new ();
895 e_activity_set_cancellable (activity, cancellable);
896 g_object_unref (cancellable);
897
898 activity_bar = E_ACTIVITY_BAR (selector->priv->activity_bar);
899 e_activity_bar_set_activity (activity_bar, activity);
900
901 return activity;
902 }
903
904 void
em_folder_selector_maybe_collapse_archive_folders(EMFolderSelector * selector)905 em_folder_selector_maybe_collapse_archive_folders (EMFolderSelector *selector)
906 {
907 EMFolderTreeModel *model;
908 EMailSession *mail_session;
909 ESourceRegistry *registry;
910 CamelSession *session;
911 GSettings *settings;
912 GList *services, *link;
913 GHashTable *archives;
914 gchar *local_archive_folder;
915
916 g_return_if_fail (EM_IS_FOLDER_SELECTOR (selector));
917
918 settings = e_util_ref_settings ("org.gnome.evolution.mail");
919 if (!g_settings_get_boolean (settings, "collapse-archive-folders-in-selectors")) {
920 g_object_unref (settings);
921 return;
922 }
923 local_archive_folder = g_settings_get_string (settings, "local-archive-folder");
924 g_object_unref (settings);
925
926 model = em_folder_selector_get_model (selector);
927 mail_session = em_folder_tree_model_get_session (model);
928 registry = e_mail_session_get_registry (mail_session);
929 session = CAMEL_SESSION (mail_session);
930
931 archives = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
932
933 if (local_archive_folder && *local_archive_folder) {
934 g_hash_table_insert (archives, local_archive_folder, NULL);
935 } else {
936 g_free (local_archive_folder);
937 }
938
939 services = camel_session_list_services (session);
940 for (link = services; link; link = g_list_next (link)) {
941 CamelService *service = link->data;
942
943 if (CAMEL_IS_STORE (service)) {
944 ESource *source;
945
946 source = e_source_registry_ref_source (registry, camel_service_get_uid (service));
947 if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
948 ESourceMailAccount *account_ext;
949 gchar *archive_folder;
950
951 account_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
952
953 archive_folder = e_source_mail_account_dup_archive_folder (account_ext);
954 if (archive_folder && *archive_folder) {
955 g_hash_table_insert (archives, archive_folder, NULL);
956 } else {
957 g_free (archive_folder);
958 }
959 }
960
961 g_clear_object (&source);
962 }
963 }
964
965 g_list_free_full (services, g_object_unref);
966
967 if (g_hash_table_size (archives)) {
968 GtkTreeView *tree_view;
969 GHashTableIter iter;
970 gpointer key;
971
972 tree_view = GTK_TREE_VIEW (em_folder_selector_get_folder_tree (selector));
973
974 g_hash_table_iter_init (&iter, archives);
975
976 while (g_hash_table_iter_next (&iter, &key, NULL)) {
977 const gchar *folder_uri = key;
978 CamelStore *store = NULL;
979 gchar *folder_name = NULL;
980
981 if (folder_uri && *folder_uri &&
982 e_mail_folder_uri_parse (session, folder_uri, &store, &folder_name, NULL)) {
983 GtkTreeRowReference *row;
984
985 row = em_folder_tree_model_get_row_reference (model, store, folder_name);
986 if (row) {
987 GtkTreePath *path;
988
989 path = gtk_tree_row_reference_get_path (row);
990 gtk_tree_view_collapse_row (tree_view, path);
991 gtk_tree_path_free (path);
992 }
993
994 g_clear_object (&store);
995 g_free (folder_name);
996 }
997 }
998 }
999
1000 g_hash_table_destroy (archives);
1001 }
1002