* Added a new account key called type for server accounts
[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 <tny-account-store.h>
31 #include "modest-edit-msg-window.h"
32 #include "modest-widget-memory.h"
33 #include "modest-mail-operation.h"
34 #include "modest-tny-platform-factory.h"
35 #include "modest-tny-msg-actions.h"
36 #include <tny-simple-list.h>
37
38 static void  modest_edit_msg_window_class_init   (ModestEditMsgWindowClass *klass);
39 static void  modest_edit_msg_window_init         (ModestEditMsgWindow *obj);
40 static void  modest_edit_msg_window_finalize     (GObject *obj);
41
42 /* list my signals */
43 enum {
44         /* MY_SIGNAL_1, */
45         /* MY_SIGNAL_2, */
46         LAST_SIGNAL
47 };
48
49 typedef struct _ModestEditMsgWindowPrivate ModestEditMsgWindowPrivate;
50 struct _ModestEditMsgWindowPrivate {
51
52         ModestWidgetFactory *factory;
53         TnyPlatformFactory *fact;
54         
55         GtkWidget      *toolbar, *menubar;
56         GtkWidget      *msg_body;
57         GtkWidget      *from_field, *to_field, *cc_field, *bcc_field,
58                        *subject_field;
59 };
60 #define MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
61                                                     MODEST_TYPE_EDIT_MSG_WINDOW, \
62                                                     ModestEditMsgWindowPrivate))
63 /* globals */
64 static GtkWindowClass *parent_class = NULL;
65
66 /* uncomment the following if you have defined any signals */
67 /* static guint signals[LAST_SIGNAL] = {0}; */
68
69 GType
70 modest_edit_msg_window_get_type (void)
71 {
72         static GType my_type = 0;
73         if (!my_type) {
74                 static const GTypeInfo my_info = {
75                         sizeof(ModestEditMsgWindowClass),
76                         NULL,           /* base init */
77                         NULL,           /* base finalize */
78                         (GClassInitFunc) modest_edit_msg_window_class_init,
79                         NULL,           /* class finalize */
80                         NULL,           /* class data */
81                         sizeof(ModestEditMsgWindow),
82                         1,              /* n_preallocs */
83                         (GInstanceInitFunc) modest_edit_msg_window_init,
84                         NULL
85                 };
86                 my_type = g_type_register_static (GTK_TYPE_WINDOW,
87                                                   "ModestEditMsgWindow",
88                                                   &my_info, 0);
89         }
90         return my_type;
91 }
92
93 static void
94 modest_edit_msg_window_class_init (ModestEditMsgWindowClass *klass)
95 {
96         GObjectClass *gobject_class;
97         gobject_class = (GObjectClass*) klass;
98
99         parent_class            = g_type_class_peek_parent (klass);
100         gobject_class->finalize = modest_edit_msg_window_finalize;
101
102         g_type_class_add_private (gobject_class, sizeof(ModestEditMsgWindowPrivate));
103
104         /* signal definitions go here, e.g.: */
105 /*      signals[MY_SIGNAL_1] = */
106 /*              g_signal_new ("my_signal_1",....); */
107 /*      signals[MY_SIGNAL_2] = */
108 /*              g_signal_new ("my_signal_2",....); */
109 /*      etc. */
110 }
111
112 static void
113 modest_edit_msg_window_init (ModestEditMsgWindow *obj)
114 {
115         ModestEditMsgWindowPrivate *priv;
116         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
117
118         priv->fact = modest_tny_platform_factory_get_instance ();
119         priv->factory = NULL;
120         priv->toolbar = NULL;
121         priv->menubar = NULL;
122 }
123
124
125
126 static void
127 save_settings (ModestEditMsgWindow *self)
128 {
129         ModestEditMsgWindowPrivate *priv;
130         ModestConf *conf;
131
132         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
133         conf = modest_tny_platform_factory_get_modest_conf_instance (priv->fact);
134
135         modest_widget_memory_save (conf, G_OBJECT(self), "modest-edit-msg-window");
136 }
137
138
139 static void
140 restore_settings (ModestEditMsgWindow *self)
141 {
142         ModestEditMsgWindowPrivate *priv;
143         ModestConf *conf;
144
145         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
146         conf = modest_tny_platform_factory_get_modest_conf_instance (priv->fact);
147
148         modest_widget_memory_restore (conf, G_OBJECT(self), "modest-edit-msg-window");
149 }
150
151         
152
153 static void
154 on_menu_quit (ModestEditMsgWindow *self, guint action, GtkWidget *widget)
155 {
156         save_settings (self);
157         gtk_widget_destroy (GTK_WIDGET(self));
158 }
159
160
161
162
163
164 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
165 static GtkItemFactoryEntry menu_items[] = {
166         { "/_File",             NULL,                   NULL,           0, "<Branch>" ,NULL},
167         { "/File/_New",         "<control>N",           NULL,           0, "<StockItem>", GTK_STOCK_NEW },
168         { "/File/_Open",        "<control>O",           NULL,           0, "<StockItem>", GTK_STOCK_OPEN },
169         { "/File/_Save",        "<control>S",           NULL,           0, "<StockItem>", GTK_STOCK_SAVE },
170         { "/File/Save _As",     NULL,                   NULL,           0, "<Item>", NULL} ,
171         { "/File/Save Draft",   "<control><shift>S",    NULL,           0, "<Item>",NULL },
172
173
174         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" ,NULL },
175         { "/File/_Quit",        "<CTRL>Q",              on_menu_quit,   0, "<StockItem>", GTK_STOCK_QUIT },
176
177         { "/_Edit",             NULL,                   NULL,           0, "<Branch>" ,NULL },
178         { "/Edit/_Undo",        "<CTRL>Z",              NULL,           0, "<StockItem>", GTK_STOCK_UNDO },
179         { "/Edit/_Redo",        "<shift><CTRL>Z",       NULL,           0, "<StockItem>", GTK_STOCK_REDO },
180         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>",NULL },
181         { "/Edit/Cut",          "<control>X",           NULL,           0, "<StockItem>", GTK_STOCK_CUT  },
182         { "/Edit/Copy",         "<CTRL>C",              NULL,           0, "<StockItem>", GTK_STOCK_COPY },
183         { "/Edit/Paste",        NULL,                   NULL,           0, "<StockItem>", GTK_STOCK_PASTE},
184         { "/Edit/sep1",         NULL,                   NULL,           0, "<Separator>",NULL },
185         { "/Edit/Delete",       "<CTRL>Q",              NULL,           0, "<Item>" ,NULL },
186         { "/Edit/Select all",   "<CTRL>A",              NULL,           0, "<Item>" ,NULL },
187         { "/Edit/Deselect all",  "<Shift><CTRL>A",      NULL,           0, "<Item>",NULL },
188
189         { "/_View",             NULL,           NULL,                   0, "<Branch>",NULL },
190         { "/View/To-field",          NULL,              NULL,           0, "<CheckItem>",NULL },
191         
192         { "/View/Cc-field:",          NULL,             NULL,           0, "<CheckItem>",NULL },
193         { "/View/Bcc-field:",          NULL,            NULL,           0, "<CheckItem>",NULL },
194         
195         
196         { "/_Insert",             NULL,         NULL,           0, "<Branch>",NULL },
197 /*      { "/Actions/_Reply",    NULL,                   NULL,           0, "<Item>" }, */
198 /*      { "/Actions/_Forward",  NULL,                   NULL,           0, "<Item>" }, */
199 /*      { "/Actions/_Bounce",   NULL,                   NULL,           0, "<Item>" },   */
200         
201         { "/_Format",            NULL,                  NULL,           0, "<Branch>",NULL }
202 /*      { "/Options/_Accounts",  NULL,                  on_menu_accounts,0, "<Item>" }, */
203 /*      { "/Options/_Contacts",  NULL,                  NULL,           0, "<Item>" }, */
204
205
206 /*      { "/_Help",         NULL,                       NULL,           0, "<Branch>" }, */
207 /*      { "/_Help/About",   NULL,                       on_menu_about,  0, "<StockItem>", GTK_STOCK_ABOUT}, */
208 };
209
210 static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
211
212
213 static GtkWidget *
214 menubar_new (ModestEditMsgWindow *self)
215 {
216         GtkItemFactory *item_factory;
217         GtkAccelGroup *accel_group;
218         
219         /* Make an accelerator group (shortcut keys) */
220         accel_group = gtk_accel_group_new ();
221         
222         /* Make an ItemFactory (that makes a menubar) */
223         item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
224                                              accel_group);
225         
226         /* This function generates the menu items. Pass the item factory,
227            the number of items in the array, the array itself, and any
228            callback data for the the menu items. */
229         gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, self);
230         
231         ///* Attach the new accelerator group to the window. */
232         gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
233         
234         /* Finally, return the actual menu bar created by the item factory. */
235         return gtk_item_factory_get_widget (item_factory, "<main>");
236 }
237
238
239 static void
240 send_mail (ModestEditMsgWindow *self)
241 {
242         const gchar *to, *cc, *bcc, *subject;
243         gchar *body, *from;
244         ModestEditMsgWindowPrivate *priv;
245         TnyTransportAccount *transport_account;
246         ModestMailOperation *mail_operation;
247         ModestAccountData *data;
248         
249         GtkTextBuffer *buf;
250         GtkTextIter b, e;
251         
252         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
253         data = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
254
255         /* don't free these (except from) */
256         from    =  g_strdup_printf ("%s <%s>", data->full_name, data->email) ;
257         to      =  gtk_entry_get_text (GTK_ENTRY(priv->to_field));
258         cc      =  gtk_entry_get_text (GTK_ENTRY(priv->cc_field));
259         bcc     =  gtk_entry_get_text (GTK_ENTRY(priv->bcc_field));
260         subject =  gtk_entry_get_text (GTK_ENTRY(priv->subject_field));
261         
262         /* don't unref */
263         buf   =  gtk_text_view_get_buffer (GTK_TEXT_VIEW(priv->msg_body));
264         
265         gtk_text_buffer_get_bounds (buf, &b, &e);
266         body  = gtk_text_buffer_get_text (buf, &b, &e,
267                                           FALSE); /* free this one */
268
269         /* FIXME: Code added just for testing. The final version will
270            use the send queue provided by tinymail and some
271            classifier */
272         {
273                 TnyList *accounts;
274                 TnyIterator *iter;
275                 TnyAccountStore *account_store;
276
277                 accounts = TNY_LIST(tny_simple_list_new ());
278                 account_store = tny_platform_factory_new_account_store (priv->fact);
279                 tny_account_store_get_accounts (account_store, accounts,
280                                                 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
281
282                 iter = tny_list_create_iterator(accounts);
283                 tny_iterator_first (iter);
284                 if (tny_iterator_is_done (iter)) {
285                         /* FIXME: Add error handling through mail operation */
286                         g_printerr("modest: no transport accounts defined\n");
287                         g_free (body);
288                         return;
289                 }
290                 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
291                 g_object_ref (transport_account);
292
293                 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
294                 g_object_unref (G_OBJECT (accounts));
295                 g_object_unref (G_OBJECT (iter));
296         }
297
298         mail_operation = modest_mail_operation_new ();
299
300         modest_mail_operation_send_new_mail (mail_operation,
301                                              transport_account,
302                                              from, to, cc, bcc,
303                                              subject, body, NULL);
304         /* Clean up */
305         g_object_unref (G_OBJECT (mail_operation));
306         g_object_unref (G_OBJECT (transport_account));
307         g_free (from);
308         g_free (body);
309 }
310
311
312 static void
313 on_toolbar_button_clicked (ModestToolbar *toolbar, ModestToolbarButton button_id,
314                            ModestEditMsgWindow *self)
315 {
316         switch (button_id) {
317         case MODEST_TOOLBAR_BUTTON_MAIL_SEND:
318                 send_mail (self);
319                 save_settings (self);
320                 gtk_widget_destroy (GTK_WIDGET(self));
321                 break;
322                 
323         case MODEST_TOOLBAR_BUTTON_REPLY:
324         case MODEST_TOOLBAR_BUTTON_REPLY_ALL:
325         case MODEST_TOOLBAR_BUTTON_FORWARD:
326         case MODEST_TOOLBAR_BUTTON_SEND_RECEIVE:
327         case MODEST_TOOLBAR_BUTTON_NEXT:
328         case MODEST_TOOLBAR_BUTTON_PREV:
329         case MODEST_TOOLBAR_BUTTON_DELETE:
330
331         default:
332                 g_printerr ("modest: key %d pressed\n", button_id);
333         }
334 }
335
336
337
338
339 static ModestToolbar*
340 toolbar_new (ModestEditMsgWindow *self)
341 {
342         int i;
343         ModestToolbar *toolbar;
344         GSList *buttons = NULL;
345         ModestEditMsgWindowPrivate *priv;
346
347         ModestToolbarButton button_ids[] = {
348                 MODEST_TOOLBAR_BUTTON_MAIL_SEND
349         };              
350         
351         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
352
353         for (i = 0 ; i != sizeof(button_ids) / sizeof(ModestToolbarButton); ++i)
354                 buttons = g_slist_append (buttons, GINT_TO_POINTER(button_ids[i]));
355         
356         toolbar = modest_widget_factory_get_edit_toolbar (priv->factory, buttons);
357         g_slist_free (buttons);
358
359         g_signal_connect (G_OBJECT(toolbar), "button_clicked",
360                           G_CALLBACK(on_toolbar_button_clicked), self);
361         
362         return toolbar;
363 }
364
365
366 static void
367 init_window (ModestEditMsgWindow *obj)
368 {
369         GtkWidget *to_button, *cc_button, *bcc_button; 
370         GtkWidget *header_table;
371         GtkWidget *main_vbox;
372         
373         ModestEditMsgWindowPrivate *priv;
374         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
375
376         to_button     = gtk_button_new_with_label (_("To..."));
377         cc_button     = gtk_button_new_with_label (_("Cc..."));
378         bcc_button    = gtk_button_new_with_label (_("Bcc..."));
379
380         priv->from_field    = modest_widget_factory_get_combo_box (priv->factory,
381                                                                    MODEST_COMBO_BOX_TYPE_TRANSPORTS);
382         priv->to_field      = gtk_entry_new_with_max_length (80);
383         priv->cc_field      = gtk_entry_new_with_max_length (80);
384         priv->bcc_field     = gtk_entry_new_with_max_length (80);
385         priv->subject_field = gtk_entry_new_with_max_length (80);
386         
387         header_table = gtk_table_new (5,2, FALSE);
388         
389         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("From:")),
390                           0,1,0,1, GTK_SHRINK, 0, 0, 0);
391         gtk_table_attach (GTK_TABLE(header_table), to_button,     0,1,1,2, GTK_SHRINK, 0, 0, 0);
392         gtk_table_attach (GTK_TABLE(header_table), cc_button,     0,1,2,3, GTK_SHRINK, 0, 0, 0);
393         gtk_table_attach (GTK_TABLE(header_table), bcc_button,    0,1,3,4, GTK_SHRINK, 0, 0, 0);
394         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("Subject:")),
395                           0,1,4,5, GTK_SHRINK, 0, 0, 0);
396
397         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->from_field,   1,2,0,1);
398         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->to_field,     1,2,1,2);
399         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->cc_field,     1,2,2,3);
400         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->bcc_field,    1,2,3,4);
401         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->subject_field,1,2,4,5);
402
403         priv->msg_body = gtk_text_view_new ();
404         
405         main_vbox = gtk_vbox_new  (FALSE, 6);
406
407         priv->menubar = menubar_new (obj);
408         priv->toolbar = GTK_WIDGET(toolbar_new (obj));
409
410         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 0);
411         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);
412         gtk_box_pack_start (GTK_BOX(main_vbox), header_table, FALSE, FALSE, 6);
413         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 6);
414
415         gtk_widget_show_all (GTK_WIDGET(main_vbox));
416         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
417 }
418         
419
420
421 static void
422 modest_edit_msg_window_finalize (GObject *obj)
423 {
424         ModestEditMsgWindowPrivate *priv;
425
426         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
427
428         g_object_unref (G_OBJECT(priv->factory));
429         priv->factory = NULL;
430         
431         G_OBJECT_CLASS(parent_class)->finalize (obj);
432
433 }
434
435
436
437 static gboolean
438 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestEditMsgWindow *self)
439 {
440         save_settings (self);
441         return FALSE;
442 }
443
444
445 GtkWidget*
446 modest_edit_msg_window_new (ModestWidgetFactory *factory,
447                             ModestEditType type)
448 {
449         GObject *obj;
450         ModestEditMsgWindowPrivate *priv;
451
452         g_return_val_if_fail (factory, NULL);
453         g_return_val_if_fail (type < MODEST_EDIT_TYPE_NUM, NULL);
454 /*      g_return_val_if_fail (!(type!=MODEST_EDIT_TYPE_NEW && !msg), NULL);      */
455         
456         obj = g_object_new(MODEST_TYPE_EDIT_MSG_WINDOW, NULL);
457         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
458
459         g_object_ref (factory);
460         priv->factory = factory;
461
462         init_window (MODEST_EDIT_MSG_WINDOW(obj));
463
464         restore_settings (MODEST_EDIT_MSG_WINDOW(obj));
465         
466         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
467         gtk_window_set_icon  (GTK_WINDOW(obj),
468                               modest_icon_factory_get_icon (MODEST_APP_ICON));
469
470         g_signal_connect (G_OBJECT(obj), "delete-event",
471                           G_CALLBACK(on_delete_event), obj);
472
473         return GTK_WIDGET (obj);
474 }
475
476 void
477 modest_edit_msg_window_set_msg (ModestEditMsgWindow *self, TnyMsg *msg)
478 {
479         TnyHeader *header;
480         GtkTextBuffer *buf;
481         const gchar *to, *cc, *bcc, *subject;
482         ModestEditMsgWindowPrivate *priv;
483
484         g_return_if_fail (MODEST_IS_EDIT_MSG_WINDOW (self));
485         g_return_if_fail (TNY_IS_MSG (msg));
486
487         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE (self);
488
489         header = tny_msg_get_header (msg);
490         to      = tny_header_get_to (header);
491         cc      = tny_header_get_cc (header);
492         bcc     = tny_header_get_bcc (header);
493         subject = tny_header_get_subject (header);
494
495         if (to)
496                 gtk_entry_set_text (GTK_ENTRY(priv->to_field),  to);
497         if (cc)
498                 gtk_entry_set_text (GTK_ENTRY(priv->cc_field),  cc);
499         if (bcc)
500                 gtk_entry_set_text (GTK_ENTRY(priv->bcc_field), bcc);
501         if (subject)
502                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject);   
503         
504         buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(priv->msg_body));
505         gtk_text_buffer_set_text (buf,
506                                   (const gchar *) modest_tny_msg_actions_find_body (msg, TRUE),
507                                   -1);
508
509         /* TODO: lower priority, select in the From: combo to the
510            value that comes from msg <- not sure, should it be
511            allowed? */
512         
513         /* TODO: set attachments */
514 }