018a4c61eba299d3efa2d6c7e7dd7a1f3fbacf82
[modest] / src / gtk / modest-edit-msg-window.c
1 /* Copyright (c) 2006, 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 #include <glib/gi18n.h>
30 #include <string.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
33
34 #include "modest-account-mgr.h"
35 #include "modest-account-mgr-helpers.h"
36 #include "modest-edit-msg-window.h"
37 #include "modest-edit-msg-window-ui.h"
38 #include "modest-icon-names.h"
39 #include "modest-icon-factory.h"
40 #include "modest-mail-operation.h"
41 #include "modest-text-utils.h"
42 #include "modest-tny-platform-factory.h"
43 #include "modest-tny-msg-actions.h"
44 #include "modest-ui-actions.h"
45 #include "modest-widget-memory.h"
46 #include "modest-window-priv.h"
47
48 static void  modest_edit_msg_window_class_init   (ModestEditMsgWindowClass *klass);
49 static void  modest_edit_msg_window_init         (ModestEditMsgWindow *obj);
50 static void  modest_edit_msg_window_finalize     (GObject *obj);
51
52 /* list my signals */
53 enum {
54         /* MY_SIGNAL_1, */
55         /* MY_SIGNAL_2, */
56         LAST_SIGNAL
57 };
58
59 typedef struct _ModestEditMsgWindowPrivate ModestEditMsgWindowPrivate;
60 struct _ModestEditMsgWindowPrivate {
61
62         GtkWidget   *toolbar;
63         GtkWidget   *menubar;
64
65         GtkWidget   *msg_body;
66         GtkWidget   *from_field;
67         GtkWidget   *to_field;
68         GtkWidget   *cc_field;
69         GtkWidget   *bcc_field;
70         GtkWidget   *subject_field;
71 };
72
73 #define MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
74                                                     MODEST_TYPE_EDIT_MSG_WINDOW, \
75                                                     ModestEditMsgWindowPrivate))
76 /* globals */
77 static GtkWindowClass *parent_class = NULL;
78
79 /* uncomment the following if you have defined any signals */
80 /* static guint signals[LAST_SIGNAL] = {0}; */
81
82 GType
83 modest_edit_msg_window_get_type (void)
84 {
85         static GType my_type = 0;
86         if (!my_type) {
87                 static const GTypeInfo my_info = {
88                         sizeof(ModestEditMsgWindowClass),
89                         NULL,           /* base init */
90                         NULL,           /* base finalize */
91                         (GClassInitFunc) modest_edit_msg_window_class_init,
92                         NULL,           /* class finalize */
93                         NULL,           /* class data */
94                         sizeof(ModestEditMsgWindow),
95                         1,              /* n_preallocs */
96                         (GInstanceInitFunc) modest_edit_msg_window_init,
97                         NULL
98                 };
99                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
100                                                   "ModestEditMsgWindow",
101                                                   &my_info, 0);
102         }
103         return my_type;
104 }
105
106 static void
107 modest_edit_msg_window_class_init (ModestEditMsgWindowClass *klass)
108 {
109         GObjectClass *gobject_class;
110         gobject_class = (GObjectClass*) klass;
111
112         parent_class            = g_type_class_peek_parent (klass);
113         gobject_class->finalize = modest_edit_msg_window_finalize;
114
115         g_type_class_add_private (gobject_class, sizeof(ModestEditMsgWindowPrivate));
116 }
117
118 static void
119 modest_edit_msg_window_init (ModestEditMsgWindow *obj)
120 {
121         ModestEditMsgWindowPrivate *priv;
122         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
123
124         priv->toolbar       = NULL;
125         priv->menubar       = NULL;
126         priv->msg_body      = NULL;
127         priv->from_field    = NULL;
128         priv->to_field      = NULL;
129         priv->cc_field      = NULL;
130         priv->bcc_field     = NULL;
131         priv->subject_field = NULL;
132 }
133
134 static void
135 save_settings (ModestEditMsgWindow *self)
136 {
137         ModestWindowPrivate *parent_priv;
138         ModestConf *conf;
139
140         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
141         conf = modest_tny_platform_factory_get_conf_instance
142                 (MODEST_TNY_PLATFORM_FACTORY(parent_priv->plat_factory));
143
144         modest_widget_memory_save (conf, G_OBJECT(self), "modest-edit-msg-window");
145 }
146
147
148 static void
149 restore_settings (ModestEditMsgWindow *self)
150 {
151         ModestWindowPrivate *parent_priv;
152         ModestConf *conf;
153
154         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
155         conf = modest_tny_platform_factory_get_conf_instance
156                 (MODEST_TNY_PLATFORM_FACTORY(parent_priv->plat_factory));
157         modest_widget_memory_restore (conf, G_OBJECT(self), "modest-edit-msg-window");
158 }
159
160
161 static void
162 init_window (ModestEditMsgWindow *obj)
163 {
164         GtkWidget *to_button, *cc_button, *bcc_button; 
165         GtkWidget *header_table;
166         GtkWidget *main_vbox;
167         ModestEditMsgWindowPrivate *priv;
168         ModestWindowPrivate *parent_priv;
169
170         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
171         parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
172
173         to_button     = gtk_button_new_with_label (_("To..."));
174         cc_button     = gtk_button_new_with_label (_("Cc..."));
175         bcc_button    = gtk_button_new_with_label (_("Bcc..."));
176
177         priv->from_field    = modest_widget_factory_get_combo_box (parent_priv->widget_factory,
178                                                                    MODEST_COMBO_BOX_TYPE_TRANSPORTS);
179         priv->to_field      = gtk_entry_new_with_max_length (80);
180         priv->cc_field      = gtk_entry_new_with_max_length (80);
181         priv->bcc_field     = gtk_entry_new_with_max_length (80);
182         priv->subject_field = gtk_entry_new_with_max_length (80);
183         
184         header_table = gtk_table_new (5,2, FALSE);
185         
186         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("From:")),
187                           0,1,0,1, GTK_SHRINK, 0, 0, 0);
188         gtk_table_attach (GTK_TABLE(header_table), to_button,     0,1,1,2, GTK_SHRINK, 0, 0, 0);
189         gtk_table_attach (GTK_TABLE(header_table), cc_button,     0,1,2,3, GTK_SHRINK, 0, 0, 0);
190         gtk_table_attach (GTK_TABLE(header_table), bcc_button,    0,1,3,4, GTK_SHRINK, 0, 0, 0);
191         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("Subject:")),
192                           0,1,4,5, GTK_SHRINK, 0, 0, 0);
193
194         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->from_field,   1,2,0,1);
195         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->to_field,     1,2,1,2);
196         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->cc_field,     1,2,2,3);
197         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->bcc_field,    1,2,3,4);
198         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->subject_field,1,2,4,5);
199
200         priv->msg_body = gtk_text_view_new ();
201         
202         main_vbox = gtk_vbox_new  (FALSE, 6);
203
204         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 0);
205         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);
206         gtk_box_pack_start (GTK_BOX(main_vbox), header_table, FALSE, FALSE, 6);
207         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 6);
208
209         gtk_widget_show_all (GTK_WIDGET(main_vbox));
210         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
211 }
212         
213
214
215 static void
216 modest_edit_msg_window_finalize (GObject *obj)
217 {
218         G_OBJECT_CLASS(parent_class)->finalize (obj);
219 }
220
221
222
223 static gboolean
224 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestEditMsgWindow *self)
225 {
226         save_settings (self);
227         return FALSE;
228 }
229
230
231 ModestWindow *
232 modest_edit_msg_window_new (ModestWidgetFactory *factory,
233                             TnyAccountStore *account_store,
234                             ModestEditType type)
235 {
236         GObject *obj;
237         ModestEditMsgWindowPrivate *priv;
238         ModestWindowPrivate *parent_priv;
239         GtkActionGroup *action_group;
240         GError *error = NULL;
241
242         g_return_val_if_fail (factory, NULL);
243         g_return_val_if_fail (type < MODEST_EDIT_TYPE_NUM, NULL);
244         
245         obj = g_object_new(MODEST_TYPE_EDIT_MSG_WINDOW, NULL);
246         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
247         parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
248
249         parent_priv->widget_factory = g_object_ref (factory);
250         parent_priv->account_store  = g_object_ref (account_store);
251
252         /* ****** */
253         parent_priv->ui_manager = gtk_ui_manager_new();
254         action_group = gtk_action_group_new ("ModestEditMsgWindowActions");
255
256         /* Add common actions */
257         gtk_action_group_add_actions (action_group,
258                                       modest_edit_msg_action_entries,
259                                       G_N_ELEMENTS (modest_edit_msg_action_entries),
260                                       obj);
261         gtk_action_group_add_toggle_actions (action_group,
262                                              modest_edit_msg_toggle_action_entries,
263                                              G_N_ELEMENTS (modest_edit_msg_toggle_action_entries),
264                                              obj);
265         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
266         g_object_unref (action_group);
267
268         /* Load the UI definition */
269         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-edit-msg-window-ui.xml", &error);
270         if (error) {
271                 g_printerr ("modest: could not merge modest-edit-msg-window-ui.xml: %s\n", error->message);
272                 g_error_free (error);
273                 error = NULL;
274         }
275         /* ****** */
276
277         /* Add accelerators */
278         gtk_window_add_accel_group (GTK_WINDOW (obj), 
279                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
280
281
282         /* Toolbar / Menubar */
283         priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
284         priv->menubar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar");
285
286         gtk_toolbar_set_tooltips (GTK_TOOLBAR (priv->toolbar), TRUE);
287
288         /* Init window */
289         init_window (MODEST_EDIT_MSG_WINDOW(obj));
290
291         restore_settings (MODEST_EDIT_MSG_WINDOW(obj));
292         
293         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
294         gtk_window_set_icon  (GTK_WINDOW(obj),
295                               modest_icon_factory_get_icon (MODEST_APP_ICON));
296
297         g_signal_connect (G_OBJECT(obj), "delete-event",
298                           G_CALLBACK(on_delete_event), obj);
299
300         return (ModestWindow *) (obj);
301 }
302
303 void
304 modest_edit_msg_window_set_msg (ModestEditMsgWindow *self, TnyMsg *msg)
305 {
306         TnyHeader *header;
307         GtkTextBuffer *buf;
308         const gchar *to, *cc, *bcc, *subject;
309         ModestEditMsgWindowPrivate *priv;
310
311         g_return_if_fail (MODEST_IS_EDIT_MSG_WINDOW (self));
312         g_return_if_fail (TNY_IS_MSG (msg));
313
314         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE (self);
315
316         header  = tny_msg_get_header (msg);
317         to      = tny_header_get_to (header);
318         cc      = tny_header_get_cc (header);
319         bcc     = tny_header_get_bcc (header);
320         subject = tny_header_get_subject (header);
321
322         /* TODO: the comparison with Invalid is ugly, should be fixed
323            in tinymail -> TnyCamelHeader */
324         if (strcmp (to, "Invalid"))
325                 gtk_entry_set_text (GTK_ENTRY(priv->to_field), to);
326         if (strcmp (cc, "Invalid"))
327                 gtk_entry_set_text (GTK_ENTRY(priv->cc_field), cc);
328         if (strcmp (bcc, "Invalid"))
329                 gtk_entry_set_text (GTK_ENTRY(priv->bcc_field),  bcc);
330         if (subject)
331                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);
332         
333         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(priv->msg_body));
334         gtk_text_buffer_set_text (buf,
335                                   (const gchar *) modest_tny_msg_actions_find_body (msg, FALSE),
336                                   -1);
337
338         /* TODO: lower priority, select in the From: combo to the
339            value that comes from msg <- not sure, should it be
340            allowed? */
341         
342         /* TODO: set attachments */
343 }
344
345 MsgData * 
346 modest_edit_msg_window_get_msg_data (ModestEditMsgWindow *edit_window)
347 {
348         MsgData *data;
349         ModestAccountData *account_data;
350         GtkTextBuffer *buf;
351         GtkTextIter b, e;
352         ModestEditMsgWindowPrivate *priv;
353         
354         g_return_val_if_fail (MODEST_IS_EDIT_MSG_WINDOW (edit_window), NULL);
355
356         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE (edit_window);
357         
358         account_data = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
359         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body));
360         gtk_text_buffer_get_bounds (buf, &b, &e);
361
362         /* don't free these (except from) */
363         data = g_slice_new0 (MsgData);
364         data->from    =  g_strdup_printf ("%s <%s>", account_data->fullname, account_data->email) ;
365         data->to      =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->to_field));
366         data->cc      =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->cc_field));
367         data->bcc     =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->bcc_field));
368         data->subject =  (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->subject_field));
369         data->body    =  gtk_text_buffer_get_text (buf, &b, &e, FALSE);
370
371         return data;
372 }
373
374 void 
375 modest_edit_msg_window_free_msg_data (ModestEditMsgWindow *edit_window,
376                                       MsgData *data)
377 {
378         g_return_if_fail (MODEST_IS_EDIT_MSG_WINDOW (edit_window));
379
380         g_free (data->from);
381         g_free (data->body);
382         g_slice_free (MsgData, data);
383 }