1 /*
2  * e-attachment-bar.c
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  *
16  *
17  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
18  *
19  */
20 
21 #include "evolution-config.h"
22 
23 #include "e-attachment-bar.h"
24 
25 #include <glib/gi18n.h>
26 
27 #include "e-attachment-store.h"
28 #include "e-attachment-icon-view.h"
29 #include "e-attachment-tree-view.h"
30 #include "e-misc-utils.h"
31 
32 #define E_ATTACHMENT_BAR_GET_PRIVATE(obj) \
33 	(G_TYPE_INSTANCE_GET_PRIVATE \
34 	((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarPrivate))
35 
36 #define NUM_VIEWS 2
37 
38 struct _EAttachmentBarPrivate {
39 	GtkTreeModel *model;
40 	GtkWidget *vbox;
41 	GtkWidget *expander;
42 	GtkWidget *combo_box;
43 	GtkWidget *icon_view;
44 	GtkWidget *tree_view;
45 	GtkWidget *icon_frame;
46 	GtkWidget *tree_frame;
47 	GtkWidget *status_icon;
48 	GtkWidget *status_label;
49 	GtkWidget *save_all_button;
50 	GtkWidget *save_one_button;
51 	GtkWidget *icon_scrolled_window; /* not referenced */
52 	GtkWidget *tree_scrolled_window; /* not referenced */
53 
54 	gint active_view;
55 	guint expanded : 1;
56 };
57 
58 enum {
59 	PROP_0,
60 	PROP_ACTIVE_VIEW,
61 	PROP_DRAGGING,
62 	PROP_EDITABLE,
63 	PROP_EXPANDED,
64 	PROP_STORE
65 };
66 
67 /* Forward Declarations */
68 static void	e_attachment_bar_interface_init
69 				(EAttachmentViewInterface *iface);
70 
G_DEFINE_TYPE_WITH_CODE(EAttachmentBar,e_attachment_bar,GTK_TYPE_BOX,G_IMPLEMENT_INTERFACE (E_TYPE_ATTACHMENT_VIEW,e_attachment_bar_interface_init))71 G_DEFINE_TYPE_WITH_CODE (
72 	EAttachmentBar,
73 	e_attachment_bar,
74 	GTK_TYPE_BOX,
75 	G_IMPLEMENT_INTERFACE (
76 		E_TYPE_ATTACHMENT_VIEW,
77 		e_attachment_bar_interface_init))
78 
79 static void
80 attachment_bar_update_status (EAttachmentBar *bar)
81 {
82 	EAttachmentStore *store;
83 	GtkActivatable *activatable;
84 	GtkAction *action;
85 	GtkLabel *label;
86 	gint num_attachments;
87 	guint64 total_size;
88 	gchar *display_size;
89 	gchar *markup;
90 
91 	store = E_ATTACHMENT_STORE (bar->priv->model);
92 	label = GTK_LABEL (bar->priv->status_label);
93 
94 	num_attachments = e_attachment_store_get_num_attachments (store);
95 	total_size = e_attachment_store_get_total_size (store);
96 	display_size = g_format_size (total_size);
97 
98 	if (total_size > 0)
99 		markup = g_strdup_printf (
100 			"<b>%d</b> %s (%s)", num_attachments, ngettext (
101 			"Attachment", "Attachments", num_attachments),
102 			display_size);
103 	else
104 		markup = g_strdup_printf (
105 			"<b>%d</b> %s", num_attachments, ngettext (
106 			"Attachment", "Attachments", num_attachments));
107 	gtk_label_set_markup (label, markup);
108 	g_free (markup);
109 
110 	activatable = GTK_ACTIVATABLE (bar->priv->save_all_button);
111 	action = gtk_activatable_get_related_action (activatable);
112 	gtk_action_set_visible (action, num_attachments > 1);
113 
114 	activatable = GTK_ACTIVATABLE (bar->priv->save_one_button);
115 	action = gtk_activatable_get_related_action (activatable);
116 	gtk_action_set_visible (action, (num_attachments == 1));
117 
118 	g_free (display_size);
119 }
120 
121 static void
attachment_bar_notify_vadjustment_upper_cb(GObject * object,GParamSpec * param,gpointer user_data)122 attachment_bar_notify_vadjustment_upper_cb (GObject *object,
123 					    GParamSpec *param,
124 					    gpointer user_data)
125 {
126 	EAttachmentBar *bar = user_data;
127 	GtkAdjustment *adjustment;
128 	gint max_upper, max_content_height = -2;
129 	gint request_height = -1;
130 
131 	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
132 
133 	adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (bar->priv->icon_scrolled_window));
134 	max_upper = gtk_adjustment_get_upper (adjustment);
135 
136 	adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (bar->priv->tree_scrolled_window));
137 	max_upper = MAX (max_upper, gtk_adjustment_get_upper (adjustment));
138 
139 	gtk_widget_style_get (GTK_WIDGET (bar), "max-content-height", &max_content_height, NULL);
140 
141 	if ((max_content_height >= 0 && max_content_height < 50) || max_content_height <= -2)
142 		max_content_height = 50;
143 
144 	if (max_content_height == -1) {
145 		request_height = max_upper;
146 	} else if (max_content_height < max_upper) {
147 		request_height = max_content_height;
148 	} else {
149 		request_height = max_upper;
150 	}
151 
152 	gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (bar->priv->icon_scrolled_window),
153 		request_height);
154 	gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (bar->priv->tree_scrolled_window),
155 		request_height);
156 }
157 
158 static void
attachment_bar_set_store(EAttachmentBar * bar,EAttachmentStore * store)159 attachment_bar_set_store (EAttachmentBar *bar,
160                           EAttachmentStore *store)
161 {
162 	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
163 
164 	bar->priv->model = GTK_TREE_MODEL (g_object_ref (store));
165 
166 	gtk_icon_view_set_model (
167 		GTK_ICON_VIEW (bar->priv->icon_view),
168 		bar->priv->model);
169 	gtk_tree_view_set_model (
170 		GTK_TREE_VIEW (bar->priv->tree_view),
171 		bar->priv->model);
172 
173 	e_signal_connect_notify_object (
174 		bar->priv->model, "notify::num-attachments",
175 		G_CALLBACK (attachment_bar_update_status), bar,
176 		G_CONNECT_SWAPPED);
177 
178 	e_signal_connect_notify_object (
179 		bar->priv->model, "notify::total-size",
180 		G_CALLBACK (attachment_bar_update_status), bar,
181 		G_CONNECT_SWAPPED);
182 
183 	/* Initialize */
184 	attachment_bar_update_status (bar);
185 }
186 
187 static void
attachment_bar_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)188 attachment_bar_set_property (GObject *object,
189                              guint property_id,
190                              const GValue *value,
191                              GParamSpec *pspec)
192 {
193 	switch (property_id) {
194 		case PROP_ACTIVE_VIEW:
195 				e_attachment_bar_set_active_view (
196 				E_ATTACHMENT_BAR (object),
197 				g_value_get_int (value));
198 			return;
199 
200 		case PROP_DRAGGING:
201 			e_attachment_view_set_dragging (
202 				E_ATTACHMENT_VIEW (object),
203 				g_value_get_boolean (value));
204 			return;
205 
206 		case PROP_EDITABLE:
207 			e_attachment_view_set_editable (
208 				E_ATTACHMENT_VIEW (object),
209 				g_value_get_boolean (value));
210 			return;
211 
212 		case PROP_EXPANDED:
213 			e_attachment_bar_set_expanded (
214 				E_ATTACHMENT_BAR (object),
215 				g_value_get_boolean (value));
216 			return;
217 		case PROP_STORE:
218 			attachment_bar_set_store (
219 				E_ATTACHMENT_BAR (object),
220 				g_value_get_object (value));
221 			return;
222 	}
223 
224 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
225 }
226 
227 static void
attachment_bar_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)228 attachment_bar_get_property (GObject *object,
229                              guint property_id,
230                              GValue *value,
231                              GParamSpec *pspec)
232 {
233 	switch (property_id) {
234 		case PROP_ACTIVE_VIEW:
235 			g_value_set_int (
236 				value,
237 				e_attachment_bar_get_active_view (
238 				E_ATTACHMENT_BAR (object)));
239 			return;
240 
241 		case PROP_DRAGGING:
242 			g_value_set_boolean (
243 				value,
244 				e_attachment_view_get_dragging (
245 				E_ATTACHMENT_VIEW (object)));
246 			return;
247 
248 		case PROP_EDITABLE:
249 			g_value_set_boolean (
250 				value,
251 				e_attachment_view_get_editable (
252 				E_ATTACHMENT_VIEW (object)));
253 			return;
254 
255 		case PROP_EXPANDED:
256 			g_value_set_boolean (
257 				value,
258 				e_attachment_bar_get_expanded (
259 				E_ATTACHMENT_BAR (object)));
260 			return;
261 		case PROP_STORE:
262 			g_value_set_object (
263 				value,
264 				e_attachment_bar_get_store (
265 				E_ATTACHMENT_BAR (object)));
266 	}
267 
268 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
269 }
270 
271 static void
attachment_bar_dispose(GObject * object)272 attachment_bar_dispose (GObject *object)
273 {
274 	EAttachmentBarPrivate *priv;
275 
276 	priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
277 	g_clear_object (&priv->model);
278 	g_clear_object (&priv->vbox);
279 	g_clear_object (&priv->expander);
280 	g_clear_object (&priv->combo_box);
281 	g_clear_object (&priv->icon_view);
282 	g_clear_object (&priv->tree_view);
283 	g_clear_object (&priv->icon_frame);
284 	g_clear_object (&priv->tree_frame);
285 	g_clear_object (&priv->status_icon);
286 	g_clear_object (&priv->status_label);
287 	g_clear_object (&priv->save_all_button);
288 	g_clear_object (&priv->save_one_button);
289 
290 	/* Chain up to parent's dispose() method. */
291 	G_OBJECT_CLASS (e_attachment_bar_parent_class)->dispose (object);
292 }
293 
294 static void
attachment_bar_constructed(GObject * object)295 attachment_bar_constructed (GObject *object)
296 {
297 	EAttachmentBarPrivate *priv;
298 	GSettings *settings;
299 
300 	priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
301 
302 	/* Set up property-to-property bindings. */
303 
304 	e_binding_bind_property (
305 		object, "active-view",
306 		priv->combo_box, "active",
307 		G_BINDING_BIDIRECTIONAL |
308 		G_BINDING_SYNC_CREATE);
309 
310 	e_binding_bind_property (
311 		object, "dragging",
312 		priv->icon_view, "dragging",
313 		G_BINDING_BIDIRECTIONAL |
314 		G_BINDING_SYNC_CREATE);
315 
316 	e_binding_bind_property (
317 		object, "dragging",
318 		priv->tree_view, "dragging",
319 		G_BINDING_BIDIRECTIONAL |
320 		G_BINDING_SYNC_CREATE);
321 
322 	e_binding_bind_property (
323 		object, "editable",
324 		priv->icon_view, "editable",
325 		G_BINDING_BIDIRECTIONAL |
326 		G_BINDING_SYNC_CREATE);
327 
328 	e_binding_bind_property (
329 		object, "editable",
330 		priv->tree_view, "editable",
331 		G_BINDING_BIDIRECTIONAL |
332 		G_BINDING_SYNC_CREATE);
333 
334 	e_binding_bind_property (
335 		object, "expanded",
336 		priv->expander, "expanded",
337 		G_BINDING_BIDIRECTIONAL |
338 		G_BINDING_SYNC_CREATE);
339 
340 	e_binding_bind_property (
341 		object, "expanded",
342 		priv->combo_box, "visible",
343 		G_BINDING_BIDIRECTIONAL |
344 		G_BINDING_SYNC_CREATE);
345 
346 	e_binding_bind_property (
347 		object, "expanded",
348 		priv->vbox, "visible",
349 		G_BINDING_BIDIRECTIONAL |
350 		G_BINDING_SYNC_CREATE);
351 
352 	/* Set up property-to-GSettings bindings. */
353 	settings = e_util_ref_settings ("org.gnome.evolution.shell");
354 	g_settings_bind (
355 		settings, "attachment-view",
356 		object, "active-view",
357 		G_SETTINGS_BIND_DEFAULT);
358 	g_object_unref (settings);
359 
360 	/* Chain up to parent's constructed() method. */
361 	G_OBJECT_CLASS (e_attachment_bar_parent_class)->constructed (object);
362 }
363 
364 static EAttachmentViewPrivate *
attachment_bar_get_private(EAttachmentView * view)365 attachment_bar_get_private (EAttachmentView *view)
366 {
367 	EAttachmentBar *bar;
368 
369 	bar = E_ATTACHMENT_BAR (view);
370 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
371 
372 	return e_attachment_view_get_private (view);
373 }
374 
375 static GtkTreePath *
attachment_bar_get_path_at_pos(EAttachmentView * view,gint x,gint y)376 attachment_bar_get_path_at_pos (EAttachmentView *view,
377                                 gint x,
378                                 gint y)
379 {
380 	EAttachmentBar *bar;
381 
382 	bar = E_ATTACHMENT_BAR (view);
383 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
384 
385 	return e_attachment_view_get_path_at_pos (view, x, y);
386 }
387 
388 static EAttachmentStore *
attachment_bar_get_store(EAttachmentView * view)389 attachment_bar_get_store (EAttachmentView *view)
390 {
391 	return e_attachment_bar_get_store (E_ATTACHMENT_BAR (view));
392 }
393 
394 static GList *
attachment_bar_get_selected_paths(EAttachmentView * view)395 attachment_bar_get_selected_paths (EAttachmentView *view)
396 {
397 	EAttachmentBar *bar;
398 
399 	bar = E_ATTACHMENT_BAR (view);
400 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
401 
402 	return e_attachment_view_get_selected_paths (view);
403 }
404 
405 static gboolean
attachment_bar_path_is_selected(EAttachmentView * view,GtkTreePath * path)406 attachment_bar_path_is_selected (EAttachmentView *view,
407                                  GtkTreePath *path)
408 {
409 	EAttachmentBar *bar;
410 
411 	bar = E_ATTACHMENT_BAR (view);
412 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
413 
414 	return e_attachment_view_path_is_selected (view, path);
415 }
416 
417 static void
attachment_bar_select_path(EAttachmentView * view,GtkTreePath * path)418 attachment_bar_select_path (EAttachmentView *view,
419                             GtkTreePath *path)
420 {
421 	EAttachmentBar *bar;
422 
423 	bar = E_ATTACHMENT_BAR (view);
424 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
425 
426 	e_attachment_view_select_path (view, path);
427 }
428 
429 static void
attachment_bar_unselect_path(EAttachmentView * view,GtkTreePath * path)430 attachment_bar_unselect_path (EAttachmentView *view,
431                               GtkTreePath *path)
432 {
433 	EAttachmentBar *bar;
434 
435 	bar = E_ATTACHMENT_BAR (view);
436 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
437 
438 	e_attachment_view_unselect_path (view, path);
439 }
440 
441 static void
attachment_bar_select_all(EAttachmentView * view)442 attachment_bar_select_all (EAttachmentView *view)
443 {
444 	EAttachmentBar *bar;
445 
446 	bar = E_ATTACHMENT_BAR (view);
447 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
448 
449 	e_attachment_view_select_all (view);
450 }
451 
452 static void
attachment_bar_unselect_all(EAttachmentView * view)453 attachment_bar_unselect_all (EAttachmentView *view)
454 {
455 	EAttachmentBar *bar;
456 
457 	bar = E_ATTACHMENT_BAR (view);
458 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
459 
460 	e_attachment_view_unselect_all (view);
461 }
462 
463 static void
attachment_bar_update_actions(EAttachmentView * view)464 attachment_bar_update_actions (EAttachmentView *view)
465 {
466 	EAttachmentBar *bar;
467 
468 	bar = E_ATTACHMENT_BAR (view);
469 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
470 
471 	e_attachment_view_update_actions (view);
472 }
473 
474 static gboolean
attachment_bar_button_press_event(GtkWidget * widget,GdkEventButton * event)475 attachment_bar_button_press_event (GtkWidget *widget,
476 				   GdkEventButton *event)
477 {
478 	/* Chain up to parent's button_press_event() method. */
479 	GTK_WIDGET_CLASS (e_attachment_bar_parent_class)->button_press_event (widget, event);
480 
481 	/* Never propagate the event to the parent */
482 	return TRUE;
483 }
484 
485 static gboolean
attachment_bar_button_release_event(GtkWidget * widget,GdkEventButton * event)486 attachment_bar_button_release_event (GtkWidget *widget,
487 				     GdkEventButton *event)
488 {
489 	/* Chain up to parent's button_release_event() method. */
490 	GTK_WIDGET_CLASS (e_attachment_bar_parent_class)->button_release_event (widget, event);
491 
492 	/* Never propagate the event to the parent */
493 	return TRUE;
494 }
495 
496 static gboolean
attachment_bar_motion_notify_event(GtkWidget * widget,GdkEventMotion * event)497 attachment_bar_motion_notify_event (GtkWidget *widget,
498 				    GdkEventMotion *event)
499 {
500 	/* Chain up to parent's motion_notify_event() method. */
501 	GTK_WIDGET_CLASS (e_attachment_bar_parent_class)->motion_notify_event (widget, event);
502 
503 	/* Never propagate the event to the parent */
504 	return TRUE;
505 }
506 
507 static void
e_attachment_bar_class_init(EAttachmentBarClass * class)508 e_attachment_bar_class_init (EAttachmentBarClass *class)
509 {
510 	GObjectClass *object_class;
511 	GtkWidgetClass *widget_class;
512 
513 	g_type_class_add_private (class, sizeof (EAttachmentBarPrivate));
514 
515 	object_class = G_OBJECT_CLASS (class);
516 	object_class->set_property = attachment_bar_set_property;
517 	object_class->get_property = attachment_bar_get_property;
518 	object_class->dispose = attachment_bar_dispose;
519 	object_class->constructed = attachment_bar_constructed;
520 
521 	widget_class = GTK_WIDGET_CLASS (class);
522 	widget_class->button_press_event = attachment_bar_button_press_event;
523 	widget_class->button_release_event = attachment_bar_button_release_event;
524 	widget_class->motion_notify_event = attachment_bar_motion_notify_event;
525 
526 	gtk_widget_class_set_css_name (widget_class, G_OBJECT_CLASS_NAME (class));
527 
528 	g_object_class_install_property (
529 		object_class,
530 		PROP_ACTIVE_VIEW,
531 		g_param_spec_int (
532 			"active-view",
533 			"Active View",
534 			NULL,
535 			0,
536 			NUM_VIEWS,
537 			0,
538 			G_PARAM_READWRITE |
539 			G_PARAM_CONSTRUCT));
540 
541 	g_object_class_install_property (
542 		object_class,
543 		PROP_EXPANDED,
544 		g_param_spec_boolean (
545 			"expanded",
546 			"Expanded",
547 			NULL,
548 			FALSE,
549 			G_PARAM_READWRITE |
550 			G_PARAM_CONSTRUCT));
551 
552 	g_object_class_install_property (
553 		object_class,
554 		PROP_STORE,
555 		g_param_spec_object (
556 			"store",
557 			"Attachment Store",
558 			NULL,
559 			E_TYPE_ATTACHMENT_STORE,
560 			G_PARAM_READWRITE |
561 			G_PARAM_CONSTRUCT_ONLY));
562 
563 	g_object_class_override_property (
564 		object_class, PROP_DRAGGING, "dragging");
565 
566 	g_object_class_override_property (
567 		object_class, PROP_EDITABLE, "editable");
568 
569 	gtk_widget_class_install_style_property (
570 		widget_class,
571 		g_param_spec_int (
572 			"max-content-height",
573 			"Max Content Height",
574 			NULL,
575 			-1, G_MAXINT, 150,
576 			G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
577 }
578 
579 static void
e_attachment_bar_interface_init(EAttachmentViewInterface * iface)580 e_attachment_bar_interface_init (EAttachmentViewInterface *iface)
581 {
582 	iface->get_private = attachment_bar_get_private;
583 	iface->get_store = attachment_bar_get_store;
584 	iface->get_path_at_pos = attachment_bar_get_path_at_pos;
585 	iface->get_selected_paths = attachment_bar_get_selected_paths;
586 	iface->path_is_selected = attachment_bar_path_is_selected;
587 	iface->select_path = attachment_bar_select_path;
588 	iface->unselect_path = attachment_bar_unselect_path;
589 	iface->select_all = attachment_bar_select_all;
590 	iface->unselect_all = attachment_bar_unselect_all;
591 	iface->update_actions = attachment_bar_update_actions;
592 }
593 
594 static void
e_attachment_bar_init(EAttachmentBar * bar)595 e_attachment_bar_init (EAttachmentBar *bar)
596 {
597 	EAttachmentView *view;
598 	GtkSizeGroup *size_group;
599 	GtkWidget *container;
600 	GtkWidget *widget;
601 	GtkAction *action;
602 	GtkAdjustment *adjustment;
603 
604 	gtk_widget_set_name (GTK_WIDGET (bar), "e-attachment-bar");
605 
606 	bar->priv = E_ATTACHMENT_BAR_GET_PRIVATE (bar);
607 
608 	gtk_orientable_set_orientation (GTK_ORIENTABLE (bar), GTK_ORIENTATION_VERTICAL);
609 
610 	/* Keep the expander label and save button the same height. */
611 	size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
612 
613 	/* Construct the Attachment Views */
614 
615 	container = GTK_WIDGET (bar);
616 
617 	widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
618 	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
619 	bar->priv->vbox = g_object_ref (widget);
620 	gtk_widget_show (widget);
621 
622 	container = bar->priv->vbox;
623 
624 	widget = gtk_frame_new (NULL);
625 	gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_NONE);
626 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
627 	bar->priv->icon_frame = g_object_ref (widget);
628 	gtk_widget_show (widget);
629 
630 	container = widget;
631 
632 	widget = gtk_scrolled_window_new (NULL, NULL);
633 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
634 	gtk_container_add (GTK_CONTAINER (container), widget);
635 	bar->priv->icon_scrolled_window = widget;
636 	gtk_widget_show (widget);
637 
638 	widget = e_attachment_icon_view_new ();
639 	gtk_widget_set_can_focus (widget, TRUE);
640 	gtk_icon_view_set_model (GTK_ICON_VIEW (widget), bar->priv->model);
641 	gtk_container_add (GTK_CONTAINER (bar->priv->icon_scrolled_window), widget);
642 	bar->priv->icon_view = g_object_ref (widget);
643 	gtk_widget_show (widget);
644 
645 	container = bar->priv->vbox;
646 
647 	widget = gtk_frame_new (NULL);
648 	gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_NONE);
649 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
650 	bar->priv->tree_frame = g_object_ref (widget);
651 	gtk_widget_hide (widget);
652 
653 	container = widget;
654 
655 	widget = gtk_scrolled_window_new (NULL, NULL);
656 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
657 	gtk_container_add (GTK_CONTAINER (container), widget);
658 	bar->priv->tree_scrolled_window = widget;
659 	gtk_widget_show (widget);
660 
661 	widget = e_attachment_tree_view_new ();
662 	gtk_widget_set_can_focus (widget, TRUE);
663 	gtk_tree_view_set_model (GTK_TREE_VIEW (widget), bar->priv->model);
664 	gtk_container_add (GTK_CONTAINER (bar->priv->tree_scrolled_window), widget);
665 	bar->priv->tree_view = g_object_ref (widget);
666 	gtk_widget_show (widget);
667 
668 	/* Construct the Controls */
669 
670 	container = GTK_WIDGET (bar);
671 
672 	widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
673 	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
674 	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
675 	gtk_widget_show (widget);
676 
677 	container = widget;
678 
679 	widget = gtk_expander_new (NULL);
680 	gtk_expander_set_spacing (GTK_EXPANDER (widget), 0);
681 	gtk_widget_set_valign (widget, GTK_ALIGN_CENTER);
682 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
683 	bar->priv->expander = g_object_ref (widget);
684 	gtk_widget_show (widget);
685 
686 	/* The "Save All" button proxies the "save-all" action from
687 	 * one of the two attachment views.  Doesn't matter which. */
688 	widget = gtk_button_new ();
689 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
690 	action = e_attachment_view_get_action (view, "save-all");
691 	gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ());
692 	gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action);
693 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
694 	bar->priv->save_all_button = g_object_ref (widget);
695 	gtk_widget_show (widget);
696 
697 	/* Same deal with the "Save" button. */
698 	widget = gtk_button_new ();
699 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
700 	action = e_attachment_view_get_action (view, "save-one");
701 	gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ());
702 	gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action);
703 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
704 	bar->priv->save_one_button = g_object_ref (widget);
705 	gtk_widget_show (widget);
706 
707 	widget = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
708 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
709 	gtk_widget_show (widget);
710 
711 	container = widget;
712 
713 	widget = gtk_combo_box_text_new ();
714 	gtk_size_group_add_widget (size_group, widget);
715 	gtk_combo_box_text_append_text (
716 		GTK_COMBO_BOX_TEXT (widget), _("Icon View"));
717 	gtk_combo_box_text_append_text (
718 		GTK_COMBO_BOX_TEXT (widget), _("List View"));
719 	gtk_container_add (GTK_CONTAINER (container), widget);
720 	bar->priv->combo_box = g_object_ref (widget);
721 	gtk_widget_show (widget);
722 
723 	container = bar->priv->expander;
724 
725 	widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
726 	gtk_size_group_add_widget (size_group, widget);
727 	gtk_expander_set_label_widget (GTK_EXPANDER (container), widget);
728 	gtk_widget_show (widget);
729 
730 	container = widget;
731 
732 	widget = gtk_image_new_from_icon_name (
733 		"mail-attachment", GTK_ICON_SIZE_MENU);
734 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
735 	bar->priv->status_icon = g_object_ref (widget);
736 	gtk_widget_show (widget);
737 
738 	widget = gtk_label_new (NULL);
739 	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
740 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
741 	bar->priv->status_label = g_object_ref (widget);
742 	gtk_widget_show (widget);
743 
744 	g_object_unref (size_group);
745 
746 	adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (bar->priv->icon_scrolled_window));
747 	e_signal_connect_notify (adjustment, "notify::upper",
748 		G_CALLBACK (attachment_bar_notify_vadjustment_upper_cb), bar);
749 
750 	adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (bar->priv->tree_scrolled_window));
751 	e_signal_connect_notify (adjustment, "notify::upper",
752 		G_CALLBACK (attachment_bar_notify_vadjustment_upper_cb), bar);
753 }
754 
755 GtkWidget *
e_attachment_bar_new(EAttachmentStore * store)756 e_attachment_bar_new (EAttachmentStore *store)
757 {
758 	g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), NULL);
759 
760 	return g_object_new (
761 		E_TYPE_ATTACHMENT_BAR,
762 		"editable", FALSE,
763 		"store", store, NULL);
764 }
765 
766 gint
e_attachment_bar_get_active_view(EAttachmentBar * bar)767 e_attachment_bar_get_active_view (EAttachmentBar *bar)
768 {
769 	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), 0);
770 
771 	return bar->priv->active_view;
772 }
773 
774 void
e_attachment_bar_set_active_view(EAttachmentBar * bar,gint active_view)775 e_attachment_bar_set_active_view (EAttachmentBar *bar,
776                                   gint active_view)
777 {
778 	EAttachmentView *source;
779 	EAttachmentView *target;
780 
781 	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
782 	g_return_if_fail (active_view >= 0 && active_view < NUM_VIEWS);
783 
784 	if (active_view == bar->priv->active_view)
785 		return;
786 
787 	bar->priv->active_view = active_view;
788 
789 	if (active_view == 0) {
790 		gtk_widget_show (bar->priv->icon_frame);
791 		gtk_widget_hide (bar->priv->tree_frame);
792 	} else {
793 		gtk_widget_hide (bar->priv->icon_frame);
794 		gtk_widget_show (bar->priv->tree_frame);
795 	}
796 
797 	/* Synchronize the item selection of the view we're
798 	 * switching TO with the view we're switching FROM. */
799 	if (active_view == 0) {
800 		/* from tree view to icon view */
801 		source = E_ATTACHMENT_VIEW (bar->priv->tree_view);
802 		target = E_ATTACHMENT_VIEW (bar->priv->icon_view);
803 	} else {
804 		/* from icon view to tree view */
805 		source = E_ATTACHMENT_VIEW (bar->priv->icon_view);
806 		target = E_ATTACHMENT_VIEW (bar->priv->tree_view);
807 	}
808 
809 	e_attachment_view_sync_selection (source, target);
810 
811 	g_object_notify (G_OBJECT (bar), "active-view");
812 }
813 
814 gboolean
e_attachment_bar_get_expanded(EAttachmentBar * bar)815 e_attachment_bar_get_expanded (EAttachmentBar *bar)
816 {
817 	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), FALSE);
818 
819 	return bar->priv->expanded;
820 }
821 
822 void
e_attachment_bar_set_expanded(EAttachmentBar * bar,gboolean expanded)823 e_attachment_bar_set_expanded (EAttachmentBar *bar,
824                                     gboolean expanded)
825 {
826 	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
827 
828 	if (bar->priv->expanded == expanded)
829 		return;
830 
831 	bar->priv->expanded = expanded;
832 
833 	g_object_notify (G_OBJECT (bar), "expanded");
834 }
835 
836 EAttachmentStore *
e_attachment_bar_get_store(EAttachmentBar * bar)837 e_attachment_bar_get_store (EAttachmentBar *bar)
838 {
839 	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
840 
841 	return E_ATTACHMENT_STORE (bar->priv->model);
842 }
843