* src/modest-tny-store-actions.h
[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_settings (conf, GTK_WIDGET(self),
136                                             "modest-edit-msg-window");
137 }
138
139
140 static void
141 restore_settings (ModestEditMsgWindow *self)
142 {
143         ModestEditMsgWindowPrivate *priv;
144         ModestConf *conf;
145
146         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
147         conf = modest_tny_platform_factory_get_modest_conf_instance (priv->fact);
148
149         modest_widget_memory_restore_settings (conf, GTK_WIDGET(self),
150                                                "modest-edit-msg-window");
151 }
152
153         
154
155 static void
156 on_menu_quit (ModestEditMsgWindow *self, guint action, GtkWidget *widget)
157 {
158         save_settings (self);
159         gtk_widget_destroy (GTK_WIDGET(self));
160 }
161
162
163
164
165
166 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
167 static GtkItemFactoryEntry menu_items[] = {
168         { "/_File",             NULL,                   NULL,           0, "<Branch>" ,NULL},
169         { "/File/_New",         "<control>N",           NULL,           0, "<StockItem>", GTK_STOCK_NEW },
170         { "/File/_Open",        "<control>O",           NULL,           0, "<StockItem>", GTK_STOCK_OPEN },
171         { "/File/_Save",        "<control>S",           NULL,           0, "<StockItem>", GTK_STOCK_SAVE },
172         { "/File/Save _As",     NULL,                   NULL,           0, "<Item>", NULL} ,
173         { "/File/Save Draft",   "<control><shift>S",    NULL,           0, "<Item>",NULL },
174
175
176         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" ,NULL },
177         { "/File/_Quit",        "<CTRL>Q",              on_menu_quit,   0, "<StockItem>", GTK_STOCK_QUIT },
178
179         { "/_Edit",             NULL,                   NULL,           0, "<Branch>" ,NULL },
180         { "/Edit/_Undo",        "<CTRL>Z",              NULL,           0, "<StockItem>", GTK_STOCK_UNDO },
181         { "/Edit/_Redo",        "<shift><CTRL>Z",       NULL,           0, "<StockItem>", GTK_STOCK_REDO },
182         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>",NULL },
183         { "/Edit/Cut",          "<control>X",           NULL,           0, "<StockItem>", GTK_STOCK_CUT  },
184         { "/Edit/Copy",         "<CTRL>C",              NULL,           0, "<StockItem>", GTK_STOCK_COPY },
185         { "/Edit/Paste",        NULL,                   NULL,           0, "<StockItem>", GTK_STOCK_PASTE},
186         { "/Edit/sep1",         NULL,                   NULL,           0, "<Separator>",NULL },
187         { "/Edit/Delete",       "<CTRL>Q",              NULL,           0, "<Item>" ,NULL },
188         { "/Edit/Select all",   "<CTRL>A",              NULL,           0, "<Item>" ,NULL },
189         { "/Edit/Deselect all",  "<Shift><CTRL>A",      NULL,           0, "<Item>",NULL },
190
191         { "/_View",             NULL,           NULL,                   0, "<Branch>",NULL },
192         { "/View/To-field",          NULL,              NULL,           0, "<CheckItem>",NULL },
193         
194         { "/View/Cc-field:",          NULL,             NULL,           0, "<CheckItem>",NULL },
195         { "/View/Bcc-field:",          NULL,            NULL,           0, "<CheckItem>",NULL },
196         
197         
198         { "/_Insert",             NULL,         NULL,           0, "<Branch>",NULL },
199 /*      { "/Actions/_Reply",    NULL,                   NULL,           0, "<Item>" }, */
200 /*      { "/Actions/_Forward",  NULL,                   NULL,           0, "<Item>" }, */
201 /*      { "/Actions/_Bounce",   NULL,                   NULL,           0, "<Item>" },   */
202         
203         { "/_Format",            NULL,                  NULL,           0, "<Branch>",NULL }
204 /*      { "/Options/_Accounts",  NULL,                  on_menu_accounts,0, "<Item>" }, */
205 /*      { "/Options/_Contacts",  NULL,                  NULL,           0, "<Item>" }, */
206
207
208 /*      { "/_Help",         NULL,                       NULL,           0, "<Branch>" }, */
209 /*      { "/_Help/About",   NULL,                       on_menu_about,  0, "<StockItem>", GTK_STOCK_ABOUT}, */
210 };
211
212 static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
213
214
215 static GtkWidget *
216 menubar_new (ModestEditMsgWindow *self)
217 {
218         GtkItemFactory *item_factory;
219         GtkAccelGroup *accel_group;
220         
221         /* Make an accelerator group (shortcut keys) */
222         accel_group = gtk_accel_group_new ();
223         
224         /* Make an ItemFactory (that makes a menubar) */
225         item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
226                                              accel_group);
227         
228         /* This function generates the menu items. Pass the item factory,
229            the number of items in the array, the array itself, and any
230            callback data for the the menu items. */
231         gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, self);
232         
233         ///* Attach the new accelerator group to the window. */
234         gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
235         
236         /* Finally, return the actual menu bar created by the item factory. */
237         return gtk_item_factory_get_widget (item_factory, "<main>");
238 }
239
240
241 static void
242 send_mail (ModestEditMsgWindow *self)
243 {
244         const gchar *from, *to, *cc, *bcc, *subject;
245         gchar *body;
246         ModestEditMsgWindowPrivate *priv;
247         TnyTransportAccount *transport_account;
248         ModestMailOperation *mail_operation;
249         
250         GtkTextBuffer *buf;
251         GtkTextIter b, e;
252         
253         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
254
255         /* don't free these */
256         from    = "djcb@djcbsoftware.nl";
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 transport_account
270            should be provided by the account manager, maybe using
271            _get_current_account () or _get_default_account
272            (TRANSPORT_ACCOUNT). These methods do not exist currently. */
273         {
274                 TnyList *accounts;
275                 TnyIterator *iter;
276                 TnyAccountStore *account_store;
277
278                 accounts = TNY_LIST(tny_simple_list_new ());
279                 account_store = tny_platform_factory_new_account_store (priv->fact);
280                 tny_account_store_get_accounts (account_store, accounts,
281                                                 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
282
283                 iter = tny_list_create_iterator(accounts);
284                 tny_iterator_first (iter);
285                 if (tny_iterator_is_done (iter)) {
286                         /* FIXME: Add error handling through mail operation */
287                         g_printerr("modest: no transport accounts defined\n");
288                         g_free (body);
289                         return;
290                 }
291                 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
292         }
293
294         mail_operation = modest_mail_operation_new (TNY_ACCOUNT (transport_account));
295
296         modest_mail_operation_send_new_mail (mail_operation,
297                                              from, to, cc, bcc,
298                                              subject, body, NULL);
299         /* Clean up */
300         g_object_unref (mail_operation);
301         g_free (body);
302 }
303
304
305 static void
306 on_toolbar_button_clicked (ModestToolbar *toolbar, ModestToolbarButton button_id,
307                            ModestEditMsgWindow *self)
308 {
309         switch (button_id) {
310         case MODEST_TOOLBAR_BUTTON_MAIL_SEND:
311                 send_mail (self);
312                 save_settings (self);
313                 gtk_widget_destroy (GTK_WIDGET(self));
314                 break;
315                 
316         case MODEST_TOOLBAR_BUTTON_REPLY:
317         case MODEST_TOOLBAR_BUTTON_REPLY_ALL:
318         case MODEST_TOOLBAR_BUTTON_FORWARD:
319         case MODEST_TOOLBAR_BUTTON_SEND_RECEIVE:
320         case MODEST_TOOLBAR_BUTTON_NEXT:
321         case MODEST_TOOLBAR_BUTTON_PREV:
322         case MODEST_TOOLBAR_BUTTON_DELETE:
323
324         default:
325                 g_printerr ("modest: key %d pressed\n", button_id);
326         }
327 }
328
329
330
331
332 static ModestToolbar*
333 toolbar_new (ModestEditMsgWindow *self)
334 {
335         int i;
336         ModestToolbar *toolbar;
337         GSList *buttons = NULL;
338         ModestEditMsgWindowPrivate *priv;
339
340         ModestToolbarButton button_ids[] = {
341                 MODEST_TOOLBAR_BUTTON_MAIL_SEND
342         };              
343         
344         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
345
346         for (i = 0 ; i != sizeof(button_ids) / sizeof(ModestToolbarButton); ++i)
347                 buttons = g_slist_append (buttons, GINT_TO_POINTER(button_ids[i]));
348         
349         toolbar = modest_widget_factory_get_edit_toolbar (priv->factory, buttons);
350         g_slist_free (buttons);
351
352         g_signal_connect (G_OBJECT(toolbar), "button_clicked",
353                           G_CALLBACK(on_toolbar_button_clicked), self);
354         
355         return toolbar;
356 }
357
358
359 static void
360 init_window (ModestEditMsgWindow *obj)
361 {
362         GtkWidget *to_button, *cc_button, *bcc_button; 
363         GtkWidget *header_table;
364         GtkWidget *main_vbox;
365         
366         ModestEditMsgWindowPrivate *priv;
367         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
368
369         to_button     = gtk_button_new_with_label (_("To..."));
370         cc_button     = gtk_button_new_with_label (_("Cc..."));
371         bcc_button    = gtk_button_new_with_label (_("Bcc..."));
372
373         priv->from_field    = modest_widget_factory_get_combo_box (priv->factory,
374                                                                    MODEST_COMBO_BOX_TYPE_TRANSPORTS);
375         priv->to_field      = gtk_entry_new_with_max_length (40);
376         priv->cc_field      = gtk_entry_new_with_max_length (40);
377         priv->bcc_field     = gtk_entry_new_with_max_length (40);
378         priv->subject_field = gtk_entry_new_with_max_length (40);
379         
380         header_table = gtk_table_new (5,2, FALSE);
381         
382         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("From:")),
383                           0,1,0,1, GTK_SHRINK, 0, 0, 0);
384         gtk_table_attach (GTK_TABLE(header_table), to_button,     0,1,1,2, GTK_SHRINK, 0, 0, 0);
385         gtk_table_attach (GTK_TABLE(header_table), cc_button,     0,1,2,3, GTK_SHRINK, 0, 0, 0);
386         gtk_table_attach (GTK_TABLE(header_table), bcc_button,    0,1,3,4, GTK_SHRINK, 0, 0, 0);
387         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("Subject:")),
388                           0,1,4,5, GTK_SHRINK, 0, 0, 0);
389
390         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->from_field,   1,2,0,1);
391         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->to_field,     1,2,1,2);
392         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->cc_field,     1,2,2,3);
393         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->bcc_field,    1,2,3,4);
394         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->subject_field,1,2,4,5);
395
396         priv->msg_body = gtk_text_view_new ();
397         
398         main_vbox = gtk_vbox_new  (FALSE, 6);
399
400         priv->menubar = menubar_new (obj);
401         priv->toolbar = GTK_WIDGET(toolbar_new (obj));
402
403         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 0);
404         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);
405         gtk_box_pack_start (GTK_BOX(main_vbox), header_table, FALSE, FALSE, 6);
406         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 6);
407
408         gtk_widget_show_all (GTK_WIDGET(main_vbox));
409         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
410 }
411         
412
413
414 static void
415 modest_edit_msg_window_finalize (GObject *obj)
416 {
417         ModestEditMsgWindowPrivate *priv;
418
419         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
420
421         g_object_unref (G_OBJECT(priv->factory));
422         priv->factory = NULL;
423         
424         G_OBJECT_CLASS(parent_class)->finalize (obj);
425
426 }
427
428
429
430 static gboolean
431 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestEditMsgWindow *self)
432 {
433         save_settings (self);
434         return FALSE;
435 }
436
437
438 GtkWidget*
439 modest_edit_msg_window_new (ModestWidgetFactory *factory,
440                             ModestEditType type, TnyMsg *msg)
441 {
442         GObject *obj;
443         ModestEditMsgWindowPrivate *priv;
444
445         g_return_val_if_fail (factory, NULL);
446         g_return_val_if_fail (type < MODEST_EDIT_TYPE_NUM, NULL);
447         g_return_val_if_fail (!(type==MODEST_EDIT_TYPE_NEW && msg), NULL); 
448         g_return_val_if_fail (!(type!=MODEST_EDIT_TYPE_NEW && !msg), NULL);     
449         
450         obj = g_object_new(MODEST_TYPE_EDIT_MSG_WINDOW, NULL);
451         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
452
453         g_object_ref (factory);
454         priv->factory = factory;
455
456         init_window (MODEST_EDIT_MSG_WINDOW(obj));
457
458         restore_settings (MODEST_EDIT_MSG_WINDOW(obj));
459         
460         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
461         gtk_window_set_icon  (GTK_WINDOW(obj),
462                               modest_icon_factory_get_icon (MODEST_APP_ICON));
463
464         g_signal_connect (G_OBJECT(obj), "delete-event",
465                           G_CALLBACK(on_delete_event), obj);
466         
467         if (msg) {
468                 /* Testing code. Should be into a set_msg method */
469                 TnyHeader *header;
470                 GtkTextBuffer *buf;
471
472                 header = tny_msg_get_header (msg);
473                 gtk_entry_set_text (GTK_ENTRY(priv->to_field),
474                                     tny_header_get_to (header));
475                 gtk_entry_set_text (GTK_ENTRY(priv->cc_field),
476                                     tny_header_get_cc (header));
477                 gtk_entry_set_text (GTK_ENTRY(priv->bcc_field),
478                                     tny_header_get_bcc (header));
479                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field),
480                                     tny_header_get_subject (header));   
481
482                 buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(priv->msg_body));
483                 gtk_text_buffer_set_text (buf,
484                                           (const gchar *) modest_tny_msg_actions_find_body (msg, FALSE),
485                                           -1);
486         }
487
488         return GTK_WIDGET (obj);
489 }