* src/widgets/modest-mail-header-view.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-attachments-view.h>
43
44 static GObjectClass *parent_class = NULL;
45
46 /* signals */
47 enum {
48         ACTIVATE_SIGNAL,
49         LAST_SIGNAL
50 };
51
52 typedef struct _ModestAttachmentsViewPriv ModestAttachmentsViewPriv;
53
54 struct _ModestAttachmentsViewPriv
55 {
56         TnyMsg *msg;
57 };
58
59 #define MODEST_ATTACHMENTS_VIEW_GET_PRIVATE(o)  \
60         (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_ATTACHMENTS_VIEW, ModestAttachmentsViewPriv))
61
62 static guint signals[LAST_SIGNAL] = {0};
63
64
65 /**
66  * modest_attachments_view_new:
67  * @msg: a #TnyMsg
68  *
69  * Constructor for attachments view widget.
70  *
71  * Return value: a new #ModestAttachmentsView instance implemented for Gtk+
72  **/
73 GtkWidget*
74 modest_attachments_view_new (TnyMsg *msg)
75 {
76         ModestAttachmentsView *self = g_object_new (MODEST_TYPE_ATTACHMENTS_VIEW, NULL);
77
78         modest_attachments_view_set_message (self, msg);
79
80         return GTK_WIDGET (self);
81 }
82
83 void
84 modest_attachments_view_set_message (ModestAttachmentsView *attachments_view, TnyMsg *msg)
85 {
86         ModestAttachmentsViewPriv *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (attachments_view);
87         TnyList *parts;
88         TnyIterator *iter;
89         gint index = 0;
90         GtkTextBuffer *buffer = NULL;
91         gboolean has_first = FALSE;
92         GtkTextIter text_iter;
93         gint icon_height;
94
95         if (priv->msg) {
96                 g_object_unref (priv->msg);
97         }
98         priv->msg = msg;
99
100         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (attachments_view));
101         gtk_text_buffer_set_text (buffer, "", -1);
102         gtk_text_buffer_get_end_iter (buffer, &text_iter);
103
104         if (priv->msg == NULL) {
105                 gtk_widget_hide (GTK_WIDGET (attachments_view));
106                 return;
107         }
108
109         parts = TNY_LIST (tny_simple_list_new ());
110         tny_mime_part_get_parts (TNY_MIME_PART (priv->msg), parts);
111         iter = tny_list_create_iterator (parts);
112
113         gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, NULL, &icon_height);
114
115         while (!tny_iterator_is_done (iter)) {
116                 TnyMimePart *part;
117
118                 ++index;
119                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
120                 if (tny_mime_part_is_attachment (part)) {
121                         const gchar *filename = tny_mime_part_get_filename (part);
122                         gchar *file_icon_name = 
123                                 modest_platform_get_file_icon_name (filename, tny_mime_part_get_content_type(part) , NULL);
124                         GdkPixbuf *pixbuf = NULL;
125                         GtkTextTag *tag = NULL;
126
127                         if (has_first) {
128                                 gtk_text_buffer_insert (buffer, &text_iter, ", ", -1);
129                                 gtk_text_buffer_get_end_iter (buffer, &text_iter);
130                         }
131                         
132                         tag = gtk_text_buffer_create_tag (buffer, NULL,
133                                                           "underline", PANGO_UNDERLINE_SINGLE,
134                                                           "foreground", "blue",
135                                                           NULL);
136                         
137                         g_object_set_data (G_OBJECT (tag), "attachment-index", GINT_TO_POINTER (index));
138                         g_object_set_data (G_OBJECT (tag), "attachment-set", GINT_TO_POINTER (TRUE));
139                         
140                         if (file_icon_name) {
141                                 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), file_icon_name, 
142                                                                    icon_height, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
143                                 if (pixbuf) {
144                                         gtk_text_buffer_insert_pixbuf (buffer, &text_iter, pixbuf);
145                                 }
146                         }
147                         gtk_text_buffer_insert_with_tags (buffer, &text_iter, filename, -1, tag, NULL);
148                         gtk_text_buffer_get_end_iter (buffer, &text_iter);
149                         if (file_icon_name)
150                                 g_free (file_icon_name);
151                         has_first = TRUE;
152                 }
153                 g_object_unref (part);
154                 tny_iterator_next (iter);
155         }
156
157         if (has_first)
158                 gtk_widget_show (GTK_WIDGET (attachments_view));
159         else
160                 gtk_widget_hide (GTK_WIDGET (attachments_view));
161
162 }
163
164 static gboolean
165 button_release_event (GtkWidget *widget,
166                       GdkEventButton *event,
167                       gpointer user_data)
168 {
169         gint buffer_x, buffer_y;
170         GtkTextIter iter;
171         GSList *tags = NULL;
172         GSList *node = NULL;
173         
174         if ((event->type != GDK_BUTTON_RELEASE) 
175             || (event->button != 1))
176                 return FALSE;
177         
178         gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_WIDGET,
179                                                event->x, event->y, &buffer_x, &buffer_y);
180         gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (widget), &iter, buffer_x, buffer_y);
181
182         tags = gtk_text_iter_get_tags (&iter);
183
184         for (node = tags; node != NULL; node = g_slist_next (node)) {
185                 GtkTextTag *tag = node->data;
186                 gboolean is_attachment = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "attachment-set"));
187
188                 if (is_attachment) {
189                         gint attachment_index = 0;
190
191                         attachment_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "attachment-index"));
192                         g_signal_emit (G_OBJECT (widget), signals[ACTIVATE_SIGNAL], NULL, attachment_index);
193                         break;
194                 }
195                 
196         }
197         return FALSE;
198 }
199
200 static void
201 modest_attachments_view_instance_init (GTypeInstance *instance, gpointer g_class)
202 {
203         ModestAttachmentsViewPriv *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (instance);
204         GtkTextBuffer *buffer = NULL;
205
206         gtk_text_view_set_editable (GTK_TEXT_VIEW (instance), FALSE);
207         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (instance), GTK_WRAP_WORD_CHAR);
208         gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (instance), 0);
209         gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (instance), 0);
210         gtk_text_view_set_justification (GTK_TEXT_VIEW (instance), GTK_JUSTIFY_LEFT);
211         gtk_text_view_set_left_margin (GTK_TEXT_VIEW (instance), 0);
212         gtk_text_view_set_right_margin (GTK_TEXT_VIEW (instance), 0);
213         gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (instance), FALSE);
214
215         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (instance));
216
217         g_signal_connect (G_OBJECT (instance), "button-release-event", G_CALLBACK (button_release_event), NULL);
218
219         priv->msg = NULL;
220
221         return;
222 }
223
224 static void
225 modest_attachments_view_finalize (GObject *object)
226 {
227         ModestAttachmentsViewPriv *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (object);
228
229         if (priv->msg) {
230                 g_object_unref (priv->msg);
231                 priv->msg = NULL;
232         }
233
234         (*parent_class->finalize) (object);
235
236         return;
237 }
238
239 static void 
240 modest_attachments_view_class_init (ModestAttachmentsViewClass *klass)
241 {
242         GObjectClass *object_class;
243         GtkWidgetClass *widget_class;
244
245         parent_class = g_type_class_peek_parent (klass);
246         object_class = (GObjectClass*) klass;
247         widget_class = GTK_WIDGET_CLASS (klass);
248
249         object_class->finalize = modest_attachments_view_finalize;
250
251         klass->activate = NULL;
252
253         g_type_class_add_private (object_class, sizeof (ModestAttachmentsViewPriv));
254
255         signals[ACTIVATE_SIGNAL] =
256                 g_signal_new ("activate",
257                               G_TYPE_FROM_CLASS (object_class),
258                               G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
259                               G_STRUCT_OFFSET(ModestAttachmentsViewClass, activate),
260                               NULL, NULL,
261                               g_cclosure_marshal_VOID__INT,
262                               G_TYPE_NONE, 1, G_TYPE_INT);
263         
264         return;
265 }
266
267 GType 
268 modest_attachments_view_get_type (void)
269 {
270         static GType type = 0;
271
272         if (G_UNLIKELY(type == 0))
273         {
274                 static const GTypeInfo info = 
275                 {
276                   sizeof (ModestAttachmentsViewClass),
277                   NULL,   /* base_init */
278                   NULL,   /* base_finalize */
279                   (GClassInitFunc) modest_attachments_view_class_init,   /* class_init */
280                   NULL,   /* class_finalize */
281                   NULL,   /* class_data */
282                   sizeof (ModestAttachmentsView),
283                   0,      /* n_preallocs */
284                   modest_attachments_view_instance_init    /* instance_init */
285                 };
286
287                 type = g_type_register_static (GTK_TYPE_TEXT_VIEW,
288                         "ModestAttachmentsView",
289                         &info, 0);
290
291         }
292
293         return type;
294 }