* all:
[modest] / src / modest-ui.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 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H*/
33
34 #include <glib/gi18n.h>
35 #include "modest-ui-priv.h"
36 #include "modest-ui.h"
37 #include "modest-ui-actions.h"
38 #include "modest-icon-names.h"
39 #include "modest-tny-platform-factory.h"
40 #include "modest-account-view-window.h"
41 #include "modest-main-window.h"
42 #include <modest-widget-memory.h>
43 #include <tny-error.h>
44 #include <tny-simple-list.h>
45
46 #define MODEST_UI_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
47                                        MODEST_TYPE_UI, \
48                                        ModestUIPrivate))
49
50 typedef struct _GetMsgAsyncHelper {
51         ModestMainWindow *main_window;
52         TnyIterator *iter;
53         GFunc func;
54         gpointer user_data;
55 } GetMsgAsyncHelper;
56
57 typedef enum _ReplyForwardAction {
58         ACTION_REPLY,
59         ACTION_REPLY_TO_ALL,
60         ACTION_FORWARD
61 } ReplyForwardAction;
62
63 typedef struct _ReplyForwardHelper {
64         guint reply_forward_type;
65         ReplyForwardAction action;
66         gchar *from;
67 } ReplyForwardHelper;
68
69 /* globals */
70 static GObjectClass *parent_class = NULL;
71
72 /* 'private'/'protected' functions */
73 static void   modest_ui_class_init     (ModestUIClass *klass);
74 static void   modest_ui_init           (ModestUI *obj);
75 static void   modest_ui_finalize       (GObject *obj);
76
77 static void   register_stock_icons        ();
78 static void   connect_signals             (ModestUI *self);
79 /* static GtkUIManager *create_ui_manager (); */
80
81 static void   reply_forward_func (gpointer data, gpointer user_data);
82 static void   read_msg_func      (gpointer data, gpointer user_data);
83 static void   get_msg_cb         (TnyFolder *folder, 
84                                   TnyMsg *msg, 
85                                   GError **err, 
86                                   gpointer user_data);
87
88 static void   reply_forward      (GtkWidget *widget,
89                                   ReplyForwardAction action,
90                                   ModestMainWindow *main_window);
91
92 static void  _modest_ui_actions_on_password_requested   (ModestTnyAccountStore *account_store, 
93                                                          const gchar* account_name,
94                                                          gchar **password, 
95                                                          gboolean *cancel, 
96                                                          gboolean *remember, 
97                                                          ModestMainWindow *main_window);
98
99 GType
100 modest_ui_get_type (void)
101 {
102         static GType my_type = 0;
103         if (!my_type) {
104                 static const GTypeInfo my_info = {
105                         sizeof(ModestUIClass),
106                         NULL,           /* base init */
107                         NULL,           /* base finalize */
108                         (GClassInitFunc) modest_ui_class_init,
109                         NULL,           /* class finalize */
110                         NULL,           /* class data */
111                         sizeof(ModestUI),
112                         1,              /* n_preallocs */
113                         (GInstanceInitFunc) modest_ui_init,
114                         NULL
115                 };
116                 my_type = g_type_register_static (G_TYPE_OBJECT,
117                                                   "ModestUI",
118                                                   &my_info, 0);
119         }
120         return my_type;
121 }
122
123
124 static void
125 modest_ui_class_init (ModestUIClass *klass)
126 {
127         GObjectClass *gobject_class;
128         gobject_class = (GObjectClass*) klass;
129
130         parent_class            = g_type_class_peek_parent (klass);
131         gobject_class->finalize = modest_ui_finalize;
132
133         g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
134
135 }
136
137
138 static void
139 modest_ui_init (ModestUI *obj)
140 {
141         ModestUIPrivate *priv;
142
143         priv = MODEST_UI_GET_PRIVATE(obj);
144
145         priv->widget_factory = NULL;
146         priv->main_window    = NULL;
147         priv->account_store  = NULL;
148 }
149
150
151 static void
152 modest_ui_finalize (GObject *obj)
153 {
154         
155         ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
156         
157         if (priv->widget_factory) {
158                 g_object_unref (G_OBJECT(priv->widget_factory));
159                 priv->widget_factory = NULL;
160         }
161
162         if (priv->ui_manager) {
163                 g_object_unref (G_OBJECT(priv->ui_manager));
164                 priv->ui_manager = NULL;
165         }
166         
167         G_OBJECT_CLASS(parent_class)->finalize (obj);
168 }
169
170
171 ModestUI*
172 modest_ui_new (TnyAccountStore *account_store)
173 {
174         GObject *obj;
175         ModestUIPrivate *priv;
176         TnyPlatformFactory *fact;
177         ModestAccountMgr *account_mgr;
178
179         obj  = g_object_new(MODEST_TYPE_UI, NULL);
180         priv = MODEST_UI_GET_PRIVATE(obj);
181
182         /* Get the platform-dependent instances */
183         fact = modest_tny_platform_factory_get_instance ();
184         
185         priv->account_store = account_store;
186
187         account_mgr = modest_tny_platform_factory_get_account_mgr_instance
188                 (MODEST_TNY_PLATFORM_FACTORY(fact));
189         if (!account_mgr) {
190                 g_printerr ("modest: could not create ModestAccountMgr instance\n");
191                 g_object_unref (obj);
192                 return NULL;
193         }
194
195         priv->widget_factory = modest_widget_factory_new ();
196         if (!priv->widget_factory) {
197                 g_printerr ("modest: could not initialize widget factory\n");
198                 return NULL;
199         }
200
201         /* Register our own icons as stock icons in order to
202            use them with the UI manager */
203         register_stock_icons ();
204                 
205         return MODEST_UI(obj);
206 }
207
208 static gboolean
209 on_main_window_destroy (GtkObject *widget, ModestUI *self)
210 {
211         /* FIXME: check if there any viewer/editing windows opened */
212         gtk_main_quit ();
213         return FALSE;
214 }
215
216
217 ModestWindow *
218 modest_ui_main_window (ModestUI *self)
219 {
220         ModestUIPrivate *priv;
221
222         g_return_val_if_fail (self, NULL);
223         priv = MODEST_UI_GET_PRIVATE(self);
224
225         if (!priv->main_window) {
226
227                 /* Create main window */
228                 priv->main_window = modest_main_window_new (priv->widget_factory,
229                                                             priv->account_store);
230
231                 connect_signals (self);
232         }
233                 
234         if (!priv->main_window)
235                 g_printerr ("modest: could not create main window\n");
236         
237         return priv->main_window;
238 }
239
240 ModestWindow *
241 modest_ui_edit_window (ModestUI *self, ModestEditType edit_type)
242 {
243         ModestUIPrivate *priv;
244         ModestWindow *edit_window;
245
246         g_return_val_if_fail (self, NULL);
247         priv = MODEST_UI_GET_PRIVATE(self);
248
249         /* Create window */
250         edit_window = modest_edit_msg_window_new (priv->widget_factory, 
251                                                   priv->account_store,
252                                                   edit_type);
253         
254         /* Connect Edit Window signals */
255 /*      connect_edit_window_signals (self); */
256                 
257         return edit_window;
258 }
259
260 /* 
261  *  This function registers our custom toolbar icons, so they can be
262  *  themed. The idea of this function was taken from the gtk-demo
263  */
264 static void
265 register_stock_icons ()
266 {
267         static gboolean registered = FALSE;
268   
269         if (!registered) {
270                 GdkPixbuf *pixbuf;
271                 GtkIconFactory *factory;
272                 gint i;
273
274                 static GtkStockItem items[] = {
275                         { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
276                         { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
277                         { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
278                         { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
279                         { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
280                         { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
281                         { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
282                         { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
283                         { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
284                         { MODEST_STOCK_STOP, "stop", 0, 0, NULL }
285                 };
286       
287                 static gchar *items_names [] = {
288                         MODEST_TOOLBAR_ICON_MAIL_SEND,
289                         MODEST_TOOLBAR_ICON_NEW_MAIL,           
290                         MODEST_TOOLBAR_ICON_SEND_RECEIVE,
291                         MODEST_TOOLBAR_ICON_REPLY,      
292                         MODEST_TOOLBAR_ICON_REPLY_ALL,
293                         MODEST_TOOLBAR_ICON_FORWARD,
294                         MODEST_TOOLBAR_ICON_DELETE,
295                         MODEST_TOOLBAR_ICON_NEXT,
296                         MODEST_TOOLBAR_ICON_PREV,
297                         MODEST_TOOLBAR_ICON_STOP
298                 };
299
300                 registered = TRUE;
301
302                 /* Register our stock items */
303                 gtk_stock_add (items, G_N_ELEMENTS (items));
304       
305                 /* Add our custom icon factory to the list of defaults */
306                 factory = gtk_icon_factory_new ();
307                 gtk_icon_factory_add_default (factory);
308
309                 /* Register icons to accompany stock items */
310                 for (i = 0; i < G_N_ELEMENTS (items); i++) {
311                         pixbuf = NULL;
312                         pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
313
314                         if (pixbuf != NULL) {
315                                 GtkIconSet *icon_set;
316                                 GdkPixbuf *transparent;
317
318                                 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
319
320                                 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
321                                 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
322                                 gtk_icon_set_unref (icon_set);
323                                 g_object_unref (pixbuf);
324                                 g_object_unref (transparent);
325                         }
326                         else
327                                 g_warning ("failed to load %s icon", items_names[i]);
328                 }
329                 /* Drop our reference to the factory, GTK will hold a reference. */
330                 g_object_unref (factory);
331         }
332 }
333
334 /* FIXME: uninit these as well */
335 static void
336 connect_signals (ModestUI *self)
337 {
338         TnyDevice *device;
339         ModestUIPrivate *priv;
340         ModestFolderView *folder_view;
341         ModestHeaderView *header_view;
342         ModestMsgView *msg_view;
343         GtkWidget *toggle;
344         
345         priv = MODEST_UI_GET_PRIVATE(self);
346
347         folder_view = modest_widget_factory_get_folder_view (priv->widget_factory);
348         header_view = modest_widget_factory_get_header_view (priv->widget_factory);
349         msg_view    = modest_widget_factory_get_msg_preview (priv->widget_factory);
350         toggle      = modest_widget_factory_get_online_toggle (priv->widget_factory);
351         device      = tny_account_store_get_device (priv->account_store);
352
353         /* folder view */
354         g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
355                           G_CALLBACK(_modest_ui_actions_on_folder_selection_changed),
356                           priv->main_window);   
357         /* header view */
358         g_signal_connect (G_OBJECT(header_view), "status_update",
359                           G_CALLBACK(_modest_ui_actions_on_header_status_update), 
360                           priv->main_window);
361         g_signal_connect (G_OBJECT(header_view), "header_selected",
362                           G_CALLBACK(_modest_ui_actions_on_header_selected), 
363                           priv->main_window);
364         g_signal_connect (G_OBJECT(header_view), "item_not_found",
365                           G_CALLBACK(_modest_ui_actions_on_item_not_found), 
366                           priv->main_window);
367         /* msg preview */
368         g_signal_connect (G_OBJECT(msg_view), "link_clicked",
369                           G_CALLBACK(_modest_ui_actions_on_msg_link_clicked), 
370                           priv->main_window);
371         g_signal_connect (G_OBJECT(msg_view), "link_hover",
372                           G_CALLBACK(_modest_ui_actions_on_msg_link_hover), 
373                           priv->main_window);
374         g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
375                           G_CALLBACK(_modest_ui_actions_on_msg_attachment_clicked), 
376                           priv->main_window);
377
378         /* Device */
379         g_signal_connect (G_OBJECT(device), "connection_changed",
380                           G_CALLBACK(_modest_ui_actions_on_connection_changed), 
381                           priv->main_window);
382         g_signal_connect (G_OBJECT(toggle), "toggled",
383                           G_CALLBACK(_modest_ui_actions_on_online_toggle_toggled),
384                           priv->main_window);
385                 
386         /* account store */
387         g_signal_connect (G_OBJECT (priv->account_store), 
388                           "password_requested",
389                           G_CALLBACK(_modest_ui_actions_on_password_requested),
390                           priv->main_window);
391
392         /* Destroy window */
393         g_signal_connect (G_OBJECT(priv->main_window), 
394                           "destroy",
395                           G_CALLBACK(on_main_window_destroy), 
396                           NULL);
397
398
399         /* Init toggle in correct state */
400         _modest_ui_actions_on_connection_changed (device,
401                                                  tny_device_is_online (device),
402                                                  MODEST_MAIN_WINDOW (priv->main_window));
403 }
404
405
406 /* ***************************************************************** */
407 /*                M O D E S T    U I    A C T I O N S                */
408 /* ***************************************************************** */
409 void     
410 _modest_ui_actions_on_about (GtkWidget *widget, 
411                              ModestMainWindow *main_window)
412 {
413         GtkWidget *about;
414         const gchar *authors[] = {
415                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
416                 NULL
417         };
418         about = gtk_about_dialog_new ();
419         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
420         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
421         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
422                                         _("Copyright (c) 2006, Nokia Corporation\n"
423                                           "All rights reserved."));
424         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
425                                        _("a modest e-mail client\n\n"
426                                          "design and implementation: Dirk-Jan C. Binnema\n"
427                                          "contributions from the fine people at KernelConcepts and Igalia\n"
428                                          "uses the tinymail email framework written by Philip van Hoof"));
429         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
430         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
431
432         gtk_dialog_run (GTK_DIALOG (about));
433         gtk_widget_destroy(about);
434 }
435
436 void
437 _modest_ui_actions_on_delete (GtkWidget *widget, 
438                              ModestMainWindow *main_window)
439 {
440         ModestWidgetFactory *widget_factory;
441         ModestHeaderView *header_view;
442         TnyList *header_list;
443         TnyIterator *iter;
444         GtkTreeModel *model;
445
446         widget_factory = modest_main_window_get_widget_factory (main_window);
447         header_view = modest_widget_factory_get_header_view (widget_factory);
448         header_list = modest_header_view_get_selected_headers (header_view);
449         g_object_unref (G_OBJECT(widget_factory));
450         
451         if (header_list) {
452                 iter = tny_list_create_iterator (header_list);
453                 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
454                 if (GTK_IS_TREE_MODEL_SORT (model))
455                         model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
456                 do {
457                         TnyHeader *header;
458                         ModestMailOperation *mail_op;
459
460                         header = TNY_HEADER (tny_iterator_get_current (iter));
461                         /* TODO: thick grain mail operation involving
462                            a list of objects. Composite pattern ??? */
463                         mail_op = modest_mail_operation_new ();
464
465                         /* TODO: add confirmation dialog */
466
467                         /* Move to trash */
468                         modest_mail_operation_remove_msg (mail_op, header, TRUE);
469
470                         /* Remove from tree model */
471                         if (modest_mail_operation_get_status (mail_op) == 
472                             MODEST_MAIL_OPERATION_STATUS_SUCCESS)
473                                 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
474                         else {
475                                 /* TODO: error handling management */
476                                 const GError *error;
477                                 error = modest_mail_operation_get_error (mail_op);
478                                 g_warning (error->message);
479                         }
480
481                         g_object_unref (G_OBJECT (mail_op));
482                         g_object_unref (header);
483                         tny_iterator_next (iter);
484
485                 } while (!tny_iterator_is_done (iter));
486         }
487 }
488
489 void
490 _modest_ui_actions_on_quit (GtkWidget *widget, 
491                            ModestMainWindow *main_window)
492 {
493         /* FIXME: save size of main window */
494 /*      save_sizes (main_window); */
495         gtk_widget_destroy (GTK_WIDGET (main_window));
496 }
497
498 void
499 _modest_ui_actions_on_accounts (GtkWidget *widget, 
500                                ModestMainWindow *main_window)
501 {
502         GtkWidget *account_win;
503         ModestWidgetFactory *widget_factory;
504
505         widget_factory = modest_main_window_get_widget_factory (main_window);
506         account_win = modest_account_view_window_new (widget_factory);
507         g_object_unref (G_OBJECT(widget_factory));
508
509         gtk_window_set_transient_for (GTK_WINDOW (account_win),
510                                       GTK_WINDOW (main_window));
511                                       
512         gtk_widget_show (account_win);
513 }
514
515 void
516 _modest_ui_actions_on_new_msg (GtkWidget *widget, 
517                                ModestMainWindow *main_window)
518 {
519         ModestWindow *msg_win;
520         ModestWidgetFactory *widget_factory;
521         TnyAccountStore *account_store;
522
523         widget_factory = modest_main_window_get_widget_factory (main_window);
524         account_store = modest_main_window_get_account_store (main_window);
525         msg_win = modest_edit_msg_window_new (widget_factory, 
526                                               account_store,
527                                               MODEST_EDIT_TYPE_NEW);
528         g_object_unref (G_OBJECT (widget_factory));
529         g_object_unref (G_OBJECT (account_store));
530
531         gtk_widget_show (GTK_WIDGET (msg_win));
532 }
533
534 static void
535 reply_forward_func (gpointer data, gpointer user_data)
536 {
537         ModestWidgetFactory *widget_factory;
538         TnyHeader *new_header;
539         TnyMsg *msg, *new_msg;
540         TnyAccountStore *account_store;
541         GetMsgAsyncHelper *helper;
542         ReplyForwardHelper *rf_helper;
543         GtkWindow *msg_win;
544         ModestEditType edit_type;
545
546         msg = TNY_MSG (data);
547         helper = (GetMsgAsyncHelper *) user_data;
548         rf_helper = (ReplyForwardHelper *) helper->user_data;
549
550         /* Create reply mail */
551         switch (rf_helper->action) {
552         case ACTION_REPLY:
553                 new_msg = 
554                         modest_mail_operation_create_reply_mail (msg, 
555                                                                  rf_helper->from, 
556                                                                  rf_helper->reply_forward_type,
557                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
558         case ACTION_REPLY_TO_ALL:
559                 new_msg = 
560                         modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
561                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
562                 edit_type = MODEST_EDIT_TYPE_REPLY;
563                 break;
564         case ACTION_FORWARD:
565                 new_msg = 
566                         modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
567                 edit_type = MODEST_EDIT_TYPE_FORWARD;
568                 break;
569         default:
570                 g_return_if_reached ();
571         }
572
573         /* Set from */
574         new_header = tny_msg_get_header (new_msg);
575         tny_header_set_from (new_header, rf_helper->from);
576         g_object_unref (G_OBJECT (new_header));
577                 
578         /* Show edit window */
579         widget_factory = modest_main_window_get_widget_factory (helper->main_window);
580         account_store = modest_main_window_get_account_store (helper->main_window);
581         msg_win = modest_edit_msg_window_new (widget_factory, 
582                                               account_store,
583                                               MODEST_EDIT_TYPE_NEW);
584         g_object_unref (G_OBJECT (widget_factory));
585         g_object_unref (G_OBJECT (account_store));
586         modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
587                                         new_msg);
588         gtk_widget_show (GTK_WIDGET (msg_win));
589         
590         /* Clean */
591         g_object_unref (G_OBJECT (new_msg));
592         g_free (rf_helper->from);
593         g_slice_free (ReplyForwardHelper, rf_helper);
594 }
595
596 /*
597  * Common code for the reply and forward actions
598  */
599 static void
600 reply_forward (GtkWidget *widget,
601                ReplyForwardAction action,
602                ModestMainWindow *main_window)
603 {
604         ModestHeaderView *header_view;
605         ModestWidgetFactory *widget_factory;
606         TnyList *header_list;
607         guint reply_forward_type;
608         ModestConf *conf;
609         TnyPlatformFactory *plat_factory;
610         TnyHeader *header;
611         TnyFolder *folder;
612         gchar *from, *key;
613         GetMsgAsyncHelper *helper;
614         ReplyForwardHelper *rf_helper;
615
616         /* Get ModestConf */
617         plat_factory = modest_tny_platform_factory_get_instance ();
618         conf = modest_tny_platform_factory_get_conf_instance
619                 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
620
621         /* Get reply or forward type */
622         key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, 
623                                (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
624         reply_forward_type = modest_conf_get_int (conf, key, NULL);
625         g_free (key);
626
627         /* Get the list of headers */
628         widget_factory = modest_main_window_get_widget_factory (main_window);
629         header_view = modest_widget_factory_get_header_view (widget_factory);
630         header_list = modest_header_view_get_selected_headers (header_view);
631         g_object_unref (G_OBJECT(widget_factory));
632
633         if (!header_list)
634                 return;
635
636         /* We assume that we can only select messages of the
637            same folder and that we reply all of them from the
638            same account. In fact the interface currently only
639            allows single selection */
640
641         /* TODO: get the from string from account */
642         from = g_strdup ("Invalid");
643         
644         /* Fill helpers */
645         rf_helper = g_slice_new0 (ReplyForwardHelper);
646         rf_helper->reply_forward_type = reply_forward_type;
647         rf_helper->action = action;
648         rf_helper->from = from;
649         
650         helper = g_slice_new0 (GetMsgAsyncHelper);
651         helper->main_window = main_window;
652         helper->func = reply_forward_func;
653         helper->iter = tny_list_create_iterator (header_list);
654         helper->user_data = rf_helper;
655         
656         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
657         folder = tny_header_get_folder (header);
658         
659         /* The callback will call it per each header */
660         tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
661         
662         /* Clean */
663         g_object_unref (G_OBJECT (folder));
664 }
665
666 void
667 _modest_ui_actions_on_reply (GtkWidget *widget,
668                             ModestMainWindow *main_window)
669 {
670         reply_forward (widget, ACTION_REPLY, main_window);
671 }
672
673 void
674 _modest_ui_actions_on_forward (GtkWidget *widget,
675                               ModestMainWindow *main_window)
676 {
677         reply_forward (widget, ACTION_FORWARD, main_window);
678 }
679
680 void
681 _modest_ui_actions_on_reply_all (GtkWidget *widget,
682                                 ModestMainWindow *main_window)
683 {
684         reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
685 }
686
687 void 
688 _modest_ui_actions_on_next (GtkWidget *widget, 
689                            ModestMainWindow *main_window)
690 {
691         ModestHeaderView *header_view;
692         ModestWidgetFactory *widget_factory;
693
694         widget_factory = modest_main_window_get_widget_factory (main_window);
695         header_view = modest_widget_factory_get_header_view (widget_factory);
696         g_object_unref (G_OBJECT(widget_factory));
697
698         modest_header_view_select_next (header_view);
699 }
700
701 void
702 _modest_ui_actions_toggle_view (GtkWidget *widget,
703                                 ModestMainWindow *main_window)
704 {
705         ModestHeaderView *header_view;
706         ModestWidgetFactory *widget_factory;
707         ModestConf *conf;
708         TnyPlatformFactory *plat_factory;
709
710         /* Get ModestConf */
711         plat_factory = modest_tny_platform_factory_get_instance ();
712         conf = modest_tny_platform_factory_get_conf_instance
713                 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
714         widget_factory = modest_main_window_get_widget_factory (main_window);
715         header_view = modest_widget_factory_get_header_view (widget_factory);
716         g_object_unref (G_OBJECT(widget_factory));
717
718         /* what is saved/restored is depending on the style; thus; we save with
719          * old style, then update the style, and restore for this new style*/
720         modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
721         
722         if (modest_header_view_get_style (header_view) == MODEST_HEADER_VIEW_STYLE_DETAILS)
723                 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
724         else
725                 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_DETAILS);
726
727         modest_widget_memory_restore (conf, G_OBJECT(header_view), "header-view");
728 }
729
730
731
732 /*
733  * Marks a message as read and passes it to the msg preview widget
734  */
735 static void
736 read_msg_func (gpointer data, gpointer user_data)
737 {
738         ModestMsgView *msg_view;
739         ModestWidgetFactory *widget_factory;
740         TnyMsg *msg;
741         TnyHeader *header;
742         GetMsgAsyncHelper *helper;
743         TnyHeaderFlags header_flags;
744
745         msg = TNY_MSG (data);
746         helper = (GetMsgAsyncHelper *) user_data;
747
748         /* mark message as seen; _set_flags crashes, bug in tinymail? */
749         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
750         header_flags = tny_header_get_flags (header);
751         tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
752         g_object_unref (G_OBJECT (header));
753
754         /* Set message on msg view */
755         widget_factory = modest_main_window_get_widget_factory (helper->main_window);
756         msg_view = modest_widget_factory_get_msg_preview (widget_factory);
757         g_object_unref (G_OBJECT(widget_factory));
758         modest_msg_view_set_message (msg_view, msg);
759 }
760
761 /*
762  * This function is a generic handler for the tny_folder_get_msg_async
763  * call. It expects as user_data a #GetMsgAsyncHelper. This helper
764  * contains a user provided function that is called inside this
765  * method. This will allow us to use this callback in many different
766  * places. This callback performs the common actions for the
767  * get_msg_async call, more specific actions will be done by the user
768  * function
769  */
770 static void
771 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
772 {
773         GetMsgAsyncHelper *helper;
774
775         helper = (GetMsgAsyncHelper *) user_data;
776
777         if (*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) {
778                 ModestHeaderView *header_view;
779                 ModestWidgetFactory *widget_factory;
780
781                 widget_factory = modest_main_window_get_widget_factory (helper->main_window);
782                 header_view = modest_widget_factory_get_header_view (widget_factory);
783                 g_object_unref (G_OBJECT (widget_factory));
784                 _modest_ui_actions_on_item_not_found (header_view, 
785                                                       MODEST_ITEM_TYPE_MESSAGE, 
786                                                       helper->main_window);
787                 return;
788         }
789
790         if (!msg)
791                 return;
792
793         /* Call user function */
794         helper->func (msg, user_data);
795
796         /* Process next element (if exists) */
797         tny_iterator_next (helper->iter);
798         if (tny_iterator_is_done (helper->iter)) {
799                 TnyList *headers;
800                 headers = tny_iterator_get_list (helper->iter);
801                 /* Free resources */
802                 g_object_unref (G_OBJECT (headers));
803                 g_object_unref (G_OBJECT (helper->iter));
804                 g_slice_free (GetMsgAsyncHelper, helper);
805         } else
806                 tny_folder_get_msg_async (folder, 
807                                           TNY_HEADER (tny_iterator_get_current (helper->iter)), 
808                                           get_msg_cb, helper);
809 }
810
811 void 
812 _modest_ui_actions_on_header_selected (ModestHeaderView *folder_view, 
813                                       TnyHeader *header,
814                                       ModestMainWindow *main_window)
815 {
816         TnyFolder *folder;
817         GetMsgAsyncHelper *helper;
818         TnyList *list;
819
820         /* when there's no header, clear the msgview */
821         if (!header) {
822                 ModestMsgView *msg_view;
823                 ModestWidgetFactory *widget_factory;
824                 widget_factory = modest_main_window_get_widget_factory (main_window);
825                 msg_view       = modest_widget_factory_get_msg_preview (widget_factory);
826                 modest_msg_view_set_message (msg_view, NULL);
827                 return;
828         }
829
830         folder = tny_header_get_folder (TNY_HEADER(header));
831
832         /* Create list */
833         list = tny_simple_list_new ();
834         tny_list_prepend (list, G_OBJECT (header));
835
836         /* Fill helper data */
837         helper = g_slice_new0 (GetMsgAsyncHelper);
838         helper->main_window = main_window;
839         helper->iter = tny_list_create_iterator (list);
840         helper->func = read_msg_func;
841
842         tny_folder_get_msg_async (TNY_FOLDER(folder),
843                                   header, get_msg_cb,
844                                   helper);
845
846         /* Frees */
847         g_object_unref (G_OBJECT (folder));
848 }
849
850 void 
851 _modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
852                                                TnyFolder *folder, 
853                                                gboolean selected,
854                                                ModestMainWindow *main_window)
855 {
856         GtkLabel *folder_info_label;
857         TnyPlatformFactory *factory;
858         gchar *txt;     
859         ModestConf *conf;
860         ModestHeaderView *header_view;
861         ModestWidgetFactory *widget_factory;
862
863         widget_factory = modest_main_window_get_widget_factory (main_window);
864         folder_info_label = 
865                 GTK_LABEL (modest_widget_factory_get_folder_info_label (widget_factory));
866
867         if (!folder) {
868                 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
869                 return;
870         }
871
872         factory = modest_tny_platform_factory_get_instance ();
873         header_view = modest_widget_factory_get_header_view (widget_factory);
874         conf = modest_tny_platform_factory_get_conf_instance
875                 (MODEST_TNY_PLATFORM_FACTORY(factory));
876         g_object_unref (G_OBJECT (widget_factory));
877
878         if (!selected) { /* the folder was unselected; save it's settings  */
879                 modest_widget_memory_save (conf, G_OBJECT (header_view),
880                                            "header-view");
881                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
882                 modest_header_view_set_folder (header_view, NULL);
883         } else {  /* the folder was selected */
884                 guint num, unread;
885                 gchar *title;
886                 num    = tny_folder_get_all_count    (folder);
887                 unread = tny_folder_get_unread_count (folder);
888
889                 title = g_strdup_printf ("Modest: %s",
890                                          tny_folder_get_name (folder));
891                 
892                 gtk_window_set_title (GTK_WINDOW(main_window), title);
893                 g_free (title);
894
895                 txt = g_strdup_printf (_("%d %s, %d unread"),
896                                        num, num==1 ? _("item") : _("items"), unread);           
897                 gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
898                 g_free (txt);
899                         
900                 modest_header_view_set_folder (header_view, folder);
901                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
902                                               "header-view");
903         }
904 }
905
906 void
907 _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store, 
908                                          const gchar* account_name,
909                                          gchar **password, 
910                                          gboolean *cancel, 
911                                          gboolean *remember, 
912                                          ModestMainWindow *main_window)
913 {
914         gchar *txt;
915         GtkWidget *dialog, *entry, *remember_pass_check;
916
917         dialog = gtk_dialog_new_with_buttons (_("Password requested"),
918                                               GTK_WINDOW (main_window),
919                                               GTK_DIALOG_MODAL,
920                                               GTK_STOCK_CANCEL,
921                                               GTK_RESPONSE_REJECT,
922                                               GTK_STOCK_OK,
923                                               GTK_RESPONSE_ACCEPT,
924                                               NULL);
925
926         txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
927         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
928                             FALSE, FALSE, 0);
929         g_free (txt);
930
931         entry = gtk_entry_new_with_max_length (40);
932         gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
933         gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
934         
935         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
936                             TRUE, FALSE, 0);    
937
938         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
939         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
940                             TRUE, FALSE, 0);
941
942         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
943         
944         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
945                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
946                 *cancel   = FALSE;
947         } else {
948                 *password = NULL;
949                 *cancel   = TRUE;
950         }
951
952         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
953                 *remember = TRUE;
954         else
955                 *remember = FALSE;
956
957         gtk_widget_destroy (dialog);
958
959         while (gtk_events_pending ())
960                 gtk_main_iteration ();
961 }
962
963 /****************************************************/
964 /*
965  * below some stuff to clearup statusbar messages after 1,5 seconds....
966  */
967 typedef struct {
968         GtkWidget *status_bar;
969         GtkWidget *progress_bar;
970         guint     msg_id;
971 } StatusRemoveData;
972
973 static gboolean
974 on_statusbar_remove_msg (StatusRemoveData *data)
975 {
976         /* we need to test types, as this callback maybe called after the
977          * widgets have been destroyed
978          */
979         if (GTK_IS_STATUSBAR(data->status_bar)) 
980                 gtk_statusbar_remove (GTK_STATUSBAR(data->status_bar),
981                                       0, data->msg_id);
982         if (GTK_IS_PROGRESS_BAR(data->progress_bar))
983                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(data->progress_bar),
984                                                1.0);
985         g_free (data);
986         return FALSE;
987 }
988
989 static void
990 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
991 {
992         guint id;
993         StatusRemoveData *data;
994         GtkWidget *status_bar, *progress_bar;
995         
996         if (!msg)
997                 return;
998
999         progress_bar = modest_widget_factory_get_progress_bar (factory);
1000         status_bar   = modest_widget_factory_get_status_bar (factory);
1001         
1002         id = gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1003
1004         data = g_new (StatusRemoveData, 1);
1005         data->status_bar   = status_bar;
1006         data->progress_bar = progress_bar;
1007         data->msg_id     = id;
1008
1009         g_timeout_add (1500, (GSourceFunc)on_statusbar_remove_msg, data);
1010 }
1011 /****************************************************************************/
1012
1013 void
1014 _modest_ui_actions_on_connection_changed (TnyDevice *device, 
1015                                          gboolean online,
1016                                          ModestMainWindow *main_window)
1017 {
1018         GtkWidget *online_toggle;
1019         ModestHeaderView *header_view;
1020         ModestWidgetFactory *widget_factory;
1021         
1022         widget_factory = modest_main_window_get_widget_factory (main_window);
1023         header_view   = modest_widget_factory_get_header_view (widget_factory);
1024         online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
1025
1026         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1027                                       online);
1028         gtk_button_set_label (GTK_BUTTON(online_toggle),
1029                               online ? _("Online") : _("Offline"));
1030
1031         statusbar_push (widget_factory, 0, 
1032                         online ? _("Modest went online") : _("Modest went offline"));
1033         g_object_unref (G_OBJECT (widget_factory));
1034
1035         /* If Modest has became online and the header view has a
1036            header selected then show it */
1037         if (online) {
1038                 GtkTreeSelection *selected;
1039
1040                 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1041                 _modest_header_view_change_selection (selected, header_view);
1042         }
1043 }
1044
1045 void
1046 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1047                                              ModestMainWindow *main_window)
1048 {
1049         gboolean online;
1050         TnyDevice *device;
1051         TnyPlatformFactory *factory;
1052         TnyAccountStore *account_store;
1053
1054         /* Get device. Do not ask the platform factory for it, because
1055            it returns always a new one */
1056         factory = modest_tny_platform_factory_get_instance ();
1057         account_store = tny_platform_factory_new_account_store (factory);
1058         device = tny_account_store_get_device (account_store);
1059
1060         online  = gtk_toggle_button_get_active (toggle);
1061
1062         if (online)
1063                 tny_device_force_online (device);
1064         else
1065                 tny_device_force_offline (device);
1066 }
1067
1068 void 
1069 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1070                                      ModestItemType type,
1071                                      ModestMainWindow *main_window)
1072 {
1073         GtkWidget *dialog;
1074         gchar *txt, *item;
1075         gboolean online;
1076         TnyDevice *device;
1077         TnyPlatformFactory *factory;
1078         TnyAccountStore *account_store;
1079
1080         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1081
1082         /* Get device. Do not ask the platform factory for it, because
1083            it returns always a new one */
1084         factory = modest_tny_platform_factory_get_instance ();
1085         account_store = tny_platform_factory_new_account_store (factory);
1086         device = tny_account_store_get_device (account_store);
1087         
1088         gdk_threads_enter ();
1089         online = tny_device_is_online (device);
1090
1091         if (online) {
1092                 /* already online -- the item is simply not there... */
1093                 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1094                                                  GTK_DIALOG_MODAL,
1095                                                  GTK_MESSAGE_WARNING,
1096                                                  GTK_BUTTONS_OK,
1097                                                  _("The %s you selected cannot be found"),
1098                                                  item);
1099                 gtk_dialog_run (GTK_DIALOG(dialog));
1100         } else {
1101
1102                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1103                                                       GTK_WINDOW (main_window),
1104                                                       GTK_DIALOG_MODAL,
1105                                                       GTK_STOCK_CANCEL,
1106                                                       GTK_RESPONSE_REJECT,
1107                                                       GTK_STOCK_OK,
1108                                                       GTK_RESPONSE_ACCEPT,
1109                                                       NULL);
1110
1111                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1112                                          "Do you want to get online?"), item);
1113                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1114                                     gtk_label_new (txt), FALSE, FALSE, 0);
1115                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1116                 g_free (txt);
1117
1118                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1119                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1120                         tny_device_force_online (device);
1121                 }
1122         }
1123         gtk_widget_destroy (dialog);
1124         gdk_threads_leave ();
1125 }
1126
1127
1128
1129 void
1130 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
1131                                             const gchar *msg,
1132                                             gint num, 
1133                                             gint total, 
1134                                             ModestMainWindow *main_window)
1135 {
1136         GtkWidget *progress_bar;
1137         ModestWidgetFactory *widget_factory;
1138
1139         widget_factory = modest_main_window_get_widget_factory (main_window);
1140         progress_bar = modest_widget_factory_get_progress_bar (widget_factory);
1141
1142         if (total != 0)
1143                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1144                                                (gdouble)num/(gdouble)total);
1145         else
1146                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1147
1148         statusbar_push (widget_factory, 0, msg);
1149
1150         /* Free */
1151         g_object_unref (G_OBJECT (widget_factory));
1152 }
1153
1154
1155
1156 void
1157 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, 
1158                                       const gchar* link,
1159                                       ModestMainWindow *main_window)
1160 {
1161         ModestWidgetFactory *widget_factory;
1162
1163         widget_factory = modest_main_window_get_widget_factory (main_window);
1164         statusbar_push (widget_factory, 0, link);
1165         g_object_unref (G_OBJECT (widget_factory));     
1166
1167         /* TODO: do something */
1168 }       
1169
1170
1171 void
1172 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, 
1173                                         const gchar* link,
1174                                         ModestMainWindow *main_window)
1175 {
1176         gchar *msg;
1177         ModestWidgetFactory *widget_factory;
1178
1179         msg = g_strdup_printf (_("Opening %s..."), link);
1180         widget_factory = modest_main_window_get_widget_factory (main_window);
1181         statusbar_push (widget_factory, 0, msg);
1182
1183         g_object_unref (G_OBJECT (widget_factory));     
1184
1185         g_free (msg);
1186
1187         /* TODO: do something */
1188 }
1189
1190 void
1191 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, 
1192                                               int index,
1193                                               ModestMainWindow *main_window)
1194 {
1195         gchar *msg;
1196         ModestWidgetFactory *widget_factory;
1197         
1198         msg = g_strdup_printf (_("Opening attachment %d..."), index);
1199         widget_factory = modest_main_window_get_widget_factory (main_window);
1200         statusbar_push (widget_factory, 0, msg);
1201         
1202         g_free (msg);
1203         g_object_unref (G_OBJECT (widget_factory));
1204         /* TODO: do something */
1205 }
1206
1207 void
1208 _modest_ui_actions_on_send (GtkWidget *widget, 
1209                             ModestEditMsgWindow *edit_window)
1210 {
1211         TnyTransportAccount *transport_account;
1212         ModestMailOperation *mail_operation;
1213         MsgData *data;
1214
1215         data = modest_edit_msg_window_get_msg_data (edit_window);
1216
1217         /* FIXME: Code added just for testing. The final version will
1218            use the send queue provided by tinymail and some
1219            classifier */
1220         {
1221                 TnyList *accounts;
1222                 TnyIterator *iter;
1223                 TnyAccountStore *account_store;
1224
1225                 accounts = TNY_LIST(tny_simple_list_new ());
1226                 account_store = modest_edit_msg_window_get_account_store (edit_window);
1227                 tny_account_store_get_accounts (account_store, accounts,
1228                                                 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1229                 g_object_unref (G_OBJECT (account_store));
1230
1231                 iter = tny_list_create_iterator(accounts);
1232                 tny_iterator_first (iter);
1233                 if (tny_iterator_is_done (iter)) {
1234                         /* FIXME: Add error handling through mail operation */
1235                         g_printerr("modest: no transport accounts defined\n");
1236                         modest_edit_msg_window_free_msg_data (edit_window, data);
1237                         return;
1238                 }
1239                 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1240                 g_object_ref (transport_account);
1241
1242                 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1243                 g_object_unref (G_OBJECT (accounts));
1244                 g_object_unref (G_OBJECT (iter));
1245         }
1246
1247         mail_operation = modest_mail_operation_new ();
1248
1249         modest_mail_operation_send_new_mail (mail_operation,
1250                                              transport_account,
1251                                              data->from, 
1252                                              data->to, 
1253                                              data->cc, 
1254                                              data->bcc,
1255                                              data->subject, 
1256                                              data->body, 
1257                                              NULL);
1258         /* Frees */
1259         g_object_unref (G_OBJECT (mail_operation));
1260         g_object_unref (G_OBJECT (transport_account));
1261         modest_edit_msg_window_free_msg_data (edit_window, data);
1262
1263         /* Save settings and close the window */
1264         /* save_settings (edit_window) */
1265         gtk_widget_destroy (GTK_WIDGET (edit_window));
1266 }