* refactored account setup wizard (assistant), with specifics for transport/store
[modest] / src / gtk2 / modest-account-assistant.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-account-assistant.h"
31 #include "modest-store-widget.h"
32 #include "modest-transport-widget.h"
33
34 #include <string.h>
35
36 /* 'private'/'protected' functions */
37 static void       modest_account_assistant_class_init    (ModestAccountAssistantClass *klass);
38 static void       modest_account_assistant_init          (ModestAccountAssistant *obj);
39 static void       modest_account_assistant_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 _ModestAccountAssistantPrivate ModestAccountAssistantPrivate;
49 struct _ModestAccountAssistantPrivate {
50
51         ModestWidgetFactory *factory;
52         ModestAccountMgr *account_mgr;
53
54         GtkWidget *account_name;
55         GtkWidget *fullname;
56         GtkWidget *email;
57         
58         GtkWidget *store_widget;
59         GtkWidget *transport_widget;
60
61         GtkWidget *transport_holder;
62         GtkWidget *store_holder;        
63 };
64
65 #define MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
66                                                       MODEST_TYPE_ACCOUNT_ASSISTANT, \
67                                                       ModestAccountAssistantPrivate))
68 /* globals */
69 static GtkAssistantClass *parent_class = NULL;
70
71 /* uncomment the following if you have defined any signals */
72 /* static guint signals[LAST_SIGNAL] = {0}; */
73
74 GType
75 modest_account_assistant_get_type (void)
76 {
77         static GType my_type = 0;
78         if (!my_type) {
79                 static const GTypeInfo my_info = {
80                         sizeof(ModestAccountAssistantClass),
81                         NULL,           /* base init */
82                         NULL,           /* base finalize */
83                         (GClassInitFunc) modest_account_assistant_class_init,
84                         NULL,           /* class finalize */
85                         NULL,           /* class data */
86                         sizeof(ModestAccountAssistant),
87                         1,              /* n_preallocs */
88                         (GInstanceInitFunc) modest_account_assistant_init,
89                 };
90                 my_type = g_type_register_static (GTK_TYPE_ASSISTANT,
91                                                   "ModestAccountAssistant",
92                                                   &my_info, 0);
93         }
94         return my_type;
95 }
96
97 static void
98 modest_account_assistant_class_init (ModestAccountAssistantClass *klass)
99 {
100         GObjectClass *gobject_class;
101         gobject_class = (GObjectClass*) klass;
102
103         parent_class            = g_type_class_peek_parent (klass);
104         gobject_class->finalize = modest_account_assistant_finalize;
105
106         g_type_class_add_private (gobject_class, sizeof(ModestAccountAssistantPrivate));
107
108         /* signal definitions go here, e.g.: */
109 /*      signals[MY_SIGNAL_1] = */
110 /*              g_signal_new ("my_signal_1",....); */
111 /*      signals[MY_SIGNAL_2] = */
112 /*              g_signal_new ("my_signal_2",....); */
113 /*      etc. */
114 }
115
116
117
118 static void
119 add_intro_page (ModestAccountAssistant *assistant)
120 {
121         GtkWidget *page, *label;
122         
123         page = gtk_vbox_new (FALSE, 6);
124         
125         label = gtk_label_new (
126                 _("Welcome to the account assistant\n\n"
127                   "It will help to set up a new e-mail account\n"));
128         gtk_box_pack_start (GTK_BOX(page), label, FALSE, FALSE, 6);
129         gtk_widget_show_all (page);
130         
131         gtk_assistant_append_page (GTK_ASSISTANT(assistant), page);
132                 
133         gtk_assistant_set_page_title (GTK_ASSISTANT(assistant), page,
134                                       _("Modest Account Assistant"));
135         gtk_assistant_set_page_type (GTK_ASSISTANT(assistant), page,
136                                      GTK_ASSISTANT_PAGE_INTRO);
137         gtk_assistant_set_page_complete (GTK_ASSISTANT(assistant),
138                                          page, TRUE);
139 }
140
141
142 static void
143 set_current_page_complete (ModestAccountAssistant *self, gboolean complete)
144 {
145         GtkWidget *page;
146         gint pageno;
147
148         pageno = gtk_assistant_get_current_page (GTK_ASSISTANT(self));
149         page   = gtk_assistant_get_nth_page (GTK_ASSISTANT(self), pageno);
150
151         gtk_assistant_set_page_complete (GTK_ASSISTANT(self), page, complete);
152 }
153
154
155 static void
156 identity_page_update_completeness (GtkEditable *editable,
157                                    ModestAccountAssistant *self)
158 {
159         ModestAccountAssistantPrivate *priv;
160         const gchar *txt;
161
162         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
163
164         txt = gtk_entry_get_text (GTK_ENTRY(priv->fullname));
165         if (!txt || strlen(txt) == 0) {
166                 set_current_page_complete (self, FALSE);
167                 return;
168         }
169
170         /* FIXME: regexp check for email address */
171         txt = gtk_entry_get_text (GTK_ENTRY(priv->email));
172         if (!txt || strlen(txt) == 0) {
173                 set_current_page_complete (self, FALSE);
174                 return;
175         }
176         set_current_page_complete (self, TRUE);
177 }
178
179
180 static void
181 add_identity_page (ModestAccountAssistant *self)
182 {
183         GtkWidget *page, *label, *table;
184         ModestAccountAssistantPrivate *priv;
185
186         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
187
188         priv->fullname = gtk_entry_new_with_max_length (40);
189         priv->email    = gtk_entry_new_with_max_length (40);
190         
191         page = gtk_vbox_new (FALSE, 6);
192
193         label = gtk_label_new (
194                 _("Please enter your name and your e-mail address below.\n\n"));
195         gtk_box_pack_start (GTK_BOX(page), label, FALSE, FALSE, 6);
196         
197         table = gtk_table_new (2,2, FALSE);
198         gtk_table_attach_defaults (GTK_TABLE(table),gtk_label_new (_("Full name")),
199                                    0,1,0,1);
200         gtk_table_attach_defaults (GTK_TABLE(table),gtk_label_new (_("E-mail address")),
201                                    0,1,1,2);
202         gtk_table_attach_defaults (GTK_TABLE(table),priv->fullname,
203                                    1,2,0,1);
204         gtk_table_attach_defaults (GTK_TABLE(table),priv->email,
205                                    1,2,1,2);
206
207         g_signal_connect (G_OBJECT(priv->fullname), "changed",
208                           G_CALLBACK(identity_page_update_completeness),
209                           self);
210         g_signal_connect (G_OBJECT(priv->email), "changed",
211                           G_CALLBACK(identity_page_update_completeness),
212                           self);
213         
214         gtk_box_pack_start (GTK_BOX(page), table, FALSE, FALSE, 6);
215         gtk_widget_show_all (page);
216         
217         gtk_assistant_append_page (GTK_ASSISTANT(self), page);
218         
219         gtk_assistant_set_page_title (GTK_ASSISTANT(self), page,
220                                       _("Identity"));
221         gtk_assistant_set_page_type (GTK_ASSISTANT(self), page,
222                                      GTK_ASSISTANT_PAGE_INTRO);
223         gtk_assistant_set_page_complete (GTK_ASSISTANT(self),
224                                          page, FALSE);
225 }       
226
227
228 static void
229 on_receiving_combo_box_changed (GtkComboBox *combo, ModestAccountAssistant *self)
230 {
231         ModestAccountAssistantPrivate *priv;
232         gchar *chosen;
233         
234         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
235         chosen = gtk_combo_box_get_active_text (GTK_COMBO_BOX(combo));
236
237         if (priv->store_widget)
238                 gtk_container_remove (GTK_CONTAINER(priv->store_holder),
239                                       priv->store_widget);
240         
241         priv->store_widget = modest_store_widget_new (priv->factory, chosen);
242
243         gtk_container_add (GTK_CONTAINER(priv->store_holder),
244                            priv->store_widget);
245         
246         gtk_widget_show_all (priv->store_holder);
247         
248 }       
249
250 static void
251 add_receiving_page (ModestAccountAssistant *self)
252 {
253         GtkWidget *page, *box, *combo;
254
255         ModestAccountAssistantPrivate *priv;
256
257         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);      
258         page = gtk_vbox_new (FALSE, 6);
259
260         gtk_box_pack_start (GTK_BOX(page),
261                             gtk_label_new (
262                                     _("Please select among the following options")),
263                             FALSE, FALSE, 6);
264         box = gtk_hbox_new (FALSE, 6);
265         gtk_box_pack_start (GTK_BOX(box),
266                             gtk_label_new(_("Server type")),
267                             FALSE,FALSE,6);
268
269         combo = modest_widget_factory_get_combo_box (priv->factory,
270                                                      MODEST_COMBO_BOX_TYPE_STORE_PROTOS);
271         g_signal_connect (G_OBJECT(combo), "changed",
272                           G_CALLBACK(on_receiving_combo_box_changed), self);
273
274         gtk_box_pack_start (GTK_BOX(box), combo, FALSE,FALSE,6);
275         gtk_box_pack_start (GTK_BOX(page), box, FALSE,FALSE, 6);
276         
277         gtk_box_pack_start (GTK_BOX(page), gtk_hseparator_new(), FALSE, FALSE, 0);
278
279         priv->store_holder = gtk_hbox_new (FALSE, 0);
280         gtk_box_pack_start (GTK_BOX(page), priv->store_holder,
281                             TRUE, TRUE, 0);
282         
283         gtk_assistant_append_page (GTK_ASSISTANT(self), page);
284                 
285         gtk_assistant_set_page_title (GTK_ASSISTANT(self), page,
286                                       _("Receiving mail"));
287         gtk_assistant_set_page_type (GTK_ASSISTANT(self), page,
288                                      GTK_ASSISTANT_PAGE_INTRO);
289         gtk_assistant_set_page_complete (GTK_ASSISTANT(self),
290                                          page, TRUE);
291         gtk_widget_show_all (page);
292 }
293
294
295
296
297 static void
298 on_sending_combo_box_changed (GtkComboBox *combo, ModestAccountAssistant *self)
299 {
300         ModestAccountAssistantPrivate *priv;
301         gchar *chosen;
302         
303         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
304
305         chosen = gtk_combo_box_get_active_text (GTK_COMBO_BOX(combo));
306
307         if (priv->transport_widget)
308                 gtk_container_remove (GTK_CONTAINER(priv->transport_holder),
309                                       priv->transport_widget);
310         
311         priv->transport_widget = modest_transport_widget_new (priv->factory,
312                                                               chosen);
313
314         gtk_container_add (GTK_CONTAINER(priv->transport_holder),
315                            priv->transport_widget);
316
317         gtk_widget_show_all (priv->transport_holder);
318 }
319
320
321
322 static void
323 add_sending_page (ModestAccountAssistant *self)
324 {
325         GtkWidget *page, *box, *combo;
326
327         ModestAccountAssistantPrivate *priv;
328
329         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
330         page = gtk_vbox_new (FALSE, 6);
331         
332         gtk_box_pack_start (GTK_BOX(page),
333                             gtk_label_new (
334                                     _("Please select among the following options")),
335                             FALSE, FALSE, 0);
336         box = gtk_hbox_new (FALSE, 0);
337         gtk_box_pack_start (GTK_BOX(box),
338                             gtk_label_new(_("Server type")),
339                             FALSE,FALSE,0);
340
341         combo = modest_widget_factory_get_combo_box (priv->factory,
342                                                      MODEST_COMBO_BOX_TYPE_TRANSPORT_PROTOS);
343         g_signal_connect (G_OBJECT(combo), "changed",
344                           G_CALLBACK(on_sending_combo_box_changed), self);
345
346         gtk_box_pack_start (GTK_BOX(box), combo, FALSE,FALSE,0);
347         gtk_box_pack_start (GTK_BOX(page), box, FALSE,FALSE, 0);
348         
349         gtk_box_pack_start (GTK_BOX(page), gtk_hseparator_new(), FALSE, FALSE, 0);
350
351         priv->transport_holder = gtk_hbox_new (FALSE, 0);
352         gtk_box_pack_start (GTK_BOX(page), priv->transport_holder,
353                             FALSE, FALSE, 0);
354         
355         gtk_assistant_append_page (GTK_ASSISTANT(self), page);
356                 
357         gtk_assistant_set_page_title (GTK_ASSISTANT(self), page,
358                                       _("Sending mail"));
359         gtk_assistant_set_page_type (GTK_ASSISTANT(self), page,
360                                      GTK_ASSISTANT_PAGE_INTRO);
361         gtk_assistant_set_page_complete (GTK_ASSISTANT(self),
362                                          page, TRUE);
363         gtk_widget_show_all (page);
364 }
365
366
367
368 static void
369 add_final_page (ModestAccountAssistant *self)
370 {
371         GtkWidget *page, *box;
372         ModestAccountAssistantPrivate *priv;
373
374         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
375         page = gtk_vbox_new (FALSE, 6);
376         
377         gtk_box_pack_start (GTK_BOX(page),
378                             gtk_label_new (
379                                     _("We're almost done. Press 'Apply' to store this new account")),
380                             FALSE, FALSE, 6);
381         box = gtk_hbox_new (FALSE, 6);
382         priv->account_name =
383                 gtk_entry_new_with_max_length (40);
384         gtk_entry_set_text (GTK_ENTRY(priv->account_name),
385                             gtk_entry_get_text(GTK_ENTRY(priv->email)));
386         gtk_box_pack_start (GTK_BOX(box),gtk_label_new(_("Account name:")),
387                             FALSE,FALSE,6);
388         gtk_box_pack_start (GTK_BOX(box),priv->account_name , FALSE,FALSE,6);
389         
390         gtk_box_pack_start (GTK_BOX(page), box, FALSE, FALSE, 6);
391         
392         gtk_assistant_append_page (GTK_ASSISTANT(self), page);
393                 
394         gtk_assistant_set_page_title (GTK_ASSISTANT(self), page,
395                                       _("Account Management"));
396         gtk_assistant_set_page_type (GTK_ASSISTANT(self), page,
397                                      GTK_ASSISTANT_PAGE_CONFIRM);
398
399         gtk_assistant_set_page_complete (GTK_ASSISTANT(self),
400                                          page, TRUE);
401         gtk_widget_show_all (page);
402 }
403         
404
405
406
407 static void
408 modest_account_assistant_init (ModestAccountAssistant *obj)
409 {       
410         ModestAccountAssistantPrivate *priv;
411                 
412         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(obj);       
413         priv->factory           = NULL;
414         priv->account_mgr       = NULL;
415
416         priv->store_widget      = NULL;
417         priv->transport_widget  = NULL;
418 }
419
420 static void
421 modest_account_assistant_finalize (GObject *obj)
422 {
423         ModestAccountAssistantPrivate *priv;
424                 
425         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(obj);
426
427         if (priv->factory) {
428                 g_object_unref (G_OBJECT(priv->factory));
429                 priv->factory = NULL;
430         }
431         
432         if (priv->account_mgr) {
433                 g_object_unref (G_OBJECT(priv->account_mgr));
434                 priv->account_mgr = NULL;
435         }
436
437
438
439         G_OBJECT_CLASS(parent_class)->finalize (obj);
440 }
441
442 static void
443 on_cancel (ModestAccountAssistant *self, gpointer user_data)
444 {
445         GtkWidget *label;
446         GtkWidget *dialog;
447         int response;
448         
449         label = gtk_label_new (_("Are you sure you want to cancel\n"
450                                  "setting up a new account?"));
451         
452         dialog = gtk_dialog_new_with_buttons (_("Cancel"),
453                                               GTK_WINDOW(self),
454                                               GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
455                                               GTK_STOCK_YES, GTK_RESPONSE_ACCEPT,
456                                               GTK_STOCK_NO,  GTK_RESPONSE_CANCEL,
457                                               NULL);
458         
459         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
460                             label, FALSE, FALSE, 6);
461
462         gtk_widget_show_all ((GTK_DIALOG(dialog)->vbox));
463         
464         gtk_window_set_resizable (GTK_WINDOW(dialog), FALSE);
465         
466         response = gtk_dialog_run (GTK_DIALOG(dialog));
467         gtk_widget_destroy (dialog);
468
469         switch (response) {
470         case GTK_RESPONSE_ACCEPT:
471                 /* close the assistant */
472                 gtk_widget_destroy (GTK_WIDGET(self));
473                 break;
474         case GTK_RESPONSE_CANCEL:
475                 /* don't do anything */
476                 break;
477         default: g_assert_not_reached ();
478
479         };                           
480 }
481
482 static const gchar*
483 get_account_name (ModestAccountAssistant *self)
484 {
485         ModestAccountAssistantPrivate *priv;
486         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
487
488         return gtk_entry_get_text (GTK_ENTRY(priv->account_name));
489 }
490
491 static const gchar*
492 get_fullname (ModestAccountAssistant *self)
493 {
494         ModestAccountAssistantPrivate *priv;
495         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
496
497         return gtk_entry_get_text (GTK_ENTRY(priv->fullname));
498 }
499
500
501
502 static const gchar*
503 get_email (ModestAccountAssistant *self)
504 {
505         ModestAccountAssistantPrivate *priv;
506         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
507
508         return gtk_entry_get_text (GTK_ENTRY(priv->email));
509 }
510
511
512
513 static void
514 on_apply (ModestAccountAssistant *self, gpointer user_data)
515 {
516         ModestAccountAssistantPrivate *priv;
517         gchar *store_name;
518         const gchar *account_name;
519         ModestStoreWidget *store;
520
521         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
522
523         /* create account */
524
525         /* create server account -> store */
526         store = MODEST_STORE_WIDGET(priv->store_widget);
527         store_name = g_strdup_printf ("%s:%s@%s",
528                                       modest_store_widget_get_proto (store),
529                                       modest_store_widget_get_username (store),
530                                       modest_store_widget_get_servername (store));
531         
532         modest_account_mgr_add_server_account (priv->account_mgr,
533                                                 store_name,
534                                                 modest_store_widget_get_servername (store),
535                                                 modest_store_widget_get_username (store),
536                                                 NULL,
537                                                 modest_store_widget_get_proto (store));
538
539         /* create server account -> transport */
540         account_name = get_account_name (self);
541         modest_account_mgr_add_account (priv->account_mgr,
542                                         account_name,
543                                         store_name,
544                                         NULL, NULL);
545         modest_account_mgr_set_string (priv->account_mgr,
546                                        account_name,
547                                        MODEST_ACCOUNT_FULLNAME,
548                                        get_fullname(self), FALSE, NULL);
549         modest_account_mgr_set_string (priv->account_mgr,
550                                        account_name,
551                                        MODEST_ACCOUNT_EMAIL,
552                                        get_email(self), FALSE, NULL);
553         
554         g_free (store_name);
555 }
556
557
558
559 GtkWidget*
560 modest_account_assistant_new (ModestAccountMgr *account_mgr, ModestWidgetFactory *factory)
561 {
562         GObject *obj;
563         ModestAccountAssistant *self;
564         ModestAccountAssistantPrivate *priv;
565                 
566         g_return_val_if_fail (factory, NULL);
567         g_return_val_if_fail (account_mgr, NULL);
568         
569         obj  = g_object_new(MODEST_TYPE_ACCOUNT_ASSISTANT, NULL);
570         self = MODEST_ACCOUNT_ASSISTANT(obj);
571
572         priv = MODEST_ACCOUNT_ASSISTANT_GET_PRIVATE(self);
573         
574         g_object_ref (factory);
575         priv->factory = factory;
576         
577         g_object_ref (account_mgr);
578         priv->account_mgr = account_mgr;
579
580         add_intro_page (self);
581         add_identity_page (self); 
582         add_receiving_page (self); 
583         add_sending_page (self);
584         add_final_page (self);
585
586         gtk_assistant_set_current_page (GTK_ASSISTANT(self), 0);
587         gtk_window_set_title (GTK_WINDOW(self),
588                               _("Modest Account Wizard"));
589         gtk_window_set_resizable (GTK_WINDOW(self), TRUE);      
590         gtk_window_set_default_size (GTK_WINDOW(self), 400, 400);
591         
592         gtk_window_set_modal (GTK_WINDOW(self), TRUE);
593
594         g_signal_connect (G_OBJECT(self), "apply",
595                           G_CALLBACK(on_apply), NULL);
596         g_signal_connect (G_OBJECT(self), "cancel",
597                           G_CALLBACK(on_cancel), NULL);
598
599         return GTK_WIDGET(self);
600 }