* Modified the maximum size of the entries of the edit msg window
[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 *to, *cc, *bcc, *subject;
245         gchar *body, *from;
246         ModestEditMsgWindowPrivate *priv;
247         TnyTransportAccount *transport_account;
248         ModestMailOperation *mail_operation;
249         ModestAccountData *data;
250         
251         GtkTextBuffer *buf;
252         GtkTextIter b, e;
253         
254         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
255         data = modest_combo_box_get_active_id (MODEST_COMBO_BOX (priv->from_field));
256
257         /* don't free these (except from) */
258         from    =  g_strdup_printf ("%s <%s>", data->full_name, data->email) ;
259         to      =  gtk_entry_get_text (GTK_ENTRY(priv->to_field));
260         cc      =  gtk_entry_get_text (GTK_ENTRY(priv->cc_field));
261         bcc     =  gtk_entry_get_text (GTK_ENTRY(priv->bcc_field));
262         subject =  gtk_entry_get_text (GTK_ENTRY(priv->subject_field));
263         
264         /* don't unref */
265         buf   =  gtk_text_view_get_buffer (GTK_TEXT_VIEW(priv->msg_body));
266         
267         gtk_text_buffer_get_bounds (buf, &b, &e);
268         body  = gtk_text_buffer_get_text (buf, &b, &e,
269                                           FALSE); /* free this one */
270
271         /* FIXME: Code added just for testing. The transport_account
272            should be provided by the account manager, maybe using
273            _get_current_account () or _get_default_account
274            (TRANSPORT_ACCOUNT). These methods do not exist currently. */
275         {
276                 TnyList *accounts;
277                 TnyIterator *iter;
278                 TnyAccountStore *account_store;
279
280                 accounts = TNY_LIST(tny_simple_list_new ());
281                 account_store = tny_platform_factory_new_account_store (priv->fact);
282                 tny_account_store_get_accounts (account_store, accounts,
283                                                 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
284
285                 iter = tny_list_create_iterator(accounts);
286                 tny_iterator_first (iter);
287                 if (tny_iterator_is_done (iter)) {
288                         /* FIXME: Add error handling through mail operation */
289                         g_printerr("modest: no transport accounts defined\n");
290                         g_free (body);
291                         return;
292                 }
293                 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
294         }
295
296         mail_operation = modest_mail_operation_new ();
297
298         modest_mail_operation_send_new_mail (mail_operation,
299                                              transport_account,
300                                              from, to, cc, bcc,
301                                              subject, body, NULL);
302         /* Clean up */
303         g_object_unref (mail_operation);
304         g_free (from);
305         g_free (body);
306 }
307
308
309 static void
310 on_toolbar_button_clicked (ModestToolbar *toolbar, ModestToolbarButton button_id,
311                            ModestEditMsgWindow *self)
312 {
313         switch (button_id) {
314         case MODEST_TOOLBAR_BUTTON_MAIL_SEND:
315                 send_mail (self);
316                 save_settings (self);
317                 gtk_widget_destroy (GTK_WIDGET(self));
318                 break;
319                 
320         case MODEST_TOOLBAR_BUTTON_REPLY:
321         case MODEST_TOOLBAR_BUTTON_REPLY_ALL:
322         case MODEST_TOOLBAR_BUTTON_FORWARD:
323         case MODEST_TOOLBAR_BUTTON_SEND_RECEIVE:
324         case MODEST_TOOLBAR_BUTTON_NEXT:
325         case MODEST_TOOLBAR_BUTTON_PREV:
326         case MODEST_TOOLBAR_BUTTON_DELETE:
327
328         default:
329                 g_printerr ("modest: key %d pressed\n", button_id);
330         }
331 }
332
333
334
335
336 static ModestToolbar*
337 toolbar_new (ModestEditMsgWindow *self)
338 {
339         int i;
340         ModestToolbar *toolbar;
341         GSList *buttons = NULL;
342         ModestEditMsgWindowPrivate *priv;
343
344         ModestToolbarButton button_ids[] = {
345                 MODEST_TOOLBAR_BUTTON_MAIL_SEND
346         };              
347         
348         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(self);
349
350         for (i = 0 ; i != sizeof(button_ids) / sizeof(ModestToolbarButton); ++i)
351                 buttons = g_slist_append (buttons, GINT_TO_POINTER(button_ids[i]));
352         
353         toolbar = modest_widget_factory_get_edit_toolbar (priv->factory, buttons);
354         g_slist_free (buttons);
355
356         g_signal_connect (G_OBJECT(toolbar), "button_clicked",
357                           G_CALLBACK(on_toolbar_button_clicked), self);
358         
359         return toolbar;
360 }
361
362
363 static void
364 init_window (ModestEditMsgWindow *obj)
365 {
366         GtkWidget *to_button, *cc_button, *bcc_button; 
367         GtkWidget *header_table;
368         GtkWidget *main_vbox;
369         
370         ModestEditMsgWindowPrivate *priv;
371         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
372
373         to_button     = gtk_button_new_with_label (_("To..."));
374         cc_button     = gtk_button_new_with_label (_("Cc..."));
375         bcc_button    = gtk_button_new_with_label (_("Bcc..."));
376
377         priv->from_field    = modest_widget_factory_get_combo_box (priv->factory,
378                                                                    MODEST_COMBO_BOX_TYPE_TRANSPORTS);
379         priv->to_field      = gtk_entry_new_with_max_length (80);
380         priv->cc_field      = gtk_entry_new_with_max_length (80);
381         priv->bcc_field     = gtk_entry_new_with_max_length (80);
382         priv->subject_field = gtk_entry_new_with_max_length (80);
383         
384         header_table = gtk_table_new (5,2, FALSE);
385         
386         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("From:")),
387                           0,1,0,1, GTK_SHRINK, 0, 0, 0);
388         gtk_table_attach (GTK_TABLE(header_table), to_button,     0,1,1,2, GTK_SHRINK, 0, 0, 0);
389         gtk_table_attach (GTK_TABLE(header_table), cc_button,     0,1,2,3, GTK_SHRINK, 0, 0, 0);
390         gtk_table_attach (GTK_TABLE(header_table), bcc_button,    0,1,3,4, GTK_SHRINK, 0, 0, 0);
391         gtk_table_attach (GTK_TABLE(header_table), gtk_label_new (_("Subject:")),
392                           0,1,4,5, GTK_SHRINK, 0, 0, 0);
393
394         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->from_field,   1,2,0,1);
395         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->to_field,     1,2,1,2);
396         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->cc_field,     1,2,2,3);
397         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->bcc_field,    1,2,3,4);
398         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->subject_field,1,2,4,5);
399
400         priv->msg_body = gtk_text_view_new ();
401         
402         main_vbox = gtk_vbox_new  (FALSE, 6);
403
404         priv->menubar = menubar_new (obj);
405         priv->toolbar = GTK_WIDGET(toolbar_new (obj));
406
407         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 0);
408         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);
409         gtk_box_pack_start (GTK_BOX(main_vbox), header_table, FALSE, FALSE, 6);
410         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 6);
411
412         gtk_widget_show_all (GTK_WIDGET(main_vbox));
413         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
414 }
415         
416
417
418 static void
419 modest_edit_msg_window_finalize (GObject *obj)
420 {
421         ModestEditMsgWindowPrivate *priv;
422
423         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
424
425         g_object_unref (G_OBJECT(priv->factory));
426         priv->factory = NULL;
427         
428         G_OBJECT_CLASS(parent_class)->finalize (obj);
429
430 }
431
432
433
434 static gboolean
435 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestEditMsgWindow *self)
436 {
437         save_settings (self);
438         return FALSE;
439 }
440
441
442 GtkWidget*
443 modest_edit_msg_window_new (ModestWidgetFactory *factory,
444                             ModestEditType type, TnyMsg *msg)
445 {
446         GObject *obj;
447         ModestEditMsgWindowPrivate *priv;
448
449         g_return_val_if_fail (factory, NULL);
450         g_return_val_if_fail (type < MODEST_EDIT_TYPE_NUM, NULL);
451         g_return_val_if_fail (!(type==MODEST_EDIT_TYPE_NEW && msg), NULL); 
452         g_return_val_if_fail (!(type!=MODEST_EDIT_TYPE_NEW && !msg), NULL);     
453         
454         obj = g_object_new(MODEST_TYPE_EDIT_MSG_WINDOW, NULL);
455         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
456
457         g_object_ref (factory);
458         priv->factory = factory;
459
460         init_window (MODEST_EDIT_MSG_WINDOW(obj));
461
462         restore_settings (MODEST_EDIT_MSG_WINDOW(obj));
463         
464         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
465         gtk_window_set_icon  (GTK_WINDOW(obj),
466                               modest_icon_factory_get_icon (MODEST_APP_ICON));
467
468         g_signal_connect (G_OBJECT(obj), "delete-event",
469                           G_CALLBACK(on_delete_event), obj);
470         
471         if (msg) {
472                 /* Testing code. Should be into a set_msg method */
473                 TnyHeader *header;
474                 GtkTextBuffer *buf;
475
476                 header = tny_msg_get_header (msg);
477                 gtk_entry_set_text (GTK_ENTRY(priv->to_field),
478                                     tny_header_get_to (header));
479                 gtk_entry_set_text (GTK_ENTRY(priv->cc_field),
480                                     tny_header_get_cc (header));
481                 gtk_entry_set_text (GTK_ENTRY(priv->bcc_field),
482                                     tny_header_get_bcc (header));
483                 gtk_entry_set_text (GTK_ENTRY(priv->subject_field),
484                                     tny_header_get_subject (header));   
485
486                 buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(priv->msg_body));
487                 gtk_text_buffer_set_text (buf,
488                                           (const gchar *) modest_tny_msg_actions_find_body (msg, TRUE),
489                                           -1);
490
491                 /* TODO: lower priority, select in the From: combo to
492                    the value that comes from msg */
493
494                 /* TODO: set attachments */
495         }
496
497         return GTK_WIDGET (obj);
498 }