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