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