221bf314b7493e12cb919f89b13b31e7722ef13f
[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
30 #include "modest-edit-msg-window.h"
31 #include <widgets/modest-msg-view.h>
32 #include <modest-widget-memory.h>
33 #include <modest-widget-factory.h>
34 #include "modest-icon-names.h"
35 #include "modest-mail-operation.h"
36 #include "modest-tny-platform-factory.h"
37 #include <tny-simple-list.h>
38
39 static void  modest_edit_msg_window_class_init   (ModestEditMsgWindowClass *klass);
40 static void  modest_edit_msg_window_init         (ModestEditMsgWindow *obj);
41 static void  modest_edit_msg_window_finalize     (GObject *obj);
42
43 /* list my signals */
44 enum {
45         /* MY_SIGNAL_1, */
46         /* MY_SIGNAL_2, */
47         LAST_SIGNAL
48 };
49
50 typedef struct _ModestEditMsgWindowPrivate ModestEditMsgWindowPrivate;
51 struct _ModestEditMsgWindowPrivate {
52
53         ModestWidgetFactory *factory;
54         TnyPlatformFactory *fact;
55         
56         GtkWidget      *toolbar, *menubar;
57         GtkWidget      *msg_body;
58         GtkWidget      *from_field, *to_field, *cc_field, *bcc_field,
59                        *subject_field;
60 };
61 #define MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
62                                                     MODEST_TYPE_EDIT_MSG_WINDOW, \
63                                                     ModestEditMsgWindowPrivate))
64 /* globals */
65 static GtkWindowClass *parent_class = NULL;
66
67 /* uncomment the following if you have defined any signals */
68 /* static guint signals[LAST_SIGNAL] = {0}; */
69
70 GType
71 modest_edit_msg_window_get_type (void)
72 {
73         static GType my_type = 0;
74         if (!my_type) {
75                 static const GTypeInfo my_info = {
76                         sizeof(ModestEditMsgWindowClass),
77                         NULL,           /* base init */
78                         NULL,           /* base finalize */
79                         (GClassInitFunc) modest_edit_msg_window_class_init,
80                         NULL,           /* class finalize */
81                         NULL,           /* class data */
82                         sizeof(ModestEditMsgWindow),
83                         1,              /* n_preallocs */
84                         (GInstanceInitFunc) modest_edit_msg_window_init,
85                         NULL
86                 };
87                 my_type = g_type_register_static (GTK_TYPE_WINDOW,
88                                                   "ModestEditMsgWindow",
89                                                   &my_info, 0);
90         }
91         return my_type;
92 }
93
94 static void
95 modest_edit_msg_window_class_init (ModestEditMsgWindowClass *klass)
96 {
97         GObjectClass *gobject_class;
98         gobject_class = (GObjectClass*) klass;
99
100         parent_class            = g_type_class_peek_parent (klass);
101         gobject_class->finalize = modest_edit_msg_window_finalize;
102
103         g_type_class_add_private (gobject_class, sizeof(ModestEditMsgWindowPrivate));
104
105         /* signal definitions go here, e.g.: */
106 /*      signals[MY_SIGNAL_1] = */
107 /*              g_signal_new ("my_signal_1",....); */
108 /*      signals[MY_SIGNAL_2] = */
109 /*              g_signal_new ("my_signal_2",....); */
110 /*      etc. */
111 }
112
113 static void
114 modest_edit_msg_window_init (ModestEditMsgWindow *obj)
115 {
116         ModestEditMsgWindowPrivate *priv;
117         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
118
119         priv->fact = modest_tny_platform_factory_get_instance ();
120         priv->factory = NULL;
121         priv->toolbar = NULL;
122         priv->menubar = NULL;
123 }
124
125
126
127 static void
128 save_settings (ModestEditMsgWindow *self)
129 {
130         ModestEditMsgWindowPrivate *priv;
131         ModestConf *conf;
132
133         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
134         conf = modest_tny_platform_factory_get_modest_conf_instance (priv->fact);
135
136         modest_widget_memory_save_settings (conf, GTK_WIDGET(self),
137                                             "modest-edit-msg-window");
138 }
139
140
141 static void
142 restore_settings (ModestEditMsgWindow *self)
143 {
144         ModestEditMsgWindowPrivate *priv;
145         ModestConf *conf;
146
147         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
148         conf = modest_tny_platform_factory_get_modest_conf_instance (priv->fact);
149
150         modest_widget_memory_restore_settings (conf, GTK_WIDGET(self),
151                                                "modest-edit-msg-window");
152 }
153
154         
155
156 static void
157 on_menu_quit (ModestEditMsgWindow *self, guint action, GtkWidget *widget)
158 {
159         save_settings (self);
160         gtk_widget_destroy (GTK_WIDGET(self));
161 }
162
163
164
165
166
167 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
168 static GtkItemFactoryEntry menu_items[] = {
169         { "/_File",             NULL,                   NULL,           0, "<Branch>" ,NULL},
170         { "/File/_New",         "<control>N",           NULL,           0, "<StockItem>", GTK_STOCK_NEW },
171         { "/File/_Open",        "<control>O",           NULL,           0, "<StockItem>", GTK_STOCK_OPEN },
172         { "/File/_Save",        "<control>S",           NULL,           0, "<StockItem>", GTK_STOCK_SAVE },
173         { "/File/Save _As",     NULL,                   NULL,           0, "<Item>", NULL} ,
174         { "/File/Save Draft",   "<control><shift>S",    NULL,           0, "<Item>",NULL },
175
176
177         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" ,NULL },
178         { "/File/_Quit",        "<CTRL>Q",              on_menu_quit,   0, "<StockItem>", GTK_STOCK_QUIT },
179
180         { "/_Edit",             NULL,                   NULL,           0, "<Branch>" ,NULL },
181         { "/Edit/_Undo",        "<CTRL>Z",              NULL,           0, "<StockItem>", GTK_STOCK_UNDO },
182         { "/Edit/_Redo",        "<shift><CTRL>Z",       NULL,           0, "<StockItem>", GTK_STOCK_REDO },
183         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>",NULL },
184         { "/Edit/Cut",          "<control>X",           NULL,           0, "<StockItem>", GTK_STOCK_CUT  },
185         { "/Edit/Copy",         "<CTRL>C",              NULL,           0, "<StockItem>", GTK_STOCK_COPY },
186         { "/Edit/Paste",        NULL,                   NULL,           0, "<StockItem>", GTK_STOCK_PASTE},
187         { "/Edit/sep1",         NULL,                   NULL,           0, "<Separator>",NULL },
188         { "/Edit/Delete",       "<CTRL>Q",              NULL,           0, "<Item>" ,NULL },
189         { "/Edit/Select all",   "<CTRL>A",              NULL,           0, "<Item>" ,NULL },
190         { "/Edit/Deselect all",  "<Shift><CTRL>A",      NULL,           0, "<Item>",NULL },
191
192         { "/_View",             NULL,           NULL,                   0, "<Branch>",NULL },
193         { "/View/To-field",          NULL,              NULL,           0, "<CheckItem>",NULL },
194         
195         { "/View/Cc-field:",          NULL,             NULL,           0, "<CheckItem>",NULL },
196         { "/View/Bcc-field:",          NULL,            NULL,           0, "<CheckItem>",NULL },
197         
198         
199         { "/_Insert",             NULL,         NULL,           0, "<Branch>",NULL },
200 /*      { "/Actions/_Reply",    NULL,                   NULL,           0, "<Item>" }, */
201 /*      { "/Actions/_Forward",  NULL,                   NULL,           0, "<Item>" }, */
202 /*      { "/Actions/_Bounce",   NULL,                   NULL,           0, "<Item>" },   */
203         
204         { "/_Format",            NULL,                  NULL,           0, "<Branch>",NULL }
205 /*      { "/Options/_Accounts",  NULL,                  on_menu_accounts,0, "<Item>" }, */
206 /*      { "/Options/_Contacts",  NULL,                  NULL,           0, "<Item>" }, */
207
208
209 /*      { "/_Help",         NULL,                       NULL,           0, "<Branch>" }, */
210 /*      { "/_Help/About",   NULL,                       on_menu_about,  0, "<StockItem>", GTK_STOCK_ABOUT}, */
211 };
212
213 static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
214
215
216 static GtkWidget *
217 menubar_new (ModestEditMsgWindow *self)
218 {
219         GtkItemFactory *item_factory;
220         GtkAccelGroup *accel_group;
221         
222         /* Make an accelerator group (shortcut keys) */
223         accel_group = gtk_accel_group_new ();
224         
225         /* Make an ItemFactory (that makes a menubar) */
226         item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
227                                              accel_group);
228         
229         /* This function generates the menu items. Pass the item factory,
230            the number of items in the array, the array itself, and any
231            callback data for the the menu items. */
232         gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, self);
233         
234         ///* Attach the new accelerator group to the window. */
235         gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
236         
237         /* Finally, return the actual menu bar created by the item factory. */
238         return gtk_item_factory_get_widget (item_factory, "<main>");
239 }
240
241
242 static void
243 send_mail (ModestEditMsgWindow *self)
244 {
245         const gchar *from, *to, *cc, *bcc, *subject;
246         gchar *body;
247         ModestEditMsgWindowPrivate *priv;
248         TnyTransportAccount *transport_account;
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                         g_printerr("modest: no transport accounts defined\n");
287                         goto cleanup;
288                 }
289
290                 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
291
292         }
293         /*****/
294         modest_mail_operation_send_mail (transport_account,
295                                          from, to, cc, bcc,
296                                          subject, body, NULL);
297         
298  cleanup:
299
300         g_free (body);
301 }
302
303
304 static void
305 on_toolbar_button_clicked (ModestToolbar *toolbar, ModestToolbarButton button_id,
306                            ModestEditMsgWindow *self)
307 {
308         switch (button_id) {
309         case MODEST_TOOLBAR_BUTTON_MAIL_SEND:
310                 send_mail (self);
311                 save_settings (self);
312                 gtk_widget_destroy (GTK_WIDGET(self));
313                 break;
314                 
315         case MODEST_TOOLBAR_BUTTON_REPLY:
316         case MODEST_TOOLBAR_BUTTON_REPLY_ALL:
317         case MODEST_TOOLBAR_BUTTON_FORWARD:
318         case MODEST_TOOLBAR_BUTTON_SEND_RECEIVE:
319         case MODEST_TOOLBAR_BUTTON_NEXT:
320         case MODEST_TOOLBAR_BUTTON_PREV:
321         case MODEST_TOOLBAR_BUTTON_DELETE:
322
323         default:
324                 g_printerr ("modest: key %d pressed\n", button_id);
325         }
326 }
327
328
329
330
331 static ModestToolbar*
332 toolbar_new (ModestEditMsgWindow *self)
333 {
334         int i;
335         ModestToolbar *toolbar;
336         GSList *buttons = NULL;
337         ModestEditMsgWindowPrivate *priv;
338
339         ModestToolbarButton button_ids[] = {
340                 MODEST_TOOLBAR_BUTTON_MAIL_SEND
341         };              
342         
343         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
344
345         for (i = 0 ; i != sizeof(button_ids) / sizeof(ModestToolbarButton); ++i)
346                 buttons = g_slist_append (buttons, GINT_TO_POINTER(button_ids[i]));
347         
348         toolbar = modest_widget_factory_get_edit_toolbar (priv->factory, buttons);
349         g_slist_free (buttons);
350
351         g_signal_connect (G_OBJECT(toolbar), "button_clicked",
352                           G_CALLBACK(on_toolbar_button_clicked), self);
353         
354         return toolbar;
355 }
356
357
358 static void
359 init_window (ModestEditMsgWindow *obj)
360 {
361         GtkWidget *to_button, *cc_button, *bcc_button; 
362         GtkWidget *header_table;
363         GtkWidget *main_vbox;
364         
365         ModestEditMsgWindowPrivate *priv;
366         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
367
368         to_button     = gtk_button_new_with_label (_("To..."));
369         cc_button     = gtk_button_new_with_label (_("Cc..."));
370         bcc_button    = gtk_button_new_with_label (_("Bcc..."));
371
372         priv->from_field    = modest_widget_factory_get_combo_box (priv->factory,
373                                                                    MODEST_COMBO_BOX_TYPE_TRANSPORTS);
374         priv->to_field      = gtk_entry_new_with_max_length (40);
375         priv->cc_field      = gtk_entry_new_with_max_length (40);
376         priv->bcc_field     = gtk_entry_new_with_max_length (40);
377         priv->subject_field = gtk_entry_new_with_max_length (40);
378         
379         header_table = gtk_table_new (5,2, FALSE);
380         
381         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("From:")),
382                           0,1,0,1, GTK_SHRINK, 0, 0, 0);
383         gtk_table_attach (GTK_TABLE(header_table), to_button,     0,1,1,2, GTK_SHRINK, 0, 0, 0);
384         gtk_table_attach (GTK_TABLE(header_table), cc_button,     0,1,2,3, GTK_SHRINK, 0, 0, 0);
385         gtk_table_attach (GTK_TABLE(header_table), bcc_button,    0,1,3,4, GTK_SHRINK, 0, 0, 0);
386         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("Subject:")),
387                           0,1,4,5, GTK_SHRINK, 0, 0, 0);
388
389         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->from_field,   1,2,0,1);
390         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->to_field,     1,2,1,2);
391         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->cc_field,     1,2,2,3);
392         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->bcc_field,    1,2,3,4);
393         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->subject_field,1,2,4,5);
394
395         priv->msg_body = gtk_text_view_new ();
396         
397         main_vbox = gtk_vbox_new  (FALSE, 6);
398
399         priv->menubar = menubar_new (obj);
400         priv->toolbar = GTK_WIDGET(toolbar_new (obj));
401
402         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 0);
403         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);
404         gtk_box_pack_start (GTK_BOX(main_vbox), header_table, FALSE, FALSE, 6);
405         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 6);
406
407         gtk_widget_show_all (GTK_WIDGET(main_vbox));
408         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
409 }
410         
411
412
413 static void
414 modest_edit_msg_window_finalize (GObject *obj)
415 {
416         ModestEditMsgWindowPrivate *priv;
417
418         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
419
420         g_object_unref (G_OBJECT(priv->factory));
421         priv->factory = NULL;
422         
423         G_OBJECT_CLASS(parent_class)->finalize (obj);
424
425 }
426
427
428
429 static gboolean
430 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestEditMsgWindow *self)
431 {
432         save_settings (self);
433         return FALSE;
434 }
435
436
437 GtkWidget*
438 modest_edit_msg_window_new (ModestWidgetFactory *factory,
439                             ModestEditType type, TnyMsgIface *msg)
440 {
441         GObject *obj;
442         ModestEditMsgWindowPrivate *priv;
443
444         g_return_val_if_fail (factory, NULL);
445         g_return_val_if_fail (type < MODEST_EDIT_TYPE_NUM, NULL);
446         g_return_val_if_fail (!(type==MODEST_EDIT_TYPE_NEW && msg), NULL); 
447         g_return_val_if_fail (!(type!=MODEST_EDIT_TYPE_NEW && !msg), NULL);     
448         
449         obj = g_object_new(MODEST_TYPE_EDIT_MSG_WINDOW, NULL);
450         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
451
452         g_object_ref (factory);
453         priv->factory = factory;
454
455         init_window (MODEST_EDIT_MSG_WINDOW(obj));
456
457         restore_settings (MODEST_EDIT_MSG_WINDOW(obj));
458         
459         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
460         gtk_window_set_icon  (GTK_WINDOW(obj),
461                               modest_icon_factory_get_icon (MODEST_APP_ICON));
462
463         g_signal_connect (G_OBJECT(obj), "delete-event",
464                           G_CALLBACK(on_delete_event), obj);
465         
466         return GTK_WIDGET (obj);
467 }