8be4f73253126f6ad47682f901202f21f3d298a6
[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         if (msg)
98                 g_object_ref (G_OBJECT(msg));
99         
100         priv->msg = msg;
101         
102         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (attachments_view));
103         gtk_text_buffer_set_text (buffer, "", -1);
104         gtk_text_buffer_get_end_iter (buffer, &text_iter);
105
106         if (priv->msg == NULL) {
107                 gtk_widget_hide (GTK_WIDGET (attachments_view));
108                 return;
109         }
110
111         parts = TNY_LIST (tny_simple_list_new ());
112         tny_mime_part_get_parts (TNY_MIME_PART (priv->msg), parts);
113         iter = tny_list_create_iterator (parts);
114
115         gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, NULL, &icon_height);
116
117         while (!tny_iterator_is_done (iter)) {
118                 TnyMimePart *part;
119
120                 ++index;
121                 part = TNY_MIME_PART (tny_iterator_get_current (iter));
122                 if (tny_mime_part_is_attachment (part)) {
123                         const gchar *filename = tny_mime_part_get_filename (part);
124                         gchar *file_icon_name = 
125                                 modest_platform_get_file_icon_name (filename, tny_mime_part_get_content_type(part) , NULL);
126                         GdkPixbuf *pixbuf = NULL;
127                         GtkTextTag *tag = NULL;
128
129                         if (has_first) {
130                                 gtk_text_buffer_insert (buffer, &text_iter, ", ", -1);
131                                 gtk_text_buffer_get_end_iter (buffer, &text_iter);
132                         }
133                         
134                         tag = gtk_text_buffer_create_tag (buffer, NULL,
135                                                           "underline", PANGO_UNDERLINE_SINGLE,
136                                                           "foreground", "blue",
137                                                           NULL);
138                         
139                         g_object_set_data (G_OBJECT (tag), "attachment-index", GINT_TO_POINTER (index));
140                         g_object_set_data (G_OBJECT (tag), "attachment-set", GINT_TO_POINTER (TRUE));
141                         
142                         if (file_icon_name) {
143                                 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), file_icon_name, 
144                                                                    icon_height, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
145                                 if (pixbuf) {
146                                         GtkTextTag *pixbuf_tag;
147                                         GtkTextIter iter2;
148                                         pixbuf_tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
149                                         g_object_set_data (G_OBJECT (pixbuf_tag), "attachment-index", GINT_TO_POINTER (index));
150                                         g_object_set_data (G_OBJECT (pixbuf_tag), "attachment-set", GINT_TO_POINTER (TRUE));
151                                         gtk_text_buffer_insert_pixbuf (buffer, &text_iter, pixbuf);
152                                         iter2 = text_iter;
153                                         gtk_text_iter_backward_char (&iter2);
154                                         gtk_text_buffer_apply_tag (buffer, pixbuf_tag, &iter2, &text_iter);
155                                         gtk_text_buffer_get_end_iter (buffer, &text_iter);
156                                 }
157                         }
158                         gtk_text_buffer_insert_with_tags (buffer, &text_iter, filename, -1, tag, NULL);
159                         gtk_text_buffer_get_end_iter (buffer, &text_iter);
160                         if (file_icon_name)
161                                 g_free (file_icon_name);
162                         has_first = TRUE;
163                 }
164                 g_object_unref (part);
165                 tny_iterator_next (iter);
166         }
167
168         if (has_first)
169                 gtk_widget_show (GTK_WIDGET (attachments_view));
170         else
171                 gtk_widget_hide (GTK_WIDGET (attachments_view));
172
173 }
174
175 static gboolean
176 button_release_event (GtkWidget *widget,
177                       GdkEventButton *event,
178                       gpointer user_data)
179 {
180         gint buffer_x, buffer_y;
181         GtkTextIter iter;
182         GSList *tags = NULL;
183         GSList *node = NULL;
184         
185         if ((event->type != GDK_BUTTON_RELEASE) 
186             || (event->button != 1))
187                 return FALSE;
188         
189         gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_WIDGET,
190                                                event->x, event->y, &buffer_x, &buffer_y);
191         gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (widget), &iter, buffer_x, buffer_y);
192
193         tags = gtk_text_iter_get_tags (&iter);
194
195         for (node = tags; node != NULL; node = g_slist_next (node)) {
196                 GtkTextTag *tag = node->data;
197                 gboolean is_attachment = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "attachment-set"));
198
199                 if (is_attachment) {
200                         gint attachment_index = 0;
201
202                         attachment_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "attachment-index"));
203                         g_signal_emit (G_OBJECT (widget), signals[ACTIVATE_SIGNAL], 0,
204                                        attachment_index);
205                         break;
206                 }
207                 
208         }
209         return FALSE;
210 }
211
212 static void
213 modest_attachments_view_instance_init (GTypeInstance *instance, gpointer g_class)
214 {
215         ModestAttachmentsViewPriv *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (instance);
216         GtkTextBuffer *buffer = NULL;
217
218         gtk_text_view_set_editable (GTK_TEXT_VIEW (instance), FALSE);
219         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (instance), GTK_WRAP_WORD_CHAR);
220         gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (instance), 0);
221         gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (instance), 0);
222         gtk_text_view_set_justification (GTK_TEXT_VIEW (instance), GTK_JUSTIFY_LEFT);
223         gtk_text_view_set_left_margin (GTK_TEXT_VIEW (instance), 0);
224         gtk_text_view_set_right_margin (GTK_TEXT_VIEW (instance), 0);
225         gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (instance), FALSE);
226
227         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (instance));
228
229         g_signal_connect (G_OBJECT (instance), "button-release-event", G_CALLBACK (button_release_event), NULL);
230
231         priv->msg = NULL;
232
233         return;
234 }
235
236 static void
237 modest_attachments_view_finalize (GObject *object)
238 {
239         ModestAttachmentsViewPriv *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (object);
240
241         if (priv->msg) {
242                 g_object_unref (priv->msg);
243                 priv->msg = NULL;
244         }
245
246         (*parent_class->finalize) (object);
247
248         return;
249 }
250
251 static void 
252 modest_attachments_view_class_init (ModestAttachmentsViewClass *klass)
253 {
254         GObjectClass *object_class;
255         GtkWidgetClass *widget_class;
256
257         parent_class = g_type_class_peek_parent (klass);
258         object_class = (GObjectClass*) klass;
259         widget_class = GTK_WIDGET_CLASS (klass);
260
261         object_class->finalize = modest_attachments_view_finalize;
262
263         klass->activate = NULL;
264
265         g_type_class_add_private (object_class, sizeof (ModestAttachmentsViewPriv));
266
267         signals[ACTIVATE_SIGNAL] =
268                 g_signal_new ("activate",
269                               G_TYPE_FROM_CLASS (object_class),
270                               G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
271                               G_STRUCT_OFFSET(ModestAttachmentsViewClass, activate),
272                               NULL, NULL,
273                               g_cclosure_marshal_VOID__INT,
274                               G_TYPE_NONE, 1, G_TYPE_INT);
275         
276         return;
277 }
278
279 GType 
280 modest_attachments_view_get_type (void)
281 {
282         static GType type = 0;
283
284         if (G_UNLIKELY(type == 0))
285         {
286                 static const GTypeInfo info = 
287                 {
288                   sizeof (ModestAttachmentsViewClass),
289                   NULL,   /* base_init */
290                   NULL,   /* base_finalize */
291                   (GClassInitFunc) modest_attachments_view_class_init,   /* class_init */
292                   NULL,   /* class_finalize */
293                   NULL,   /* class_data */
294                   sizeof (ModestAttachmentsView),
295                   0,      /* n_preallocs */
296                   modest_attachments_view_instance_init    /* instance_init */
297                 };
298
299                 type = g_type_register_static (GTK_TYPE_TEXT_VIEW,
300                         "ModestAttachmentsView",
301                         &info, 0);
302
303         }
304
305         return type;
306 }