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