1 /*
2  * e-attachment-paned.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-paned.h"
24 
25 #include <glib/gi18n.h>
26 
27 #include "e-misc-utils.h"
28 #include "e-attachment-view.h"
29 #include "e-attachment-store.h"
30 #include "e-attachment-icon-view.h"
31 #include "e-attachment-tree-view.h"
32 
33 #define E_ATTACHMENT_PANED_GET_PRIVATE(obj) \
34 	(G_TYPE_INSTANCE_GET_PRIVATE \
35 	((obj), E_TYPE_ATTACHMENT_PANED, EAttachmentPanedPrivate))
36 
37 #define NUM_VIEWS 2
38 
39 /* Initial height of the lower pane. */
40 static gint initial_height = 150;
41 
42 struct _EAttachmentPanedPrivate {
43 	GtkTreeModel *model;
44 	GtkWidget *expander;
45 	GtkWidget *notebook;
46 	GtkWidget *combo_box;
47 	GtkWidget *controls_container;
48 	GtkWidget *icon_view;
49 	GtkWidget *tree_view;
50 	GtkWidget *show_hide_label;
51 	GtkWidget *status_icon;
52 	GtkWidget *status_label;
53 	GtkWidget *content_area;
54 
55 	gint active_view;
56 	gint vpaned_handle_size;
57 	gboolean expanded;
58 	gboolean resize_toplevel;
59 };
60 
61 enum {
62 	PROP_0,
63 	PROP_ACTIVE_VIEW,
64 	PROP_DRAGGING,
65 	PROP_EDITABLE,
66 	PROP_EXPANDED,
67 	PROP_RESIZE_TOPLEVEL
68 };
69 
70 /* Forward Declarations */
71 static void	e_attachment_paned_interface_init
72 					(EAttachmentViewInterface *iface);
73 
G_DEFINE_TYPE_WITH_CODE(EAttachmentPaned,e_attachment_paned,GTK_TYPE_PANED,G_IMPLEMENT_INTERFACE (E_TYPE_ATTACHMENT_VIEW,e_attachment_paned_interface_init))74 G_DEFINE_TYPE_WITH_CODE (
75 	EAttachmentPaned,
76 	e_attachment_paned,
77 	GTK_TYPE_PANED,
78 	G_IMPLEMENT_INTERFACE (
79 		E_TYPE_ATTACHMENT_VIEW,
80 		e_attachment_paned_interface_init))
81 
82 void
83 e_attachment_paned_set_default_height (gint height)
84 {
85 	initial_height = height;
86 }
87 
88 static void
attachment_paned_notify_cb(EAttachmentPaned * paned,GParamSpec * pspec,GtkExpander * expander)89 attachment_paned_notify_cb (EAttachmentPaned *paned,
90                             GParamSpec *pspec,
91                             GtkExpander *expander)
92 {
93 	GtkAllocation toplevel_allocation;
94 	GtkWidget *toplevel;
95 	GtkWidget *child;
96 	GtkLabel *label;
97 	const gchar *text;
98 
99 	label = GTK_LABEL (paned->priv->show_hide_label);
100 
101 	/* Update the expander label. */
102 	if (gtk_expander_get_expanded (expander))
103 		text = _("Hide Attachment _Bar");
104 	else
105 		text = _("Show Attachment _Bar");
106 
107 	gtk_label_set_text_with_mnemonic (label, text);
108 
109 	/* Resize the top-level window if required conditions are met.
110 	 * This is based on gtk_expander_resize_toplevel(), but adapted
111 	 * to the fact our GtkExpander has no direct child widget. */
112 
113 	if (!e_attachment_paned_get_resize_toplevel (paned))
114 		return;
115 
116 	if (!gtk_widget_get_realized (GTK_WIDGET (paned)))
117 		return;
118 
119 	child = gtk_paned_get_child2 (GTK_PANED (paned));
120 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
121 
122 	if (toplevel == NULL)
123 		return;
124 
125 	if (!gtk_widget_get_realized (GTK_WIDGET (toplevel)))
126 		return;
127 
128 	gtk_widget_get_allocation (toplevel, &toplevel_allocation);
129 
130 	if (gtk_expander_get_expanded (expander)) {
131 		GtkRequisition child_requisition;
132 
133 		gtk_widget_get_preferred_size (
134 			child, &child_requisition, NULL);
135 
136 		toplevel_allocation.height += child_requisition.height;
137 	} else {
138 		GtkAllocation child_allocation;
139 
140 		gtk_widget_get_allocation (child, &child_allocation);
141 
142 		toplevel_allocation.height -= child_allocation.height;
143 	}
144 
145 	gtk_window_resize (
146 		GTK_WINDOW (toplevel),
147 		toplevel_allocation.width,
148 		toplevel_allocation.height);
149 }
150 
151 static void
attachment_paned_update_status(EAttachmentPaned * paned)152 attachment_paned_update_status (EAttachmentPaned *paned)
153 {
154 	EAttachmentView *view;
155 	EAttachmentStore *store;
156 	GtkExpander *expander;
157 	GtkLabel *label;
158 	guint num_attachments;
159 	guint64 total_size;
160 	gchar *display_size;
161 	gchar *markup;
162 
163 	view = E_ATTACHMENT_VIEW (paned);
164 	store = e_attachment_view_get_store (view);
165 	expander = GTK_EXPANDER (paned->priv->expander);
166 	label = GTK_LABEL (paned->priv->status_label);
167 
168 	num_attachments = e_attachment_store_get_num_attachments (store);
169 	total_size = e_attachment_store_get_total_size (store);
170 	display_size = g_format_size (total_size);
171 
172 	if (total_size > 0)
173 		markup = g_strdup_printf (
174 			"<b>%d</b> %s (%s)", num_attachments, ngettext (
175 			"Attachment", "Attachments", num_attachments),
176 			display_size);
177 	else
178 		markup = g_strdup_printf (
179 			"<b>%d</b> %s", num_attachments, ngettext (
180 			"Attachment", "Attachments", num_attachments));
181 	gtk_label_set_markup (label, markup);
182 	g_free (markup);
183 
184 	g_free (display_size);
185 
186 	if (num_attachments > 0) {
187 		gtk_widget_show (paned->priv->status_icon);
188 		gtk_widget_show (paned->priv->status_label);
189 		gtk_expander_set_expanded (expander, TRUE);
190 	} else {
191 		gtk_widget_hide (paned->priv->status_icon);
192 		gtk_widget_hide (paned->priv->status_label);
193 		gtk_expander_set_expanded (expander, FALSE);
194 	}
195 }
196 
197 static void
attachment_paned_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)198 attachment_paned_set_property (GObject *object,
199                                guint property_id,
200                                const GValue *value,
201                                GParamSpec *pspec)
202 {
203 	switch (property_id) {
204 		case PROP_ACTIVE_VIEW:
205 			e_attachment_paned_set_active_view (
206 				E_ATTACHMENT_PANED (object),
207 				g_value_get_int (value));
208 			return;
209 
210 		case PROP_DRAGGING:
211 			e_attachment_view_set_dragging (
212 				E_ATTACHMENT_VIEW (object),
213 				g_value_get_boolean (value));
214 			return;
215 
216 		case PROP_EDITABLE:
217 			e_attachment_view_set_editable (
218 				E_ATTACHMENT_VIEW (object),
219 				g_value_get_boolean (value));
220 			return;
221 
222 		case PROP_EXPANDED:
223 			e_attachment_paned_set_expanded (
224 				E_ATTACHMENT_PANED (object),
225 				g_value_get_boolean (value));
226 			return;
227 
228 		case PROP_RESIZE_TOPLEVEL:
229 			e_attachment_paned_set_resize_toplevel (
230 				E_ATTACHMENT_PANED (object),
231 				g_value_get_boolean (value));
232 			return;
233 	}
234 
235 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
236 }
237 
238 static void
attachment_paned_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)239 attachment_paned_get_property (GObject *object,
240                                guint property_id,
241                                GValue *value,
242                                GParamSpec *pspec)
243 {
244 	switch (property_id) {
245 		case PROP_ACTIVE_VIEW:
246 			g_value_set_int (
247 				value,
248 				e_attachment_paned_get_active_view (
249 				E_ATTACHMENT_PANED (object)));
250 			return;
251 
252 		case PROP_DRAGGING:
253 			g_value_set_boolean (
254 				value,
255 				e_attachment_view_get_dragging (
256 				E_ATTACHMENT_VIEW (object)));
257 			return;
258 
259 		case PROP_EDITABLE:
260 			g_value_set_boolean (
261 				value,
262 				e_attachment_view_get_editable (
263 				E_ATTACHMENT_VIEW (object)));
264 			return;
265 
266 		case PROP_EXPANDED:
267 			g_value_set_boolean (
268 				value,
269 				e_attachment_paned_get_expanded (
270 				E_ATTACHMENT_PANED (object)));
271 			return;
272 
273 		case PROP_RESIZE_TOPLEVEL:
274 			g_value_set_boolean (
275 				value,
276 				e_attachment_paned_get_resize_toplevel (
277 				E_ATTACHMENT_PANED (object)));
278 			return;
279 	}
280 
281 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
282 }
283 
284 static void
attachment_paned_dispose(GObject * object)285 attachment_paned_dispose (GObject *object)
286 {
287 	EAttachmentPanedPrivate *priv;
288 
289 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (object);
290 
291 	if (priv->model != NULL) {
292 		e_attachment_store_remove_all (E_ATTACHMENT_STORE (priv->model));
293 		g_object_unref (priv->model);
294 		priv->model = NULL;
295 	}
296 
297 	g_clear_object (&priv->expander);
298 	g_clear_object (&priv->notebook);
299 	g_clear_object (&priv->combo_box);
300 	g_clear_object (&priv->icon_view);
301 	g_clear_object (&priv->tree_view);
302 	g_clear_object (&priv->show_hide_label);
303 	g_clear_object (&priv->status_icon);
304 	g_clear_object (&priv->status_label);
305 	g_clear_object (&priv->content_area);
306 
307 	/* Chain up to parent's dispose() method. */
308 	G_OBJECT_CLASS (e_attachment_paned_parent_class)->dispose (object);
309 }
310 
311 static void
attachment_paned_constructed(GObject * object)312 attachment_paned_constructed (GObject *object)
313 {
314 	EAttachmentPanedPrivate *priv;
315 	GSettings *settings;
316 
317 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (object);
318 
319 	settings = e_util_ref_settings ("org.gnome.evolution.shell");
320 
321 	/* Set up property-to-property bindings. */
322 
323 	e_binding_bind_property (
324 		object, "active-view",
325 		priv->combo_box, "active",
326 		G_BINDING_BIDIRECTIONAL |
327 		G_BINDING_SYNC_CREATE);
328 
329 	e_binding_bind_property (
330 		object, "active-view",
331 		priv->notebook, "page",
332 		G_BINDING_BIDIRECTIONAL |
333 		G_BINDING_SYNC_CREATE);
334 
335 	e_binding_bind_property (
336 		object, "dragging",
337 		priv->icon_view, "dragging",
338 		G_BINDING_BIDIRECTIONAL |
339 		G_BINDING_SYNC_CREATE);
340 
341 	e_binding_bind_property (
342 		object, "dragging",
343 		priv->tree_view, "dragging",
344 		G_BINDING_BIDIRECTIONAL |
345 		G_BINDING_SYNC_CREATE);
346 
347 	e_binding_bind_property (
348 		object, "editable",
349 		priv->icon_view, "editable",
350 		G_BINDING_BIDIRECTIONAL |
351 		G_BINDING_SYNC_CREATE);
352 
353 	e_binding_bind_property (
354 		object, "editable",
355 		priv->tree_view, "editable",
356 		G_BINDING_BIDIRECTIONAL |
357 		G_BINDING_SYNC_CREATE);
358 
359 	e_binding_bind_property (
360 		object, "expanded",
361 		priv->expander, "expanded",
362 		G_BINDING_BIDIRECTIONAL |
363 		G_BINDING_SYNC_CREATE);
364 
365 	e_binding_bind_property (
366 		object, "expanded",
367 		priv->combo_box, "sensitive",
368 		G_BINDING_BIDIRECTIONAL |
369 		G_BINDING_SYNC_CREATE);
370 
371 	e_binding_bind_property (
372 		object, "expanded",
373 		priv->notebook, "visible",
374 		G_BINDING_BIDIRECTIONAL |
375 		G_BINDING_SYNC_CREATE);
376 
377 	/* Set up property-to-GSettings bindings. */
378 	g_settings_bind (
379 		settings, "attachment-view",
380 		object, "active-view",
381 		G_SETTINGS_BIND_DEFAULT);
382 
383 	g_object_unref (settings);
384 
385 	/* Chain up to parent's constructed() method. */
386 	G_OBJECT_CLASS (e_attachment_paned_parent_class)->constructed (object);
387 }
388 
389 static EAttachmentViewPrivate *
attachment_paned_get_private(EAttachmentView * view)390 attachment_paned_get_private (EAttachmentView *view)
391 {
392 	EAttachmentPanedPrivate *priv;
393 
394 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
395 	view = E_ATTACHMENT_VIEW (priv->icon_view);
396 
397 	return e_attachment_view_get_private (view);
398 }
399 
400 static EAttachmentStore *
attachment_paned_get_store(EAttachmentView * view)401 attachment_paned_get_store (EAttachmentView *view)
402 {
403 	EAttachmentPanedPrivate *priv;
404 
405 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
406 	view = E_ATTACHMENT_VIEW (priv->icon_view);
407 
408 	return e_attachment_view_get_store (view);
409 }
410 
411 static GtkTreePath *
attachment_paned_get_path_at_pos(EAttachmentView * view,gint x,gint y)412 attachment_paned_get_path_at_pos (EAttachmentView *view,
413                                   gint x,
414                                   gint y)
415 {
416 	EAttachmentPanedPrivate *priv;
417 
418 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
419 	view = E_ATTACHMENT_VIEW (priv->icon_view);
420 
421 	return e_attachment_view_get_path_at_pos (view, x, y);
422 }
423 
424 static GList *
attachment_paned_get_selected_paths(EAttachmentView * view)425 attachment_paned_get_selected_paths (EAttachmentView *view)
426 {
427 	EAttachmentPanedPrivate *priv;
428 
429 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
430 	view = E_ATTACHMENT_VIEW (priv->icon_view);
431 
432 	return e_attachment_view_get_selected_paths (view);
433 }
434 
435 static gboolean
attachment_paned_path_is_selected(EAttachmentView * view,GtkTreePath * path)436 attachment_paned_path_is_selected (EAttachmentView *view,
437                                    GtkTreePath *path)
438 {
439 	EAttachmentPanedPrivate *priv;
440 
441 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
442 	view = E_ATTACHMENT_VIEW (priv->icon_view);
443 
444 	return e_attachment_view_path_is_selected (view, path);
445 }
446 
447 static void
attachment_paned_select_path(EAttachmentView * view,GtkTreePath * path)448 attachment_paned_select_path (EAttachmentView *view,
449                               GtkTreePath *path)
450 {
451 	EAttachmentPanedPrivate *priv;
452 
453 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
454 	view = E_ATTACHMENT_VIEW (priv->icon_view);
455 
456 	e_attachment_view_select_path (view, path);
457 }
458 
459 static void
attachment_paned_unselect_path(EAttachmentView * view,GtkTreePath * path)460 attachment_paned_unselect_path (EAttachmentView *view,
461                                 GtkTreePath *path)
462 {
463 	EAttachmentPanedPrivate *priv;
464 
465 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
466 	view = E_ATTACHMENT_VIEW (priv->icon_view);
467 
468 	e_attachment_view_unselect_path (view, path);
469 }
470 
471 static void
attachment_paned_select_all(EAttachmentView * view)472 attachment_paned_select_all (EAttachmentView *view)
473 {
474 	EAttachmentPanedPrivate *priv;
475 
476 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
477 	view = E_ATTACHMENT_VIEW (priv->icon_view);
478 
479 	e_attachment_view_select_all (view);
480 }
481 
482 static void
attachment_paned_unselect_all(EAttachmentView * view)483 attachment_paned_unselect_all (EAttachmentView *view)
484 {
485 	EAttachmentPanedPrivate *priv;
486 
487 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
488 	view = E_ATTACHMENT_VIEW (priv->icon_view);
489 
490 	e_attachment_view_unselect_all (view);
491 }
492 
493 static void
attachment_paned_update_actions(EAttachmentView * view)494 attachment_paned_update_actions (EAttachmentView *view)
495 {
496 	EAttachmentPanedPrivate *priv;
497 
498 	priv = E_ATTACHMENT_PANED_GET_PRIVATE (view);
499 	view = E_ATTACHMENT_VIEW (priv->icon_view);
500 
501 	e_attachment_view_update_actions (view);
502 }
503 
504 static void
e_attachment_paned_class_init(EAttachmentPanedClass * class)505 e_attachment_paned_class_init (EAttachmentPanedClass *class)
506 {
507 	GObjectClass *object_class;
508 
509 	g_type_class_add_private (class, sizeof (EAttachmentPanedPrivate));
510 
511 	object_class = G_OBJECT_CLASS (class);
512 	object_class->set_property = attachment_paned_set_property;
513 	object_class->get_property = attachment_paned_get_property;
514 	object_class->dispose = attachment_paned_dispose;
515 	object_class->constructed = attachment_paned_constructed;
516 
517 	g_object_class_install_property (
518 		object_class,
519 		PROP_ACTIVE_VIEW,
520 		g_param_spec_int (
521 			"active-view",
522 			"Active View",
523 			NULL,
524 			0,
525 			NUM_VIEWS,
526 			0,
527 			G_PARAM_READWRITE |
528 			G_PARAM_CONSTRUCT |
529 			G_PARAM_STATIC_STRINGS));
530 
531 	g_object_class_override_property (
532 		object_class, PROP_DRAGGING, "dragging");
533 
534 	g_object_class_override_property (
535 		object_class, PROP_EDITABLE, "editable");
536 
537 	g_object_class_install_property (
538 		object_class,
539 		PROP_EXPANDED,
540 		g_param_spec_boolean (
541 			"expanded",
542 			"Expanded",
543 			NULL,
544 			FALSE,
545 			G_PARAM_READWRITE |
546 			G_PARAM_CONSTRUCT |
547 			G_PARAM_STATIC_STRINGS));
548 
549 	g_object_class_install_property (
550 		object_class,
551 		PROP_RESIZE_TOPLEVEL,
552 		g_param_spec_boolean (
553 			"resize-toplevel",
554 			"Resize-Toplevel",
555 			NULL,
556 			FALSE,
557 			G_PARAM_READWRITE |
558 			G_PARAM_CONSTRUCT |
559 			G_PARAM_STATIC_STRINGS));
560 }
561 
562 static void
attachment_paned_style_updated_cb(EAttachmentPaned * paned)563 attachment_paned_style_updated_cb (EAttachmentPaned *paned)
564 {
565 	g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
566 
567 	gtk_widget_style_get (
568 		GTK_WIDGET (paned), "handle-size",
569 		&paned->priv->vpaned_handle_size, NULL);
570 
571 	if (paned->priv->vpaned_handle_size < 0)
572 		paned->priv->vpaned_handle_size = 0;
573 }
574 
575 static void
e_attachment_paned_init(EAttachmentPaned * paned)576 e_attachment_paned_init (EAttachmentPaned *paned)
577 {
578 	EAttachmentView *view;
579 	GtkSizeGroup *size_group;
580 	GtkWidget *container;
581 	GtkWidget *widget;
582 	GtkAction *action;
583 
584 	paned->priv = E_ATTACHMENT_PANED_GET_PRIVATE (paned);
585 	paned->priv->model = e_attachment_store_new ();
586 
587 	gtk_orientable_set_orientation (GTK_ORIENTABLE (paned), GTK_ORIENTATION_VERTICAL);
588 
589 	/* Keep the expander label and combo box the same height. */
590 	size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
591 
592 	/* Construct the Attachment Views */
593 
594 	container = GTK_WIDGET (paned);
595 
596 	widget = gtk_notebook_new ();
597 	gtk_widget_set_size_request (widget, -1, initial_height);
598 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
599 	gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
600 	gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
601 	paned->priv->notebook = g_object_ref (widget);
602 	gtk_widget_hide (widget);
603 
604 	container = paned->priv->notebook;
605 
606 	widget = gtk_scrolled_window_new (NULL, NULL);
607 	gtk_scrolled_window_set_policy (
608 		GTK_SCROLLED_WINDOW (widget),
609 		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
610 	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
611 	gtk_widget_show (widget);
612 
613 	container = widget;
614 
615 	widget = e_attachment_icon_view_new ();
616 	gtk_widget_set_can_focus (widget, TRUE);
617 	gtk_icon_view_set_model (GTK_ICON_VIEW (widget), paned->priv->model);
618 	gtk_container_add (GTK_CONTAINER (container), widget);
619 	paned->priv->icon_view = g_object_ref (widget);
620 	gtk_widget_show (widget);
621 
622 	container = paned->priv->notebook;
623 
624 	widget = gtk_scrolled_window_new (NULL, NULL);
625 	gtk_scrolled_window_set_policy (
626 		GTK_SCROLLED_WINDOW (widget),
627 		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
628 	gtk_scrolled_window_set_shadow_type (
629 		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
630 	gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
631 	gtk_widget_show (widget);
632 
633 	container = widget;
634 
635 	widget = e_attachment_tree_view_new ();
636 	gtk_widget_set_can_focus (widget, TRUE);
637 	gtk_tree_view_set_model (GTK_TREE_VIEW (widget), paned->priv->model);
638 	gtk_container_add (GTK_CONTAINER (container), widget);
639 	paned->priv->tree_view = g_object_ref (widget);
640 	gtk_widget_show (widget);
641 
642 	/* Construct the Controls */
643 
644 	container = GTK_WIDGET (paned);
645 
646 	widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
647 	gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
648 	paned->priv->content_area = g_object_ref (widget);
649 	gtk_widget_show (widget);
650 
651 	paned->priv->vpaned_handle_size = 5;
652 	attachment_paned_style_updated_cb (paned);
653 
654 	g_signal_connect (
655 		GTK_PANED (paned), "style-updated",
656 		G_CALLBACK (attachment_paned_style_updated_cb), NULL);
657 
658 	container = widget;
659 
660 	widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
661 	gtk_widget_set_margin_right (widget, 6);
662 	gtk_widget_set_margin_left (widget, 6);
663 	gtk_widget_set_margin_bottom (widget, 6);
664 	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
665 	paned->priv->controls_container = widget;
666 	gtk_widget_show (widget);
667 
668 	container = widget;
669 
670 	widget = gtk_expander_new (NULL);
671 	gtk_expander_set_spacing (GTK_EXPANDER (widget), 0);
672 	gtk_expander_set_label_fill (GTK_EXPANDER (widget), TRUE);
673 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
674 	paned->priv->expander = g_object_ref (widget);
675 	gtk_widget_show (widget);
676 
677 	/* The "Add Attachment" button proxies the "add" action from
678 	 * one of the two attachment views.  Doesn't matter which. */
679 	widget = gtk_button_new ();
680 	view = E_ATTACHMENT_VIEW (paned->priv->icon_view);
681 	action = e_attachment_view_get_action (view, "add");
682 	gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ());
683 	gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action);
684 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
685 	gtk_widget_show (widget);
686 
687 	widget = gtk_combo_box_text_new ();
688 	gtk_size_group_add_widget (size_group, widget);
689 	gtk_combo_box_text_append_text (
690 		GTK_COMBO_BOX_TEXT (widget), _("Icon View"));
691 	gtk_combo_box_text_append_text (
692 		GTK_COMBO_BOX_TEXT (widget), _("List View"));
693 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
694 	paned->priv->combo_box = g_object_ref (widget);
695 	gtk_widget_show (widget);
696 
697 	container = paned->priv->expander;
698 
699 	widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
700 	gtk_size_group_add_widget (size_group, widget);
701 	gtk_expander_set_label_widget (GTK_EXPANDER (container), widget);
702 	gtk_widget_show (widget);
703 
704 	container = widget;
705 
706 	widget = gtk_label_new_with_mnemonic (_("Show Attachment _Bar"));
707 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
708 	paned->priv->show_hide_label = g_object_ref (widget);
709 	gtk_widget_show (widget);
710 
711 	widget = gtk_alignment_new (0.5, 0.5, 0.0, 1.0);
712 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
713 	gtk_widget_show (widget);
714 
715 	container = widget;
716 
717 	widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
718 	gtk_container_add (GTK_CONTAINER (container), widget);
719 	gtk_widget_show (widget);
720 
721 	container = widget;
722 
723 	widget = gtk_image_new_from_icon_name (
724 		"mail-attachment", GTK_ICON_SIZE_MENU);
725 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
726 	paned->priv->status_icon = g_object_ref (widget);
727 	gtk_widget_hide (widget);
728 
729 	widget = gtk_label_new (NULL);
730 	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
731 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
732 	paned->priv->status_label = g_object_ref (widget);
733 	gtk_widget_hide (widget);
734 
735 	e_signal_connect_notify_swapped (
736 		paned->priv->expander, "notify::expanded",
737 		G_CALLBACK (attachment_paned_notify_cb), paned);
738 
739 	e_signal_connect_notify_swapped (
740 		paned->priv->model, "notify::num-attachments",
741 		G_CALLBACK (attachment_paned_update_status), paned);
742 
743 	e_signal_connect_notify_swapped (
744 		paned->priv->model, "notify::total-size",
745 		G_CALLBACK (attachment_paned_update_status), paned);
746 
747 	g_object_unref (size_group);
748 
749 	attachment_paned_notify_cb (paned, NULL, GTK_EXPANDER (paned->priv->expander));
750 }
751 
752 static void
e_attachment_paned_interface_init(EAttachmentViewInterface * iface)753 e_attachment_paned_interface_init (EAttachmentViewInterface *iface)
754 {
755 	iface->get_private = attachment_paned_get_private;
756 	iface->get_store = attachment_paned_get_store;
757 	iface->get_path_at_pos = attachment_paned_get_path_at_pos;
758 	iface->get_selected_paths = attachment_paned_get_selected_paths;
759 	iface->path_is_selected = attachment_paned_path_is_selected;
760 	iface->select_path = attachment_paned_select_path;
761 	iface->unselect_path = attachment_paned_unselect_path;
762 	iface->select_all = attachment_paned_select_all;
763 	iface->unselect_all = attachment_paned_unselect_all;
764 	iface->update_actions = attachment_paned_update_actions;
765 }
766 
767 GtkWidget *
e_attachment_paned_new(void)768 e_attachment_paned_new (void)
769 {
770 	return g_object_new (E_TYPE_ATTACHMENT_PANED, NULL);
771 }
772 
773 GtkWidget *
e_attachment_paned_get_content_area(EAttachmentPaned * paned)774 e_attachment_paned_get_content_area (EAttachmentPaned *paned)
775 {
776 	g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), NULL);
777 
778 	return paned->priv->content_area;
779 }
780 
781 gint
e_attachment_paned_get_active_view(EAttachmentPaned * paned)782 e_attachment_paned_get_active_view (EAttachmentPaned *paned)
783 {
784 	g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), 0);
785 
786 	return paned->priv->active_view;
787 }
788 
789 void
e_attachment_paned_set_active_view(EAttachmentPaned * paned,gint active_view)790 e_attachment_paned_set_active_view (EAttachmentPaned *paned,
791                                     gint active_view)
792 {
793 	EAttachmentView *source;
794 	EAttachmentView *target;
795 
796 	g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
797 	g_return_if_fail (active_view >= 0 && active_view < NUM_VIEWS);
798 
799 	if (active_view == paned->priv->active_view)
800 		return;
801 
802 	paned->priv->active_view = active_view;
803 
804 	/* Synchronize the item selection of the view we're
805 	 * switching TO with the view we're switching FROM. */
806 	if (active_view == 0) {
807 		/* from tree view to icon view */
808 		source = E_ATTACHMENT_VIEW (paned->priv->tree_view);
809 		target = E_ATTACHMENT_VIEW (paned->priv->icon_view);
810 	} else {
811 		/* from icon view to tree view */
812 		source = E_ATTACHMENT_VIEW (paned->priv->icon_view);
813 		target = E_ATTACHMENT_VIEW (paned->priv->tree_view);
814 	}
815 
816 	e_attachment_view_sync_selection (source, target);
817 
818 	g_object_notify (G_OBJECT (paned), "active-view");
819 }
820 
821 gboolean
e_attachment_paned_get_expanded(EAttachmentPaned * paned)822 e_attachment_paned_get_expanded (EAttachmentPaned *paned)
823 {
824 	g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), FALSE);
825 
826 	return paned->priv->expanded;
827 }
828 
829 void
e_attachment_paned_set_expanded(EAttachmentPaned * paned,gboolean expanded)830 e_attachment_paned_set_expanded (EAttachmentPaned *paned,
831                                  gboolean expanded)
832 {
833 	g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
834 
835 	if (paned->priv->expanded == expanded)
836 		return;
837 
838 	paned->priv->expanded = expanded;
839 
840 	g_object_notify (G_OBJECT (paned), "expanded");
841 }
842 
843 gboolean
e_attachment_paned_get_resize_toplevel(EAttachmentPaned * paned)844 e_attachment_paned_get_resize_toplevel (EAttachmentPaned *paned)
845 {
846 	g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), FALSE);
847 
848 	return paned->priv->resize_toplevel;
849 }
850 
851 void
e_attachment_paned_set_resize_toplevel(EAttachmentPaned * paned,gboolean resize_toplevel)852 e_attachment_paned_set_resize_toplevel (EAttachmentPaned *paned,
853                                         gboolean resize_toplevel)
854 {
855 	g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
856 
857 	if (paned->priv->resize_toplevel == resize_toplevel)
858 		return;
859 
860 	paned->priv->resize_toplevel = resize_toplevel;
861 
862 	g_object_notify (G_OBJECT (paned), "resize-toplevel");
863 }
864 
865 void
e_attachment_paned_drag_data_received(EAttachmentPaned * paned,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection,guint info,guint time)866 e_attachment_paned_drag_data_received (EAttachmentPaned *paned,
867                                        GdkDragContext *context,
868                                        gint x,
869                                        gint y,
870                                        GtkSelectionData *selection,
871                                        guint info,
872                                        guint time)
873 {
874 	g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
875 
876 	/* XXX Dirty hack for forwarding drop events. */
877 	g_signal_emit_by_name (
878 		paned->priv->icon_view, "drag-data-received",
879 		context, x, y, selection, info, time);
880 }
881 
882 GtkWidget *
e_attachment_paned_get_controls_container(EAttachmentPaned * paned)883 e_attachment_paned_get_controls_container (EAttachmentPaned *paned)
884 {
885 	return paned->priv->controls_container;
886 }
887 
888 GtkWidget *
e_attachment_paned_get_view_combo(EAttachmentPaned * paned)889 e_attachment_paned_get_view_combo (EAttachmentPaned *paned)
890 {
891 	return paned->priv->combo_box;
892 }
893 
894