* src/maemo/modest-msg-edit-window.c:
[modest] / src / widgets / modest-attachments-view.c
1 /* Copyright (c) 2007, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31
32 //#include <glib/gi18n-lib.h>
33
34 #include <string.h>
35 #include <gtk/gtk.h>
36
37 #include <tny-list.h>
38 #include <tny-simple-list.h>
39
40 #include <modest-platform.h>
41 #include <modest-runtime.h>
42 #include <modest-attachment-view.h>
43 #include <modest-attachments-view.h>
44
45 static GObjectClass *parent_class = NULL;
46
47 /* signals */
48 enum {
49         ACTIVATE_SIGNAL,
50         LAST_SIGNAL
51 };
52
53 typedef struct _ModestAttachmentsViewPrivate ModestAttachmentsViewPrivate;
54
55 struct _ModestAttachmentsViewPrivate
56 {
57         TnyMsg *msg;
58         GtkWidget *box;
59         GList *selected;
60         GtkWidget *rubber_start;
61 };
62
63 #define MODEST_ATTACHMENTS_VIEW_GET_PRIVATE(o)  \
64         (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_ATTACHMENTS_VIEW, ModestAttachmentsViewPrivate))
65
66 static gboolean button_press_event (GtkWidget *widget, GdkEventButton *event, ModestAttachmentsView *atts_view);
67 static gboolean motion_notify_event (GtkWidget *widget, GdkEventMotion *event, ModestAttachmentsView *atts_view);
68 static gboolean button_release_event (GtkWidget *widget, GdkEventButton *event, ModestAttachmentsView *atts_view);
69 static gboolean key_press_event (GtkWidget *widget, GdkEventKey *event, ModestAttachmentsView *atts_view);
70 static GtkWidget *get_att_view_at_coords (ModestAttachmentsView *atts_view,
71                                           gdouble x, gdouble y);
72 static void unselect_all (ModestAttachmentsView *atts_view);
73 static void set_selected (ModestAttachmentsView *atts_view, ModestAttachmentView *att_view);
74 static void select_range (ModestAttachmentsView *atts_view, ModestAttachmentView *att1, ModestAttachmentView *att2);
75 static void clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data,
76                            guint info, gpointer userdata);
77 static void clipboard_clear (GtkClipboard *clipboard, gpointer userdata);
78 static void own_clipboard (ModestAttachmentsView *atts_view);
79
80 static guint signals[LAST_SIGNAL] = {0};
81
82 /**
83  * modest_attachments_view_new:
84  * @msg: a #TnyMsg
85  *
86  * Constructor for attachments view widget.
87  *
88  * Return value: a new #ModestAttachmentsView instance implemented for Gtk+
89  **/
90 GtkWidget*
91 modest_attachments_view_new (TnyMsg *msg)
92 {
93         ModestAttachmentsView *self = g_object_new (MODEST_TYPE_ATTACHMENTS_VIEW, 
94                                                     "resize-mode", GTK_RESIZE_PARENT,
95                                                     NULL);
96
97         modest_attachments_view_set_message (self, msg);
98
99         return GTK_WIDGET (self);
100 }
101
102 void
103 modest_attachments_view_set_message (ModestAttachmentsView *attachments_view, TnyMsg *msg)
104 {
105         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (attachments_view);
106         TnyList *parts;
107         TnyIterator *iter;
108         
109         if (msg == priv->msg) return;
110
111         if (priv->msg) 
112                 g_object_unref (priv->msg);
113         if (msg)
114                 g_object_ref (G_OBJECT(msg));
115         
116         priv->msg = msg;
117
118         gtk_container_foreach (GTK_CONTAINER (priv->box), (GtkCallback) gtk_widget_destroy, NULL);
119         
120         if (priv->msg == NULL) {
121                 return;
122         }
123
124         parts = TNY_LIST (tny_simple_list_new ());
125         tny_mime_part_get_parts (TNY_MIME_PART (priv->msg), parts);
126         iter = tny_list_create_iterator (parts);
127
128         while (!tny_iterator_is_done (iter)) {
129                 TnyMimePart *part;
130
131                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
132                 if (tny_mime_part_is_attachment (part) || TNY_IS_MSG (part)) {
133                         modest_attachments_view_add_attachment (attachments_view, part);
134                 }
135                 g_object_unref (part);
136                 tny_iterator_next (iter);
137         }
138
139         gtk_widget_queue_draw (GTK_WIDGET (attachments_view));
140
141 }
142
143 void
144 modest_attachments_view_add_attachment (ModestAttachmentsView *attachments_view, TnyMimePart *part)
145 {
146         GtkWidget *att_view = NULL;
147         ModestAttachmentsViewPrivate *priv = NULL;
148
149         g_return_if_fail (MODEST_IS_ATTACHMENTS_VIEW (attachments_view));
150         g_return_if_fail (TNY_IS_MIME_PART (part));
151
152         priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (attachments_view);
153
154         att_view = modest_attachment_view_new (part);
155         gtk_box_pack_end (GTK_BOX (priv->box), att_view, FALSE, FALSE, 0);
156         gtk_widget_show_all (att_view);
157 }
158
159 void
160 modest_attachments_view_remove_attachment (ModestAttachmentsView *atts_view, TnyMimePart *mime_part)
161 {
162         ModestAttachmentsViewPrivate *priv = NULL;
163         GList *box_children = NULL, *node = NULL;
164         ModestAttachmentView *found_att_view = NULL;
165
166         g_return_if_fail (MODEST_IS_ATTACHMENTS_VIEW (atts_view));
167         g_return_if_fail (TNY_IS_MIME_PART (mime_part));
168
169         priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
170         box_children = gtk_container_get_children (GTK_CONTAINER (priv->box));
171
172         for (node = box_children; node != NULL; node = g_list_next (node)) {
173                 ModestAttachmentView *att_view = (ModestAttachmentView *) node->data;
174                 TnyMimePart *cur_mime_part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (att_view));
175
176                 if (mime_part == cur_mime_part)
177                         found_att_view = att_view;
178
179                 g_object_unref (cur_mime_part);
180
181                 if (found_att_view != NULL)
182                         break;
183         }
184
185         if (found_att_view) {
186                 gtk_widget_destroy (GTK_WIDGET (found_att_view));
187         }
188
189 }
190
191 void
192 modest_attachments_view_remove_attachment_by_id (ModestAttachmentsView *atts_view, const gchar *att_id)
193 {
194         ModestAttachmentsViewPrivate *priv = NULL;
195         GList *box_children = NULL, *node = NULL;
196
197         g_return_if_fail (MODEST_IS_ATTACHMENTS_VIEW (atts_view));
198         g_return_if_fail (att_id != NULL);
199
200         priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
201         box_children = gtk_container_get_children (GTK_CONTAINER (priv->box));
202
203         for (node = box_children; node != NULL; node = g_list_next (node)) {
204                 ModestAttachmentView *att_view = (ModestAttachmentView *) node->data;
205                 TnyMimePart *cur_mime_part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (att_view));
206                 const gchar *mime_part_id = NULL;
207
208                 mime_part_id = tny_mime_part_get_content_id (cur_mime_part);
209                 if ((mime_part_id != NULL) && (strcmp (mime_part_id, att_id) == 0))
210                         gtk_widget_destroy (GTK_WIDGET (att_view));
211
212                 g_object_unref (cur_mime_part);
213         }
214
215 }
216
217 static void
218 modest_attachments_view_instance_init (GTypeInstance *instance, gpointer g_class)
219 {
220         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (instance);
221
222         priv->msg = NULL;
223         priv->box = gtk_vbox_new (FALSE, 0);
224         priv->rubber_start = NULL;
225         priv->selected = NULL;
226
227         gtk_container_add (GTK_CONTAINER (instance), priv->box);
228         gtk_event_box_set_above_child (GTK_EVENT_BOX (instance), TRUE);
229
230         g_signal_connect (G_OBJECT (instance), "button-press-event", G_CALLBACK (button_press_event), instance);
231         g_signal_connect (G_OBJECT (instance), "button-release-event", G_CALLBACK (button_release_event), instance);
232         g_signal_connect (G_OBJECT (instance), "motion-notify-event", G_CALLBACK (motion_notify_event), instance);
233         g_signal_connect (G_OBJECT (instance), "key-press-event", G_CALLBACK (key_press_event), instance);
234
235         GTK_WIDGET_SET_FLAGS (instance, GTK_CAN_FOCUS);
236
237         return;
238 }
239
240 static void
241 modest_attachments_view_finalize (GObject *object)
242 {
243         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (object);
244
245         if (priv->msg) {
246                 g_object_unref (priv->msg);
247                 priv->msg = NULL;
248         }
249
250         (*parent_class->finalize) (object);
251
252         return;
253 }
254
255 static void 
256 modest_attachments_view_class_init (ModestAttachmentsViewClass *klass)
257 {
258         GObjectClass *object_class;
259         GtkWidgetClass *widget_class;
260
261         parent_class = g_type_class_peek_parent (klass);
262         object_class = (GObjectClass*) klass;
263         widget_class = GTK_WIDGET_CLASS (klass);
264
265         object_class->finalize = modest_attachments_view_finalize;
266
267         klass->activate = NULL;
268
269         g_type_class_add_private (object_class, sizeof (ModestAttachmentsViewPrivate));
270
271         signals[ACTIVATE_SIGNAL] =
272                 g_signal_new ("activate",
273                               G_TYPE_FROM_CLASS (object_class),
274                               G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
275                               G_STRUCT_OFFSET(ModestAttachmentsViewClass, activate),
276                               NULL, NULL,
277                               g_cclosure_marshal_VOID__OBJECT,
278                               G_TYPE_NONE, 1, G_TYPE_OBJECT);
279         
280         return;
281 }
282
283 GType 
284 modest_attachments_view_get_type (void)
285 {
286         static GType type = 0;
287
288         if (G_UNLIKELY(type == 0))
289         {
290                 static const GTypeInfo info = 
291                 {
292                   sizeof (ModestAttachmentsViewClass),
293                   NULL,   /* base_init */
294                   NULL,   /* base_finalize */
295                   (GClassInitFunc) modest_attachments_view_class_init,   /* class_init */
296                   NULL,   /* class_finalize */
297                   NULL,   /* class_data */
298                   sizeof (ModestAttachmentsView),
299                   0,      /* n_preallocs */
300                   modest_attachments_view_instance_init    /* instance_init */
301                 };
302
303                 type = g_type_register_static (GTK_TYPE_EVENT_BOX,
304                         "ModestAttachmentsView",
305                         &info, 0);
306
307         }
308
309         return type;
310 }
311
312 /* buttons signal events */
313 static gboolean
314 button_press_event (GtkWidget *widget, 
315                     GdkEventButton *event,
316                     ModestAttachmentsView *atts_view)
317 {
318         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
319         if (!GTK_WIDGET_HAS_FOCUS (widget))
320                 gtk_widget_grab_focus (widget);
321
322         if (event->button == 1 && event->type == GDK_BUTTON_PRESS) {
323                 GtkWidget *att_view = get_att_view_at_coords (MODEST_ATTACHMENTS_VIEW (widget), 
324                                                               event->x, event->y);
325
326                 if (att_view != NULL) {
327                         if (GTK_WIDGET_STATE (att_view) == GTK_STATE_SELECTED && (g_list_length (priv->selected) < 2)) {
328                                 TnyMimePart *mime_part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (att_view));
329                                 if (TNY_IS_MIME_PART (mime_part)) {
330                                         g_signal_emit (G_OBJECT (widget), signals[ACTIVATE_SIGNAL], 0, mime_part);
331                                         g_object_unref (mime_part);
332                                 }
333                         } else {
334                                 set_selected (MODEST_ATTACHMENTS_VIEW (widget), MODEST_ATTACHMENT_VIEW (att_view));
335                                 priv->rubber_start = att_view;
336                                 gtk_grab_add (widget);
337                         }
338                 }
339         }
340         return TRUE;
341
342 }
343
344 static gboolean
345 button_release_event (GtkWidget *widget,
346                       GdkEventButton *event,
347                       ModestAttachmentsView *atts_view)
348 {
349         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
350         if (widget == gtk_grab_get_current ()) {
351                 GtkWidget *att_view = get_att_view_at_coords (MODEST_ATTACHMENTS_VIEW (widget), 
352                                                               event->x, event->y);
353
354                 if (att_view != NULL) {
355                         unselect_all (MODEST_ATTACHMENTS_VIEW (widget));
356                         select_range (MODEST_ATTACHMENTS_VIEW (widget), 
357                                       MODEST_ATTACHMENT_VIEW (priv->rubber_start), 
358                                       MODEST_ATTACHMENT_VIEW (att_view));
359                 }
360                 priv->rubber_start = NULL;
361                 
362                 gtk_grab_remove (widget);
363         }
364         return TRUE;
365 }
366
367 static gboolean
368 motion_notify_event (GtkWidget *widget,
369                      GdkEventMotion *event,
370                      ModestAttachmentsView *atts_view)
371 {
372         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
373         if (gtk_grab_get_current () == widget) {
374                 GtkWidget *att_view = get_att_view_at_coords (MODEST_ATTACHMENTS_VIEW (widget), 
375                                                               event->x, event->y);
376
377                 if (att_view != NULL) {
378                         unselect_all (MODEST_ATTACHMENTS_VIEW (widget));
379                         select_range (MODEST_ATTACHMENTS_VIEW (widget), 
380                                       MODEST_ATTACHMENT_VIEW (priv->rubber_start), 
381                                       MODEST_ATTACHMENT_VIEW (att_view));
382                 }
383         }
384         return TRUE;
385 }
386
387 static gboolean
388 key_press_event (GtkWidget *widget,
389                  GdkEventKey *event,
390                  ModestAttachmentsView *atts_view)
391 {
392         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
393
394         /* If grabbed (for example rubber banding), escape leaves the rubberbanding mode */
395         if (gtk_grab_get_current () == widget) {
396                 if (event->keyval == GDK_Escape) {
397                         set_selected (MODEST_ATTACHMENTS_VIEW (widget),
398                                       MODEST_ATTACHMENT_VIEW (priv->rubber_start));
399                         priv->rubber_start = NULL;
400                         gtk_grab_remove (widget);
401                         return TRUE;
402                 } 
403                 return FALSE;
404         }
405
406         if (event->keyval == GDK_Up) {
407                 ModestAttachmentView *current_sel = NULL;
408                 gboolean move_out = FALSE;
409                 GList * box_children, *new_sel;
410
411                 box_children = gtk_container_get_children (GTK_CONTAINER (priv->box));
412                 if (box_children == NULL)
413                         move_out = TRUE;
414                 else if ((priv->selected != NULL)&&(priv->selected->data != box_children->data))
415                         current_sel = (ModestAttachmentView *) priv->selected->data;
416                 else
417                         move_out = TRUE;
418
419                 if (move_out) {
420                         GtkWidget *toplevel = NULL;
421                         /* move cursor outside */
422                         toplevel = gtk_widget_get_toplevel (widget);
423                         if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_IS_WINDOW (toplevel))
424                                 g_signal_emit_by_name (toplevel, "move-focus", GTK_DIR_UP);
425                         unselect_all (atts_view);
426                 } else {
427                         new_sel = g_list_find (box_children, (gpointer) current_sel);
428                         new_sel = g_list_previous (new_sel);
429                         set_selected (MODEST_ATTACHMENTS_VIEW (atts_view), MODEST_ATTACHMENT_VIEW (new_sel->data));
430                 }
431                 g_list_free (box_children);
432                 return TRUE;
433         }
434
435         if (event->keyval == GDK_Down) {
436                 ModestAttachmentView *current_sel = NULL;
437                 gboolean move_out = FALSE;
438                 GList * box_children, *new_sel, *last_child = NULL;
439
440                 box_children = gtk_container_get_children (GTK_CONTAINER (priv->box));
441
442                 if (box_children == NULL) {
443                         move_out = TRUE;
444                 } else {
445                         last_child = g_list_last (box_children);
446                         if (priv->selected != NULL) {
447                                 GList *last_selected = g_list_last (priv->selected);
448                                 if (last_selected->data != last_child->data)
449                                         current_sel = (ModestAttachmentView *) last_selected->data;
450                                 else
451                                         move_out = TRUE;
452                         } else {
453                                 move_out = TRUE;
454                         }
455                 }
456
457                 if (move_out) {
458                         GtkWidget *toplevel = NULL;
459                         /* move cursor outside */
460                         toplevel = gtk_widget_get_toplevel (widget);
461                         if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_IS_WINDOW (toplevel))
462                                 g_signal_emit_by_name (toplevel, "move-focus", GTK_DIR_DOWN);
463                         unselect_all (atts_view);
464                 } else {
465                         new_sel = g_list_find (box_children, (gpointer) current_sel);
466                         new_sel = g_list_next (new_sel);
467                         set_selected (MODEST_ATTACHMENTS_VIEW (atts_view), MODEST_ATTACHMENT_VIEW (new_sel->data));
468                 }
469                 g_list_free (box_children);
470                 return TRUE;
471         }
472
473         /* Activates selected item */
474         if (g_list_length (priv->selected) == 1) {
475                 ModestAttachmentView *att_view = (ModestAttachmentView *) priv->selected->data;
476                 if ((event->keyval == GDK_Return)) {
477                         TnyMimePart *mime_part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (att_view));
478                         if (TNY_IS_MIME_PART (mime_part)) {
479                                 g_signal_emit (G_OBJECT (widget), signals[ACTIVATE_SIGNAL], 0, mime_part);
480                                 g_object_unref (mime_part);
481                         }
482                         return TRUE;
483                 }
484         }
485
486         return FALSE;
487 }
488
489
490 static GtkWidget *
491 get_att_view_at_coords (ModestAttachmentsView *atts_view,
492                         gdouble x, gdouble y)
493 {
494         ModestAttachmentsViewPrivate *priv = NULL;
495         GList *att_view_list, *node;
496         GtkWidget *result = NULL;
497
498         priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
499         att_view_list = gtk_container_get_children (GTK_CONTAINER (priv->box));
500         
501         for (node = att_view_list; node != NULL; node = g_list_next (node)) {
502                 GtkWidget *att_view = (GtkWidget *) node->data;
503                 gint pos_x, pos_y, w, h, int_x, int_y;
504
505                 pos_x = att_view->allocation.x;
506                 pos_y = att_view->allocation.y;
507                 w = att_view->allocation.width;
508                 h = att_view->allocation.height;
509
510                 int_x = (gint) x;
511                 int_y = (gint) y;
512
513                 if ((x >= pos_x) && (x <= (pos_x + w)) && (y >= pos_y) && (y <= (pos_y + h))) {
514                         result = att_view;
515                         break;
516                 }
517         }
518
519         g_list_free (att_view_list);
520         return result;
521 }
522
523 static void
524 unselect_all (ModestAttachmentsView *atts_view)
525 {
526         ModestAttachmentsViewPrivate *priv = NULL;
527         GList *att_view_list, *node;
528
529         priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
530         att_view_list = gtk_container_get_children (GTK_CONTAINER (priv->box));
531         
532         for (node = att_view_list; node != NULL; node = g_list_next (node)) {
533                 GtkWidget *att_view = (GtkWidget *) node->data;
534
535                 if (GTK_WIDGET_STATE (att_view) == GTK_STATE_SELECTED)
536                         gtk_widget_set_state (att_view, GTK_STATE_NORMAL);
537         }
538
539         g_list_free (priv->selected);
540         priv->selected = NULL;
541
542         g_list_free (att_view_list);
543 }
544
545 static void 
546 set_selected (ModestAttachmentsView *atts_view, ModestAttachmentView *att_view)
547 {
548         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
549
550         unselect_all (atts_view);
551         gtk_widget_set_state (GTK_WIDGET (att_view), GTK_STATE_SELECTED);
552         g_list_free (priv->selected);
553         priv->selected = NULL;
554         priv->selected = g_list_append (priv->selected, att_view);
555         
556         own_clipboard (atts_view);
557 }
558
559 static void 
560 select_range (ModestAttachmentsView *atts_view, ModestAttachmentView *att1, ModestAttachmentView *att2)
561 {
562         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
563         GList *children = NULL;
564         GList *node = NULL;
565         gboolean selecting = FALSE;
566
567         unselect_all (atts_view);
568
569         if (att1 == att2) {
570                 set_selected (atts_view, att1);
571                 return;
572         }
573
574         children = gtk_container_get_children (GTK_CONTAINER (priv->box));
575         g_list_free (priv->selected);
576         priv->selected = NULL;
577
578
579         for (node = children; node != NULL; node = g_list_next (node)) {
580                 if ((node->data == att1) || (node->data == att2)) {
581                         gtk_widget_set_state (GTK_WIDGET (node->data), GTK_STATE_SELECTED);
582                         priv->selected = g_list_append (priv->selected, node->data);
583                         selecting = !selecting;
584                 } else if (selecting) {
585                         gtk_widget_set_state (GTK_WIDGET (node->data), GTK_STATE_SELECTED);
586                         priv->selected = g_list_append (priv->selected, node->data);
587                 }
588                         
589         }
590         g_list_free (children);
591         
592         own_clipboard (atts_view);
593 }
594
595 static void clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data,
596                            guint info, gpointer userdata)
597 {
598         ModestAttachmentsView *atts_view = (ModestAttachmentsView *) userdata;
599         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
600
601         if ((priv->selected != NULL)&&(priv->selected->next == NULL)) {
602                 TnyMimePart *mime_part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (priv->selected->data));
603                 if (info != MODEST_ATTACHMENTS_VIEW_CLIPBOARD_TYPE_INDEX) {
604                         if (TNY_IS_MSG (mime_part)) {
605                                 TnyHeader *header = tny_msg_get_header (TNY_MSG (mime_part));
606                                 if (TNY_IS_HEADER (header)) {
607                                         gtk_selection_data_set_text (selection_data, tny_header_get_subject (header), -1);
608                                         g_object_unref (header);
609                                 }
610                         } else {
611                                 gtk_selection_data_set_text (selection_data, tny_mime_part_get_filename (mime_part), -1);
612                         }
613                 } else {
614                         /* MODEST_ATTACHMENT requested. As the content id is not filled in all the case, we'll
615                          * use an internal index. This index is simply the index of the attachment in the vbox */
616                         GList *box_children = NULL;
617                         gint index;
618                         box_children = gtk_container_get_children (GTK_CONTAINER (priv->box));
619                         index = g_list_index (box_children, priv->selected);
620                         if (index >= 0) {
621                                 gchar *index_str = g_strdup_printf("%d", index);
622                                 gtk_selection_data_set_text (selection_data, index_str, -1);
623                                 g_free (index_str);
624                         }
625                 }
626         }
627 }
628
629 static void clipboard_clear (GtkClipboard *clipboard, gpointer userdata)
630 {
631         ModestAttachmentsView *atts_view = (ModestAttachmentsView *) userdata;
632
633         unselect_all (atts_view);
634 }
635
636 GList *
637 modest_attachments_view_get_selection (ModestAttachmentsView *atts_view)
638 {
639         ModestAttachmentsViewPrivate *priv;
640         GList *selection, *node;
641
642         g_return_val_if_fail (MODEST_IS_ATTACHMENTS_VIEW (atts_view), NULL);
643         priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
644
645         selection = NULL;
646         for (node = priv->selected; node != NULL; node = g_list_next (node)) {
647                 ModestAttachmentView *att_view = (ModestAttachmentView *) node->data;
648                 TnyMimePart *part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (att_view));
649                 selection = g_list_append (selection, part);
650         }
651         
652         return selection;
653 }
654
655 void
656 modest_attachments_view_select_all (ModestAttachmentsView *atts_view)
657 {
658         ModestAttachmentsViewPrivate *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (atts_view);
659         GList *children = NULL;
660         GList *node = NULL;
661
662         unselect_all (atts_view);
663
664         children = gtk_container_get_children (GTK_CONTAINER (priv->box));
665         g_list_free (priv->selected);
666         priv->selected = NULL;
667
668
669         for (node = children; node != NULL; node = g_list_next (node)) {
670                 gtk_widget_set_state (GTK_WIDGET (node->data), GTK_STATE_SELECTED);
671                 priv->selected = g_list_append (priv->selected, node->data);
672         }
673         g_list_free (children);
674
675         own_clipboard (atts_view);
676 }
677
678 static void
679 own_clipboard (ModestAttachmentsView *atts_view)
680 {
681         GtkTargetEntry targets[] = {
682                 {"TEXT", 0, 0},
683                 {"UTF8_STRING", 0, 1},
684                 {"COMPOUND_TEXT", 0, 2},
685                 {"STRING", 0, 3},
686                 {MODEST_ATTACHMENTS_VIEW_CLIPBOARD_TYPE, 0, MODEST_ATTACHMENTS_VIEW_CLIPBOARD_TYPE_INDEX},
687         };
688
689         gtk_clipboard_set_with_owner (gtk_widget_get_clipboard (GTK_WIDGET (atts_view), GDK_SELECTION_PRIMARY),
690                                       targets, G_N_ELEMENTS (targets),
691                                       clipboard_get, clipboard_clear, G_OBJECT(atts_view));
692                               
693 }