d09f14952217980195cdc48c813ffe2aebc479c4
[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      *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>" },
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>" },
164         { "/File/Save Draft",   "<control><shift>S",    NULL,           0, "<Item>" },
165
166
167         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" },
168         { "/File/_Quit",        "<CTRL>Q",              on_menu_quit,   0, "<StockItem>", GTK_STOCK_QUIT },
169
170         { "/_Edit",             NULL,                   NULL,           0, "<Branch>" },
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>" },
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>" },
178         { "/Edit/Delete",       "<CTRL>Q",              NULL,           0, "<Item>" },
179         { "/Edit/Select all",   "<CTRL>A",              NULL,           0, "<Item>" },
180         { "/Edit/Deselect all",  "<Shift><CTRL>A",      NULL,           0, "<Item>" },
181
182         { "/_View",             NULL,           NULL,           0, "<Branch>" },
183         { "/View/To-field",          NULL,              NULL,           0, "<CheckItem>" },
184         
185         { "/View/Cc-field:",          NULL,             NULL,           0, "<CheckItem>" },
186         { "/View/Bcc-field:",          NULL,            NULL,           0, "<CheckItem>" },
187         
188         
189         { "/_Insert",             NULL,         NULL,           0, "<Branch>" },
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>" }
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         to   =  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, *subject_label; 
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         subject_label = gtk_label_new (_("Subject:"));
333         
334         priv->to_field      = gtk_entry_new_with_max_length (40);
335         priv->cc_field      = gtk_entry_new_with_max_length (40);
336         priv->bcc_field     = gtk_entry_new_with_max_length (40);
337         priv->subject_field = gtk_entry_new_with_max_length (40);
338
339         header_table = gtk_table_new (4,2, FALSE);
340         gtk_table_attach (GTK_TABLE(header_table), to_button,     0,1,0,1,
341                           GTK_SHRINK, 0, 0, 0);
342         gtk_table_attach (GTK_TABLE(header_table), cc_button,     0,1,1,2,
343                           GTK_SHRINK, 0, 0, 0);
344         gtk_table_attach (GTK_TABLE(header_table), bcc_button,    0,1,2,3,
345                           GTK_SHRINK, 0, 0, 0);
346         gtk_table_attach (GTK_TABLE(header_table), subject_label, 0,1,3,4,
347                           GTK_SHRINK, 0, 0, 0);
348  
349         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->to_field,     1,2,0,1);
350         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->cc_field,     1,2,1,2);
351         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->bcc_field,    1,2,2,3);
352         gtk_table_attach_defaults (GTK_TABLE(header_table), priv->subject_field,1,2,3,4);
353
354         priv->msg_body = gtk_text_view_new ();
355         
356         main_vbox = gtk_vbox_new  (FALSE, 6);
357
358         priv->menubar = menubar_new (obj);
359         priv->toolbar = GTK_WIDGET(toolbar_new (obj));
360
361         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 0);
362         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);
363         gtk_box_pack_start (GTK_BOX(main_vbox), header_table, FALSE, FALSE, 6);
364         gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 6);
365
366         gtk_widget_show_all (GTK_WIDGET(main_vbox));
367         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
368 }
369         
370
371
372 static void
373 modest_edit_msg_window_finalize (GObject *obj)
374 {
375         ModestEditMsgWindowPrivate *priv;
376
377         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
378
379         g_object_unref (G_OBJECT(priv->conf));
380         priv->conf = NULL;
381
382         g_object_unref (G_OBJECT(priv->factory));
383         priv->factory = NULL;
384         
385         G_OBJECT_CLASS(parent_class)->finalize (obj);
386
387 }
388
389
390
391 static gboolean
392 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestEditMsgWindow *self)
393 {
394         save_settings (self);
395         return FALSE;
396 }
397
398
399 GtkWidget*
400 modest_edit_msg_window_new (ModestConf *conf, ModestWidgetFactory *factory,
401                             ModestEditType type, TnyMsgIface *msg)
402 {
403         GObject *obj;
404         ModestEditMsgWindowPrivate *priv;
405
406         g_return_val_if_fail (conf, NULL);
407         g_return_val_if_fail (factory, NULL);
408         g_return_val_if_fail (type >= 0 && type < MODEST_EDIT_TYPE_NUM, NULL);
409         g_return_val_if_fail (!(type==MODEST_EDIT_TYPE_NEW && msg), NULL); 
410         g_return_val_if_fail (!(type!=MODEST_EDIT_TYPE_NEW && !msg), NULL);     
411         
412         obj = g_object_new(MODEST_TYPE_EDIT_MSG_WINDOW, NULL);
413         priv = MODEST_EDIT_MSG_WINDOW_GET_PRIVATE(obj);
414
415         g_object_ref (G_OBJECT(conf));
416         priv->conf = conf;
417
418         g_object_ref (factory);
419         priv->factory = factory;
420
421         init_window (MODEST_EDIT_MSG_WINDOW(obj));
422
423         restore_settings (MODEST_EDIT_MSG_WINDOW(obj));
424         
425         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
426         gtk_window_set_icon  (GTK_WINDOW(obj),
427                               modest_icon_factory_get_icon (MODEST_APP_ICON));
428
429         g_signal_connect (G_OBJECT(obj), "delete-event",
430                           G_CALLBACK(on_delete_event), obj);
431         
432         return GTK_WIDGET (obj);
433 }