Imported Upstream version 1.1.0.99.1
[platform/upstream/syncevolution.git] / src / gtk-ui / sync-config-widget.c
1 #include "config.h"
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <glib/gi18n.h>
6 #include <dbus/dbus-glib.h>
7
8 #ifdef USE_MOBLIN_UX
9 #ifdef MX_GTK_0_99_1
10 #include <mx-gtk/mx-gtk.h>
11 #else
12 #include <mx/mx-gtk.h>
13 #endif
14 #endif
15
16 #include "sync-ui.h"
17 #include "sync-config-widget.h"
18
19 /* local copy of GtkInfoBar, used when GTK+ < 2.18 */
20 #include "gtkinfobar.h"
21
22
23 #define INDICATOR_SIZE 16
24 #define CHILD_PADDING 3
25
26 G_DEFINE_TYPE (SyncConfigWidget, sync_config_widget, GTK_TYPE_CONTAINER)
27
28
29 typedef struct source_widgets {
30     char *name;
31
32     GtkWidget *label;
33     GtkWidget *entry;
34     GtkWidget *check;
35
36     GtkWidget *source_toggle_label;
37
38     guint count;
39 } source_widgets;
40
41 enum
42 {
43   PROP_0,
44
45   PROP_SERVER,
46   PROP_NAME,
47   PROP_CONFIG,
48   PROP_CURRENT,
49   PROP_HAS_TEMPLATE,
50   PROP_CONFIGURED,
51   PROP_CURRENT_SERVICE_NAME,
52   PROP_EXPANDED,
53 };
54
55 enum {
56         SIGNAL_CHANGED,
57         LAST_SIGNAL
58 };
59 static guint32 signals[LAST_SIGNAL] = {0, };
60
61 typedef struct save_config_data {
62     SyncConfigWidget *widget;
63     gboolean delete;
64     gboolean temporary;
65     source_widgets *widgets;
66     char *basename;
67 } save_config_data;
68
69 static void start_session_for_config_write_cb (SyncevoServer *server, char *path, GError *error, save_config_data *data);
70 static void sync_config_widget_update_label (SyncConfigWidget *self);
71 static void sync_config_widget_set_name (SyncConfigWidget *self, const char *name);
72
73 static void
74 remove_child (GtkWidget *widget, GtkContainer *container)
75 {
76     gtk_container_remove (container, widget);
77 }
78
79 const char*
80 get_service_description (const char *service)
81 {
82     if (!service)
83         return NULL;
84
85     /* TRANSLATORS: Descriptions for specific services, shown in service
86      * configuration form */
87     if (strcmp (service, "ScheduleWorld") == 0) {
88         return _("ScheduleWorld enables you to keep your contacts, events, "
89                  "tasks, and notes in sync.");
90     }else if (strcmp (service, "Google") == 0) {
91         return _("Google Sync can backup and synchronize your contacts "
92                  "with your Gmail contacts.");
93     }else if (strcmp (service, "Funambol") == 0) {
94         /* TRANSLATORS: Please include the word "demo" (or the equivalent in
95            your language): Funambol is going to be a 90 day demo service
96            in the future */
97         return _("Backup your contacts and calendar. Sync with a single "
98                  "click, anytime, anywhere (DEMO).");
99     }else if (strcmp (service, "Mobical") == 0) {
100         return _("Mobical Backup and Restore service allows you to securely "
101                  "backup your personal mobile data for free.");
102     }else if (strcmp (service, "ZYB") == 0) {
103         return _("ZYB is a simple way for people to store and share mobile "
104                  "information online.");
105     }else if (strcmp (service, "Memotoo") == 0) {
106         return _("Memotoo lets you access your personal data from any "
107                  "computer connected to the Internet.");
108     }
109
110     return NULL;
111 }
112
113 static void
114 update_source_uri (char *name,
115                    GHashTable *source_configuration,
116                    SyncConfigWidget *self)
117 {
118     const char *uri;
119     source_widgets *widgets;
120
121     widgets = (source_widgets*)g_hash_table_lookup (self->sources, name);
122     if (!widgets) {
123         return;
124     }
125
126     uri = gtk_entry_get_text (GTK_ENTRY (widgets->entry));
127     g_hash_table_insert (source_configuration, g_strdup ("uri"), g_strdup (uri));
128 }
129
130 static source_widgets *
131 source_widgets_ref (source_widgets *widgets)
132 {
133     if (widgets) {
134         widgets->count++;
135     }
136     return widgets;
137 }
138
139 static void
140 source_widgets_unref (source_widgets *widgets)
141 {
142     if (widgets) {
143         widgets->count--;
144         if (widgets->count == 0)
145             g_slice_free (source_widgets, widgets);
146     }
147 }
148
149 static void
150 check_source_cb (SyncevoSession *session,
151                  GError *error,
152                  source_widgets *widgets)
153 {
154     gboolean show = TRUE;
155
156     if (error) {
157         if(error->code == DBUS_GERROR_REMOTE_EXCEPTION &&
158            dbus_g_error_has_name (error, SYNCEVO_DBUS_ERROR_SOURCE_UNUSABLE)) {
159             show = FALSE;
160         } else {
161             g_warning ("CheckSource failed: %s", error->message);
162             /* non-fatal, ignore in UI */
163         }
164         g_error_free (error);
165     }
166
167     if (widgets->count > 1) {
168         if (show) {
169             /* NOTE: with the new two sources per row layout not showing things
170              * may look weird in some cases... the layout should really only be
171              * done at this point  */
172             gtk_widget_show (widgets->source_toggle_label);
173             gtk_widget_show (widgets->label);
174             gtk_widget_show (widgets->entry);
175             gtk_widget_show (widgets->check);
176         } else {
177             /* next save should disable this source */
178             toggle_set_active (widgets->check, FALSE);
179         }
180     }
181     source_widgets_unref (widgets);
182     g_object_unref (session);
183 }
184
185 static void
186 set_config_cb (SyncevoSession *session,
187                GError *error,
188                save_config_data *data)
189 {
190     if (error) {
191         g_warning ("Error in Session.SetConfig: %s", error->message);
192         g_error_free (error);
193         g_object_unref (session);
194         show_error_dialog (GTK_WIDGET (data->widget),
195                            _("Sorry, failed to save the configuration"));
196         return;
197     }
198
199     if (data->temporary) {
200         syncevo_session_check_source (session,
201                                       data->widgets->name,
202                                       (SyncevoSessionGenericCb)check_source_cb,
203                                       data->widgets);
204     } else {
205         data->widget->configured = TRUE;
206         g_signal_emit (data->widget, signals[SIGNAL_CHANGED], 0);
207         g_object_unref (session);
208     }
209
210 }
211
212 static void
213 get_config_for_overwrite_prevention_cb (SyncevoSession *session,
214                                         SyncevoConfig *config,
215                                         GError *error,
216                                         save_config_data *data)
217 {
218     static int index = 0;
219     char *name;
220
221     if (error) {
222         index = 0;
223         if (error->code == DBUS_GERROR_REMOTE_EXCEPTION &&
224             dbus_g_error_has_name (error, SYNCEVO_DBUS_ERROR_NO_SUCH_CONFIG)) {
225             /* Config does not exist (as expected), we can now save */
226             syncevo_session_set_config (session,
227                                         data->temporary,
228                                         data->temporary,
229                                         data->widget->config,
230                                         (SyncevoSessionGenericCb)set_config_cb,
231                                         data);
232             return;
233         }
234         g_warning ("Unexpected error in Session.GetConfig: %s", error->message);
235         g_error_free (error);
236         g_object_unref (session);
237         return;
238     }
239
240     /* Config exists when we are trying to create a new config...
241      * Need to start a new session with another name */    
242     g_object_unref (session);
243     name = g_strdup_printf ("%s__%d", data->basename, ++index);
244     sync_config_widget_set_name (data->widget, name);
245     g_free (name);
246
247     syncevo_server_start_no_sync_session (data->widget->server,
248                                   data->widget->config_name,
249                                   (SyncevoServerStartSessionCb)start_session_for_config_write_cb,
250                                   data);
251 }
252
253 static void
254 save_config (save_config_data *data,
255              SyncevoSession *session)
256 {   
257     SyncConfigWidget *w = data->widget;
258
259     if (data->delete) {
260         syncevo_config_free (w->config);
261         w->config = g_hash_table_new (g_str_hash, g_str_equal);
262     }
263
264     /* if this is a client peer (a device) and not configured, we
265      * need to test that we aren't overwriting existing
266      * configs */
267     /* TODO: This might be a good thing to do for any configurations.*/
268     if (peer_is_client (w->config) &&
269         !w->configured && !data->temporary) {
270
271         syncevo_session_get_config (session,
272                                     FALSE,
273                                     (SyncevoSessionGetConfigCb)get_config_for_overwrite_prevention_cb,
274                                     data);
275     } else {
276         syncevo_session_set_config (session,
277                                     data->temporary,
278                                     data->temporary,
279                                     data->widget->config,
280                                     (SyncevoSessionGenericCb)set_config_cb,
281                                     data);
282     }
283 }
284
285 static void
286 status_changed_for_config_write_cb (SyncevoSession *session,
287                                     SyncevoSessionStatus status,
288                                     guint error_code,
289                                     SyncevoSourceStatuses *source_statuses,
290                                     save_config_data *data)
291 {
292     if (status == SYNCEVO_STATUS_IDLE) {
293         save_config (data, session);
294     }
295 }
296
297 static void
298 get_status_for_config_write_cb (SyncevoSession *session,
299                                 SyncevoSessionStatus status,
300                                 guint error_code,
301                                 SyncevoSourceStatuses *source_statuses,
302                                 GError *error,
303                                 save_config_data *data)
304 {
305     if (error) {
306         g_warning ("Error in Session.GetStatus: %s", error->message);
307         g_error_free (error);
308         g_object_unref (session);
309         /* TODO show in UI: save failed in service list */
310         return;
311     }
312
313     syncevo_source_statuses_free (source_statuses);
314
315     if (status == SYNCEVO_STATUS_IDLE) {
316         save_config (data, session);
317     }
318 }
319
320
321 static void
322 start_session_for_config_write_cb (SyncevoServer *server,
323                                    char *path,
324                                    GError *error,
325                                    save_config_data *data)
326 {
327     SyncevoSession *session;
328
329     if (error) {
330         g_warning ("Error in Server.StartSession: %s", error->message);
331         g_error_free (error);
332         /* TODO show in UI: save failed in service list */
333         return;
334     }
335
336     session = syncevo_session_new (path);
337
338     /* we want to know about status changes to our session */
339     g_signal_connect (session, "status-changed",
340                       G_CALLBACK (status_changed_for_config_write_cb), data);
341     syncevo_session_get_status (session,
342                                 (SyncevoSessionGetStatusCb)get_status_for_config_write_cb,
343                                 data);
344 }
345
346 static void
347 stop_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
348 {
349     save_config_data *data;
350
351     if (!self->config) {
352         return;
353     }
354
355     syncevo_config_set_value (self->config, NULL, "defaultPeer", "");
356     sync_config_widget_set_current (self, FALSE);
357
358     data = g_slice_new (save_config_data);
359     data->widget = self;
360     data->delete = FALSE;
361     data->temporary = FALSE;
362     syncevo_server_start_no_sync_session (self->server,
363                                   self->config_name,
364                                   (SyncevoServerStartSessionCb)start_session_for_config_write_cb,
365                                   data);
366 }
367
368 static void
369 use_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
370 {
371     save_config_data *data;
372     const char *username, *password, *sync_url, *pretty_name;
373     char *real_url, *device;
374     gboolean send, receive;
375     SyncevoSyncMode mode;
376
377     if (!self->config) {
378         return;
379     }
380
381     if (!self->config_name || strlen (self->config_name) == 0) {
382         g_free (self->config_name);
383         self->config_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry)));
384     }
385
386     if (self->mode_changed) {
387         GHashTableIter iter;
388         source_widgets *widgets;
389         char *name;
390         gboolean client = peer_is_client (self->config);
391
392         send = toggle_get_active (self->send_check);
393         receive = toggle_get_active (self->receive_check);
394
395         if (send && receive) {
396             mode = SYNCEVO_SYNC_TWO_WAY;
397         } else if (send) {
398             mode = client ?
399                 SYNCEVO_SYNC_ONE_WAY_FROM_SERVER :
400                 SYNCEVO_SYNC_ONE_WAY_FROM_CLIENT;
401         } else if (receive) {
402             mode = client ?
403                 SYNCEVO_SYNC_ONE_WAY_FROM_CLIENT :
404                 SYNCEVO_SYNC_ONE_WAY_FROM_SERVER;
405         } else {
406             mode = SYNCEVO_SYNC_NONE;
407         }
408
409         g_hash_table_iter_init (&iter, self->sources);
410         while (g_hash_table_iter_next (&iter, (gpointer)&name, (gpointer)&widgets)) {
411             const char *mode_str;
412             gboolean active;
413
414             active = toggle_get_active (widgets->check) &&
415                      GTK_WIDGET_SENSITIVE (widgets->check);
416             if (active) {
417                 mode_str = syncevo_sync_mode_to_string (mode);
418             } else {
419                 mode_str = "none";
420             }
421             syncevo_config_set_value (self->config, name, "sync", mode_str);
422         }
423     }
424
425     username = gtk_entry_get_text (GTK_ENTRY (self->username_entry));
426     syncevo_config_set_value (self->config, NULL, "username", username);
427
428     sync_url = gtk_entry_get_text (GTK_ENTRY (self->baseurl_entry));
429     /* make a wild guess if no scheme in url */
430     if (strstr (sync_url, "://") == NULL) {
431         real_url = g_strdup_printf ("http://%s", sync_url);
432     } else {
433         real_url = g_strdup (sync_url);
434     }
435     syncevo_config_set_value (self->config, NULL, "syncURL", real_url);
436
437     password = gtk_entry_get_text (GTK_ENTRY (self->password_entry));
438     syncevo_config_set_value (self->config, NULL, "password", password);
439
440     syncevo_config_get_value (self->config, NULL, "deviceName", &device);
441     if (!device || strlen (device) == 0) {
442         if (!self->config_name || strlen (self->config_name) == 0 ||
443             !sync_url || strlen (sync_url) == 0) {
444             show_error_dialog (GTK_WIDGET (self), 
445                                _("Service must have a name and server URL"));
446             return;
447         }
448     }
449
450     syncevo_config_foreach_source (self->config,
451                                    (ConfigFunc)update_source_uri,
452                                    self);
453
454     pretty_name = gtk_entry_get_text (GTK_ENTRY (self->entry));
455     syncevo_config_set_value (self->config, NULL, "PeerName", pretty_name);
456     syncevo_config_get_value (self->config, NULL, "PeerName", &self->pretty_name);
457     syncevo_config_set_value (self->config, NULL, "defaultPeer", self->config_name);
458     sync_config_widget_set_current (self, TRUE);
459
460     data = g_slice_new (save_config_data);
461     data->widget = self;
462     data->delete = FALSE;
463     data->temporary = FALSE;
464     data->basename = g_strdup (self->config_name);
465     syncevo_server_start_no_sync_session (self->server,
466                                   self->config_name,
467                                   (SyncevoServerStartSessionCb)start_session_for_config_write_cb,
468                                   data);
469
470     g_free (real_url);
471 }
472
473 static void
474 reset_delete_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
475 {
476     char *msg, *yes, *no;
477     save_config_data *data;
478
479     if (!self->config) {
480         return;
481     }
482
483     if (self->has_template) {
484         /*TRANSLATORS: warning dialog text for resetting pre-defined
485           services */
486         msg = g_strdup_printf
487             (_("Do you want to reset the settings for %s? "
488                "This will not remove any synced information on either end."),
489              self->pretty_name);
490         /*TRANSLATORS: buttons in reset-service warning dialog */
491         yes = _("Yes, reset");
492         no = _("No, keep settings");
493     } else {
494         /*TRANSLATORS: warning dialog text for deleting user-defined
495           services */
496         msg = g_strdup_printf
497             (_("Do you want to delete the settings for %s? "
498                "This will not remove any synced information on either "
499                "end but it will remove these settings."),
500              self->pretty_name);
501         /*TRANSLATORS: buttons in delete-service warning dialog */
502         yes = _("Yes, delete");
503         no = _("No, keep settings");
504     }
505
506     /*TRANSLATORS: decline button in "Reset/delete service" warning dialogs */
507     if (!show_confirmation (GTK_WIDGET (self), msg, yes, no)) {
508         g_free (msg);
509         return;
510     }
511     g_free (msg);
512
513     if (self->current) {
514         sync_config_widget_set_current (self, FALSE);
515     }
516
517     data = g_slice_new (save_config_data);
518     data->widget = self;
519     data->delete = TRUE;
520     data->temporary = FALSE;
521
522     syncevo_server_start_no_sync_session (self->server,
523                                   self->config_name,
524                                   (SyncevoServerStartSessionCb)start_session_for_config_write_cb,
525                                   data);
526 }
527
528 static void update_buttons (SyncConfigWidget *self)
529 {
530     if (self->has_template) {
531         /* TRANSLATORS: button labels in service configuration form */
532         gtk_button_set_label (GTK_BUTTON (self->reset_delete_button),
533                               _("Reset settings"));
534     } else {
535         gtk_button_set_label (GTK_BUTTON (self->reset_delete_button),
536                               _("Delete settings"));
537     }
538     if (self->configured) {
539         gtk_widget_show (GTK_WIDGET (self->reset_delete_button));
540     } else {
541         gtk_widget_hide (GTK_WIDGET (self->reset_delete_button));
542     }
543
544     if (self->current || !self->current_service_name) {
545         gtk_button_set_label (GTK_BUTTON (self->use_button),
546                               _("Save and use"));
547     } else {
548         gtk_button_set_label (GTK_BUTTON (self->use_button),
549                               _("Save and replace\ncurrent service"));
550     }
551
552
553
554     if (self->current && self->config) {
555         if (peer_is_client (self->config)) {
556             gtk_button_set_label (GTK_BUTTON (self->stop_button),
557                                               _("Stop using device"));
558         } else {
559             gtk_button_set_label (GTK_BUTTON (self->stop_button),
560                                               _("Stop using service"));
561         }
562         gtk_widget_show (self->stop_button);
563     } else { 
564         gtk_widget_hide (self->stop_button);
565     }
566 }
567
568 static void
569 mode_widget_notify_active_cb (GtkWidget *widget,
570                               GParamSpec *pspec,
571                               SyncConfigWidget *self)
572 {
573     self->mode_changed = TRUE;
574 }
575
576 static void
577 source_entry_notify_text_cb (GObject *gobject,
578                              GParamSpec *pspec,
579                              source_widgets *widgets)
580 {
581     gboolean new_editable, old_editable;
582     const char *text;
583
584     text = gtk_entry_get_text (GTK_ENTRY (widgets->entry));
585     new_editable = (strlen (text) > 0);
586     old_editable = GTK_WIDGET_SENSITIVE (widgets->check);
587     if (new_editable != old_editable) {
588         gtk_widget_set_sensitive (widgets->check, new_editable);
589         toggle_set_active (widgets->check, new_editable);
590     }
591 }
592
593 static GtkWidget*
594 add_toggle_widget (SyncConfigWidget *self,
595                    const char *title,
596                    gboolean active,
597                    guint row, guint col)
598 {
599     GtkWidget *toggle;
600     int padding;
601
602     padding = (col == 1) ? 0 : 32;
603
604 #ifdef USE_MOBLIN_UX
605     GtkWidget *label;
606
607     col = col * 2;
608     label = gtk_label_new (title);
609     gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
610     gtk_widget_set_size_request (label, 260, -1);
611     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
612     gtk_table_attach (GTK_TABLE (self->mode_table), label,
613                       col, col + 1, row, row + 1,
614                       GTK_FILL, GTK_FILL, 0, 0);
615     toggle = mx_gtk_light_switch_new ();
616     g_signal_connect_swapped (toggle, "hide",
617                               G_CALLBACK (gtk_widget_hide), label);
618     g_signal_connect_swapped (toggle, "show",
619                               G_CALLBACK (gtk_widget_show), label);
620     toggle_set_active (toggle, active);
621     g_signal_connect (toggle, "switch-flipped",
622                       G_CALLBACK (mode_widget_notify_active_cb), self);
623 #else
624     toggle = gtk_check_button_new_with_label (title);
625     gtk_widget_set_size_request (toggle, 260, -1);
626     toggle_set_active (toggle, active);
627     g_signal_connect (toggle, "notify::active",
628                       G_CALLBACK (mode_widget_notify_active_cb), self);
629 #endif
630
631     gtk_table_attach (GTK_TABLE (self->mode_table), toggle,
632                       col + 1, col + 2, row, row + 1,
633                       GTK_FILL, GTK_FILL, padding, 0);
634
635     return toggle;
636 }
637
638
639 /* check if config includes a virtual source that covers the given 
640  * source */
641 static gboolean
642 virtual_source_exists (SyncevoConfig *config, const char *name)
643 {
644     GHashTableIter iter;
645     const char *source_string;
646     GHashTable *source_config;
647
648     g_hash_table_iter_init (&iter, config);
649     while (g_hash_table_iter_next (&iter,
650                                    (gpointer)&source_string,
651                                    (gpointer)&source_config)) {
652         char **strs;
653
654         if (g_str_has_prefix (source_string, "source/")) {
655             const char *uri, *type;
656             type = g_hash_table_lookup (source_config, "type");
657             uri = g_hash_table_lookup (source_config, "uri");
658
659             if (!uri || !type || !g_str_has_prefix (type, "virtual:")) {
660                 /* this source is not defined, or not virtual */
661                 continue;
662             }
663
664             strs = g_strsplit (source_string + 7, "+", 0);
665             if (g_strv_length (strs) > 1) {
666                 int i;
667
668                 for (i = 0; strs[i]; i++) {
669                     if (g_strcmp0 (name, strs[i]) == 0) {
670                         g_strfreev (strs);
671                         return TRUE;
672                     }
673                 }
674             }
675             g_strfreev (strs);
676         }
677     }
678
679     return FALSE;
680 }
681
682 static void
683 init_source (char *name,
684              GHashTable *source_configuration,
685              SyncConfigWidget *self)
686 {
687     char *str, *pretty_name;
688     const char *uri, *type;
689     guint rows;
690     guint row;
691     static guint col = 0;
692     source_widgets *widgets;
693     SyncevoSyncMode mode;
694     save_config_data *data;
695
696     type = g_hash_table_lookup (source_configuration, "type");
697     uri = g_hash_table_lookup (source_configuration, "uri");
698     if (!type || strlen (type) == 0) {
699         return;
700     }
701
702     if (g_str_has_prefix (type, "virtual:") && !uri) {
703         /* undefined virtual source */
704         return;
705     }
706
707     if (virtual_source_exists (self->config, name)) {
708         return;
709     }
710
711     g_object_get (self->mode_table,
712                   "n-rows", &rows,
713                   NULL);
714
715     if (!self->no_source_toggles && col == 0) {
716         col = 1;
717         row = rows - 1;
718     } else {
719         col = 0;
720         row = rows;
721     }
722     self->no_source_toggles = FALSE;
723
724     widgets = g_slice_new0 (source_widgets);
725     widgets->name = name;
726     widgets->count = 1;
727     g_hash_table_insert (self->sources, name, widgets);
728
729     widgets->source_toggle_label = self->source_toggle_label;
730
731     pretty_name = get_pretty_source_name (name);
732     mode = syncevo_sync_mode_from_string
733         (g_hash_table_lookup (source_configuration, "sync"));
734
735     widgets->check = add_toggle_widget (self,
736                                         pretty_name,
737                                         (mode > SYNCEVO_SYNC_NONE),
738                                         row, col);
739
740     /* TRANSLATORS: label for an entry in service configuration form.
741      * Placeholder is a source  name.
742      * Example: "Appointments URI" */
743     str = g_strdup_printf (_("%s URI"), pretty_name);
744     widgets->label = gtk_label_new (str);
745     g_free (str);
746     g_free (pretty_name);
747
748     g_object_get (self->server_settings_table,
749                   "n-rows", &row,
750                   NULL);
751
752     gtk_misc_set_alignment (GTK_MISC (widgets->label), 0.0, 0.5);
753     gtk_table_attach (GTK_TABLE (self->server_settings_table), widgets->label,
754                       0, 1, row, row + 1, GTK_FILL, GTK_EXPAND, 0, 0);
755
756     widgets->entry = gtk_entry_new ();
757     gtk_entry_set_max_length (GTK_ENTRY (widgets->entry), 99);
758     gtk_entry_set_width_chars (GTK_ENTRY (widgets->entry), 80);
759     if (uri) {
760         gtk_entry_set_text (GTK_ENTRY (widgets->entry), uri);
761     }
762     gtk_table_attach_defaults (GTK_TABLE (self->server_settings_table),
763                                widgets->entry,
764                                1, 2, row, row + 1);
765     g_signal_connect (widgets->entry, "notify::text",
766                       G_CALLBACK (source_entry_notify_text_cb), widgets);
767
768     gtk_widget_set_sensitive (widgets->check,
769                               uri && strlen (uri) > 0);
770
771     /* start a session so we save a temporary config so we can do
772      * CheckSource, and show the source-related widgets if the 
773      * source is available */
774     data = g_slice_new (save_config_data);
775     data->widget = self;
776     data->delete = FALSE;
777     data->temporary = TRUE;
778     data->widgets = source_widgets_ref (widgets);
779
780     syncevo_server_start_no_sync_session (self->server,
781                                   self->config_name,
782                                   (SyncevoServerStartSessionCb)start_session_for_config_write_cb,
783                                   data);
784 }
785
786 static void
787 get_common_mode (char *name,
788                  GHashTable *source_configuration,
789                  SyncevoSyncMode *common_mode)
790 {
791     SyncevoSyncMode mode;
792     char *mode_str, *type;
793
794     type = g_hash_table_lookup (source_configuration, "type");
795     if (!type || strlen (type) == 0) {
796         return;
797     }
798
799     mode_str = g_hash_table_lookup (source_configuration, "sync");
800     mode = syncevo_sync_mode_from_string (mode_str);
801
802     if (mode == SYNCEVO_SYNC_NONE) {
803         return;
804     }
805
806     if (*common_mode == SYNCEVO_SYNC_NONE) {
807         *common_mode = mode;
808     } else if (mode != *common_mode) {
809         *common_mode = SYNCEVO_SYNC_UNKNOWN;
810     }
811 }
812
813 void
814 sync_config_widget_expand_id (SyncConfigWidget *self,
815                               const char *id)
816 {
817     if (id && self->config) {
818         char *sync_url;
819
820         if (syncevo_config_get_value (self->config, NULL,
821                                       "syncURL", &sync_url) &&
822             strncmp (sync_url, id, strlen (id)) == 0) {
823
824             sync_config_widget_set_expanded (self, TRUE);
825         } else if (self->config_name &&
826                    g_strcasecmp (self->config_name, id) == 0) {
827
828             sync_config_widget_set_expanded (self, TRUE);
829         }
830     }
831 }
832
833 static void
834 sync_config_widget_update_expander (SyncConfigWidget *self)
835 {
836     char *username = "";
837     char *password = "";
838     char *sync_url = "";
839     const char *descr;
840     char *str;
841     GtkWidget *label, *align;
842     SyncevoSyncMode mode = SYNCEVO_SYNC_NONE;
843     gboolean send, receive;
844     gboolean client;
845
846     gtk_container_foreach (GTK_CONTAINER (self->server_settings_table),
847                            (GtkCallback)remove_child,
848                            self->server_settings_table);
849     gtk_table_resize (GTK_TABLE (self->server_settings_table), 
850                       2, 1);
851     gtk_container_foreach (GTK_CONTAINER (self->mode_table),
852                            (GtkCallback)remove_child,
853                            self->mode_table);
854     gtk_table_resize (GTK_TABLE (self->mode_table),
855                       2, 1);
856
857     client = peer_is_client (self->config);
858     if (client) {
859         if (!self->device_template_selected) {
860             gtk_widget_hide (self->settings_box);
861             gtk_widget_show (self->device_selector_box);
862             /* temporary solution for device template selection:
863              * show list of templates only */
864         } else {
865             gtk_widget_show (self->settings_box);
866             gtk_widget_hide (self->device_selector_box);
867             gtk_widget_hide (self->userinfo_table);
868             gtk_widget_hide (self->fake_expander);
869         }
870     } else {
871         gtk_widget_show (self->settings_box);
872         gtk_widget_hide (self->device_selector_box);
873         gtk_widget_show (self->userinfo_table);
874         gtk_widget_show (self->fake_expander);
875     }
876
877     syncevo_config_foreach_source (self->config,
878                                    (ConfigFunc)get_common_mode,
879                                    &mode);
880     switch (mode) {
881     case SYNCEVO_SYNC_TWO_WAY:
882         send = receive = TRUE;
883         break;
884     case SYNCEVO_SYNC_ONE_WAY_FROM_CLIENT:
885         if (client) {
886             send = FALSE;
887             receive = TRUE;
888         } else {
889             send = TRUE;
890             receive = FALSE;
891         }
892         break;
893     case SYNCEVO_SYNC_ONE_WAY_FROM_SERVER:
894         if (client) {
895             send = TRUE;
896             receive = FALSE;
897         } else {
898             send = FALSE;
899             receive = TRUE;
900         }
901         break;
902     default:
903         gtk_widget_show (self->complex_config_info_bar);
904         send = FALSE;
905         receive = FALSE;
906     }
907     self->mode_changed = FALSE;
908
909
910     if (self->pretty_name) {
911         gtk_entry_set_text (GTK_ENTRY (self->entry), self->pretty_name);
912     }
913     if (!self->config_name || strlen (self->config_name) == 0) {
914         gtk_expander_set_expanded (GTK_EXPANDER (self->expander), TRUE);
915     }
916
917     descr = get_service_description (self->config_name);
918     if (descr) {
919         gtk_label_set_text (GTK_LABEL (self->description_label),
920                             get_service_description (self->config_name));
921         gtk_widget_show (self->description_label);
922     } else {
923         gtk_widget_hide (self->description_label);
924     }
925
926     update_buttons (self);
927
928     /* TRANSLATORS: toggles in service configuration form, placeholder is service
929      * or device name */
930     str = g_strdup_printf (_("Send changes to %s"), self->pretty_name);
931     self->send_check = add_toggle_widget (self, str, send, 0, 0);
932     gtk_widget_show (self->send_check);
933     g_free (str);
934
935     str = g_strdup_printf (_("Receive changes from %s"), self->pretty_name);
936     self->receive_check = add_toggle_widget (self, str, receive, 0, 1);
937     gtk_widget_show (self->receive_check);
938     g_free (str);
939
940     align = gtk_alignment_new (0.0, 1.0, 0.0, 0.0);
941     gtk_alignment_set_padding (GTK_ALIGNMENT (align), 10, 0, 0, 0);
942     gtk_widget_show (align);
943     gtk_table_attach (GTK_TABLE (self->mode_table), align,
944                       0, 1, 1, 2,
945                       GTK_FILL, GTK_FILL, 0, 0);
946
947     self->source_toggle_label = gtk_label_new ("");
948     /* TRANSLATORS: Label for the source toggles in configuration form.
949        This is a verb, as in "Sync Calendar". */
950     gtk_label_set_markup (GTK_LABEL (self->source_toggle_label),
951                           _("<b>Sync</b>"));
952     gtk_widget_show (self->source_toggle_label);
953     gtk_container_add (GTK_CONTAINER (align), self->source_toggle_label);
954
955     syncevo_config_get_value (self->config, NULL, "username", &username);
956     syncevo_config_get_value (self->config, NULL, "password", &password);
957     syncevo_config_get_value (self->config, NULL, "syncURL", &sync_url);
958
959     if (username) {
960         gtk_entry_set_text (GTK_ENTRY (self->username_entry), username);
961     }
962     if (password) {
963         gtk_entry_set_text (GTK_ENTRY (self->password_entry), password);
964     }
965
966     // TRANSLATORS: label of a entry in service configuration
967     label = gtk_label_new (_("Server address"));
968     gtk_misc_set_alignment (GTK_MISC (label), 9.0, 0.5);
969     gtk_widget_show (label);
970     gtk_table_attach (GTK_TABLE (self->server_settings_table), label,
971                       0, 1, 0, 1, GTK_FILL, GTK_EXPAND, 0, 0);
972
973     self->baseurl_entry = gtk_entry_new ();
974     gtk_entry_set_max_length (GTK_ENTRY (self->baseurl_entry), 99);
975     gtk_entry_set_width_chars (GTK_ENTRY (self->baseurl_entry), 80);
976     if (sync_url) {
977         gtk_entry_set_text (GTK_ENTRY (self->baseurl_entry), sync_url);
978     }
979     gtk_widget_show (self->baseurl_entry);
980
981     gtk_table_attach_defaults (GTK_TABLE (self->server_settings_table),
982                                self->baseurl_entry,
983                                1, 2, 0, 1);
984
985     /* update source widgets */
986     if (self->sources) {
987         g_hash_table_destroy (self->sources);
988     }
989     self->sources = g_hash_table_new_full (g_str_hash,
990                                            g_str_equal,
991                                            NULL,
992                                            (GDestroyNotify)source_widgets_unref);
993     self->no_source_toggles = TRUE;
994     syncevo_config_foreach_source (self->config,
995                                    (ConfigFunc)init_source,
996                                    self);
997 }
998
999 /* only adds config to hashtable and combo */
1000 static void
1001 sync_config_widget_add_config (SyncConfigWidget *self,
1002                                const char *name,
1003                                SyncevoConfig *config)
1004 {
1005     GtkListStore *store;
1006     GtkTreeIter iter;
1007     const char *guess_name;
1008     SyncevoConfig *guess_config;
1009     int score = 1;
1010     int guess_score, second_guess_score = -1;
1011     char *str;
1012
1013     store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (self->combo)));
1014     if (syncevo_config_get_value (config, NULL, "score", &str)) {
1015         score = (int)strtol (str, NULL, 10);
1016     }
1017     gtk_list_store_append (store, &iter);
1018     gtk_list_store_set (store, &iter,
1019                         0, name,
1020                         1, config,
1021                         2, score,
1022                         -1);
1023
1024     /* make an educated guess if possible */
1025     gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
1026     gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
1027                         0, &guess_name,
1028                         1, &guess_config,
1029                         2, &guess_score,
1030                         -1);
1031
1032     if (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter)) {
1033         gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
1034                             2, &second_guess_score,
1035                             -1);
1036     }
1037
1038     if (guess_score > 1 && guess_score > second_guess_score) {
1039         gtk_combo_box_set_active (GTK_COMBO_BOX (self->combo), 0);
1040         /* TRANSLATORS: explanation before a device template combobox.
1041          * Placeholder is a device name like 'Nokia N85' or 'Syncevolution
1042          * Client' */
1043         str = g_strdup_printf (_("This device looks like it might be a '%s'. "
1044                                  "If this is not correct, please take a look at "
1045                                  "the list of supported devices and pick yours "
1046                                  "if it is listed"), guess_name);
1047     } else {
1048         gtk_combo_box_set_active (GTK_COMBO_BOX (self->combo), -1);
1049         str = g_strdup (_("We don't know what this device is exactly. "
1050                           "Please take a look at the list of "
1051                           "supported devices and pick yours if it "
1052                           "is listed"));
1053     }
1054     gtk_label_set_text (GTK_LABEL (self->device_text), str);
1055     g_free (str);
1056 }
1057
1058 static void
1059 sync_config_widget_update_pretty_name (SyncConfigWidget *self)
1060 {
1061     self->pretty_name = NULL;
1062
1063     if (self->config) {
1064         syncevo_config_get_value (self->config, NULL,
1065                                   "PeerName", &self->pretty_name);
1066         if (!self->pretty_name) {
1067             syncevo_config_get_value (self->config, NULL,
1068                                       "deviceName", &self->pretty_name);
1069         }
1070     }
1071
1072     if (!self->pretty_name) {
1073         self->pretty_name = self->config_name;
1074     }
1075 }
1076
1077 static void
1078 sync_config_widget_set_config (SyncConfigWidget *self,
1079                                SyncevoConfig *config)
1080 {
1081     self->config = config;
1082     sync_config_widget_update_pretty_name (self);
1083 }
1084
1085
1086 static void
1087 setup_service_clicked (GtkButton *btn, SyncConfigWidget *self)
1088 {
1089     sync_config_widget_set_expanded (self, TRUE);
1090 }
1091
1092 static void
1093 sync_config_widget_set_name (SyncConfigWidget *self,
1094                              const char *name)
1095 {
1096     g_free (self->config_name);
1097     self->config_name = g_strdup (name);
1098     sync_config_widget_update_pretty_name (self);
1099 }
1100
1101
1102 static void
1103 device_selection_btn_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
1104 {
1105     GtkTreeIter iter;
1106
1107     if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->combo), &iter)) {
1108         const char *name;
1109         SyncevoConfig *config;
1110         GtkTreeModel *model;
1111
1112         self->device_template_selected = TRUE;
1113
1114         model = gtk_combo_box_get_model(GTK_COMBO_BOX (self->combo));
1115         gtk_tree_model_get (model, &iter, 0, &name, -1 );
1116         gtk_tree_model_get (model, &iter, 1, &config, -1 );
1117
1118         sync_config_widget_set_config (self, config);
1119
1120         sync_config_widget_update_expander (self);
1121     }
1122 }
1123
1124 static void
1125 server_settings_notify_expand_cb (GtkExpander *expander,
1126                                   GParamSpec *pspec,
1127                                   SyncConfigWidget *self)
1128 {
1129     /* NOTE: expander can be the fake or real one... */
1130     if (gtk_expander_get_expanded (GTK_EXPANDER (self->fake_expander))) {
1131         g_signal_handlers_disconnect_by_func (self->fake_expander,
1132                                               server_settings_notify_expand_cb,
1133                                               self);
1134
1135         gtk_widget_hide (self->fake_expander);
1136         gtk_expander_set_expanded (GTK_EXPANDER (self->fake_expander), FALSE);
1137         gtk_expander_set_expanded (GTK_EXPANDER (self->expander), TRUE);
1138         gtk_widget_show (self->expander);
1139
1140         g_signal_connect (self->expander, "notify::expanded",
1141                       G_CALLBACK (server_settings_notify_expand_cb), self);
1142     } else {
1143         g_signal_handlers_disconnect_by_func (self->expander,
1144                                               server_settings_notify_expand_cb,
1145                                               self);
1146
1147         gtk_widget_hide (self->expander);
1148         gtk_widget_show (self->fake_expander);
1149
1150         g_signal_connect (self->fake_expander, "notify::expanded",
1151                       G_CALLBACK (server_settings_notify_expand_cb), self);
1152     }
1153 }
1154
1155 static GdkPixbuf*
1156 load_icon (const char *uri, guint icon_size)
1157 {
1158     GError *error = NULL;
1159     GdkPixbuf *pixbuf;
1160     const char *filename;
1161     
1162     if (uri && strlen (uri) > 0) {
1163         if (g_str_has_prefix (uri, "file://")) {
1164             filename = uri+7;
1165         } else {
1166             g_warning ("only file:// icon uri is supported: %s", uri);
1167             filename = THEMEDIR "sync-generic.png";
1168         }
1169     } else {
1170         filename = THEMEDIR "sync-generic.png";
1171     }
1172     pixbuf = gdk_pixbuf_new_from_file_at_scale (filename,
1173                                                 icon_size, icon_size,
1174                                                 TRUE, &error);
1175
1176     if (!pixbuf) {
1177         g_warning ("Failed to load service icon: %s", error->message);
1178         g_error_free (error);
1179         return NULL;
1180     }
1181
1182     return pixbuf;
1183 }
1184
1185 static void
1186 sync_config_widget_update_label (SyncConfigWidget *self)
1187 {
1188     if (self->config && self->pretty_name) {
1189         char *url, *sync_url;
1190         char *str;
1191
1192         syncevo_config_get_value (self->config, NULL, "WebURL", &url);
1193         syncevo_config_get_value (self->config, NULL, "syncURL", &sync_url);
1194
1195         if (self->current) {
1196             str = g_strdup_printf ("<b>%s</b>", self->pretty_name);
1197         } else {
1198             str = g_strdup_printf ("%s", self->pretty_name);
1199         }
1200         if (g_str_has_prefix (sync_url, "obex-bt://")) {
1201             char *tmp = g_strdup_printf (_("%s - Bluetooth device"), str);
1202             g_free (str);
1203             str = tmp;
1204         } else if (!self->has_template) {
1205             /* TRANSLATORS: service title for services that are not based on a 
1206              * template in service list, the placeholder is the name of the service */
1207             char *tmp = g_strdup_printf (_("%s - manually setup"), str);
1208             g_free (str);
1209             str = tmp;
1210         } else if (url && strlen (url) > 0) {
1211             char *tmp = g_strdup_printf ("%s -",str);
1212             g_free (str);
1213             str = tmp;
1214         }
1215
1216         gtk_label_set_markup (GTK_LABEL (self->label), str);
1217         g_free (str);
1218     }
1219 }
1220
1221 void
1222 sync_config_widget_set_current_service_name (SyncConfigWidget *self,
1223                                              const char *name)
1224 {
1225     g_free (self->current_service_name);
1226     self->current_service_name = g_strdup (name);
1227
1228     update_buttons (self);
1229 }
1230
1231 void
1232 sync_config_widget_set_current (SyncConfigWidget *self,
1233                                 gboolean current)
1234 {
1235     if (self->current != current) {
1236         self->current = current;
1237         sync_config_widget_update_label (self);
1238     }
1239 }
1240
1241 static void
1242 set_session (SyncConfigWidget *self, const char *path)
1243 {
1244     g_free (self->running_session);
1245     self->running_session = g_strdup (path);
1246
1247     gtk_widget_set_sensitive (GTK_WIDGET (self->reset_delete_button),
1248                               !self->running_session);
1249     gtk_widget_set_sensitive (GTK_WIDGET (self->use_button),
1250                               !self->running_session);
1251
1252     /* TODO: maybe add a explanation text somewhere:
1253      * "Configuration changes are not possible while a sync is in progress" */
1254 }
1255
1256 static void
1257 session_changed_cb (SyncevoServer *server,
1258                     char *path,
1259                     gboolean started,
1260                     SyncConfigWidget *self)
1261 {
1262     if (started) {
1263         set_session (self, path);
1264     } else if (g_strcmp0 (self->running_session, path) == 0 ) {
1265         set_session (self, NULL);
1266     }
1267 }
1268
1269 static void
1270 get_sessions_cb (SyncevoServer *server,
1271                  SyncevoSessions *sessions,
1272                  GError *error,
1273                  SyncConfigWidget *self)
1274 {
1275     if (error) {
1276         g_warning ("Server.GetSessions failed: %s", error->message);
1277         g_error_free (error);
1278         /* non-fatal, ignore in UI */
1279
1280         g_object_unref (self);
1281         return;
1282     }
1283
1284     set_session (self, syncevo_sessions_index (sessions, 0));
1285     syncevo_sessions_free (sessions);
1286     g_object_unref (self);
1287 }
1288
1289 void
1290 sync_config_widget_set_server (SyncConfigWidget *self,
1291                                SyncevoServer *server)
1292 {
1293     if (self->server) {
1294         g_signal_handlers_disconnect_by_func (self->server,
1295                                               session_changed_cb,
1296                                               self);
1297         g_object_unref (self->server);
1298         self->server = NULL;
1299     }
1300     if (!server && !self->server) {
1301         return;
1302     }
1303
1304     self->server = g_object_ref (server);
1305
1306     /* monitor sessions so we can set editing buttons insensitive */
1307     g_signal_connect (self->server, "session-changed",
1308                       G_CALLBACK (session_changed_cb), self);
1309
1310     /* reference is released in callback */
1311     g_object_ref (self);
1312     syncevo_server_get_sessions (self->server,
1313                                  (SyncevoServerGetSessionsCb)get_sessions_cb,
1314                                  self);
1315 }
1316
1317 static void
1318 sync_config_widget_set_property (GObject      *object,
1319                                         guint         property_id,
1320                                         const GValue *value,
1321                                         GParamSpec   *pspec)
1322 {
1323     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (object);
1324
1325     switch (property_id) {
1326     case PROP_SERVER:
1327         sync_config_widget_set_server (self, g_value_get_pointer (value));
1328         break;
1329     case PROP_NAME:
1330         sync_config_widget_set_name (self, g_value_get_string (value));
1331         break;
1332     case PROP_CONFIG:
1333         sync_config_widget_set_config (self, g_value_get_pointer (value));
1334         break;
1335     case PROP_CURRENT:
1336         sync_config_widget_set_current (self, g_value_get_boolean (value));
1337         break;
1338     case PROP_HAS_TEMPLATE:
1339         sync_config_widget_set_has_template (self, g_value_get_boolean (value));
1340         break;
1341     case PROP_CONFIGURED:
1342         sync_config_widget_set_configured (self, g_value_get_boolean (value));
1343         break;
1344     case PROP_CURRENT_SERVICE_NAME:
1345         sync_config_widget_set_current_service_name (self, g_value_get_string (value));
1346         break;
1347     case PROP_EXPANDED:
1348         sync_config_widget_set_expanded (self, g_value_get_boolean (value));
1349         break;
1350     default:
1351         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1352     }
1353 }
1354
1355 static void
1356 sync_config_widget_get_property (GObject    *object,
1357                                  guint       property_id,
1358                                  GValue     *value,
1359                                  GParamSpec *pspec)
1360 {
1361     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (object);
1362
1363     switch (property_id) {
1364     case PROP_SERVER:
1365         g_value_set_pointer (value, self->server);
1366     case PROP_NAME:
1367         g_value_set_string (value, self->config_name);
1368     case PROP_CONFIG:
1369         g_value_set_pointer (value, self->config);
1370     case PROP_CURRENT:
1371         g_value_set_boolean (value, self->current);
1372     case PROP_HAS_TEMPLATE:
1373         g_value_set_boolean (value, self->has_template);
1374     case PROP_CONFIGURED:
1375         g_value_set_boolean (value, self->configured);
1376     case PROP_CURRENT_SERVICE_NAME:
1377         g_value_set_string (value, self->current_service_name);
1378     case PROP_EXPANDED:
1379         g_value_set_boolean (value, self->expanded);
1380     default:
1381         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1382     }
1383 }
1384
1385 static void
1386 sync_config_widget_dispose (GObject *object)
1387 {
1388     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (object);
1389
1390     sync_config_widget_set_server (self, NULL);
1391     if (self->config) {
1392         syncevo_config_free (self->config);
1393     }
1394     self->config = NULL;
1395
1396     g_free (self->config_name);
1397     self->config_name = NULL;
1398     g_free (self->current_service_name);
1399     self->current_service_name = NULL;
1400     g_free (self->running_session);
1401     self->running_session = NULL;
1402     if (self->sources) {
1403         g_hash_table_destroy (self->sources);
1404         self->sources = NULL;
1405     }
1406
1407
1408
1409     G_OBJECT_CLASS (sync_config_widget_parent_class)->dispose (object);
1410 }
1411
1412 static void
1413 init_default_config (SyncConfigWidget *self)
1414 {
1415     sync_config_widget_set_name (self, "");
1416     self->has_template = FALSE;
1417
1418     syncevo_config_set_value (self->config, NULL, "username", "");
1419     syncevo_config_set_value (self->config, NULL, "password", "");
1420     syncevo_config_set_value (self->config, NULL, "syncURL", "");
1421     syncevo_config_set_value (self->config, NULL, "WebURL", "");
1422     syncevo_config_set_value (self->config, "memo", "uri", "");
1423     syncevo_config_set_value (self->config, "todo", "uri", "");
1424     syncevo_config_set_value (self->config, "addressbook", "uri", "");
1425     syncevo_config_set_value (self->config, "calendar", "uri", "");
1426
1427 }
1428
1429 static gboolean
1430 label_button_expose_cb (GtkWidget      *widget,
1431                         GdkEventExpose *event,
1432                         SyncConfigWidget *self)
1433 {
1434     GtkExpanderStyle style;
1435     gint indicator_x, indicator_y;
1436
1437     indicator_x = widget->style->xthickness + INDICATOR_SIZE / 2;
1438     indicator_y = widget->style->ythickness +
1439                   widget->allocation.height / 2;
1440
1441     if (self->expanded) {
1442         style = GTK_EXPANDER_EXPANDED;
1443     } else {
1444         style = GTK_EXPANDER_COLLAPSED;
1445     }
1446
1447     gtk_paint_expander (widget->style,
1448                         widget->window,
1449                         widget->state,
1450                         NULL,
1451                         GTK_WIDGET (self),
1452                         NULL,
1453                         indicator_x,
1454                         indicator_y,
1455                         style);
1456
1457     return FALSE;
1458 }
1459
1460 static gboolean
1461 sync_config_widget_expose_event (GtkWidget      *widget,
1462                                  GdkEventExpose *event)
1463 {
1464     GdkRectangle rect;
1465     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
1466
1467     rect.x = widget->allocation.x;
1468     rect.y = widget->allocation.y;
1469     rect.height = widget->allocation.height;
1470     rect.width = widget->allocation.width;
1471
1472     gtk_paint_box (widget->style,
1473                    widget->window,
1474                    widget->state,
1475                    GTK_SHADOW_OUT,
1476                    &rect,
1477                    widget,
1478                    NULL,
1479                    rect.x,
1480                    rect.y,
1481                    rect.width,
1482                    rect.height);
1483
1484     gtk_container_propagate_expose (GTK_CONTAINER (self),
1485                                     self->label_box, event);
1486     gtk_container_propagate_expose (GTK_CONTAINER (self),
1487                                     self->expando_box, event);
1488
1489     return FALSE;
1490 }
1491
1492
1493 static void
1494 sync_config_widget_size_allocate (GtkWidget     *widget,
1495                                   GtkAllocation *allocation)
1496 {
1497     GtkRequisition req;
1498     GtkAllocation alloc;
1499     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
1500
1501     GTK_WIDGET_CLASS (sync_config_widget_parent_class)->size_allocate (widget,
1502                                                                        allocation);
1503
1504     gtk_widget_size_request (self->label_box, &req);
1505
1506     alloc.x = allocation->x + widget->style->xthickness;
1507     alloc.y = allocation->y + widget->style->ythickness;
1508     alloc.width = allocation->width - 2 * widget->style->xthickness;
1509     alloc.height = req.height;
1510
1511     gtk_widget_size_allocate (self->label_box, &alloc);
1512
1513
1514     if (self->expanded) {
1515         gtk_widget_size_request (self->expando_box, &req);
1516
1517         alloc.x = allocation->x + 2 * widget->style->xthickness;
1518         alloc.y = allocation->y + widget->style->ythickness +
1519                   alloc.height + CHILD_PADDING;
1520         alloc.width = allocation->width - 4 * widget->style->xthickness;
1521         alloc.height = req.height;
1522
1523         gtk_widget_size_allocate (self->expando_box, &alloc);
1524     }
1525 }
1526
1527 static void
1528 sync_config_widget_size_request (GtkWidget      *widget,
1529                                  GtkRequisition *requisition)
1530 {
1531     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
1532     GtkRequisition req;
1533
1534     requisition->width = widget->style->xthickness * 2;
1535     requisition->height = widget->style->ythickness * 2;
1536
1537     gtk_widget_size_request (self->label_box, &req);
1538
1539     requisition->width += req.width;
1540     requisition->height = MAX (req.height, INDICATOR_SIZE) +
1541                           widget->style->ythickness * 2;
1542
1543     if (self->expanded) {
1544
1545         gtk_widget_size_request (self->expando_box, &req);
1546         requisition->width = MAX (requisition->width,
1547                                   req.width + widget->style->xthickness * 4);
1548         requisition->height += req.height + 2 * widget->style->ythickness;
1549     }
1550 }
1551
1552 static GObject *
1553 sync_config_widget_constructor (GType                  gtype,
1554                                 guint                  n_properties,
1555                                 GObjectConstructParam *properties)
1556 {
1557     SyncConfigWidget *self;
1558     GObjectClass *parent_class;  
1559     char *url, *icon;
1560     GdkPixbuf *buf;
1561
1562     parent_class = G_OBJECT_CLASS (sync_config_widget_parent_class);
1563     self = SYNC_CONFIG_WIDGET (parent_class->constructor (gtype,
1564                                                           n_properties,
1565                                                           properties));
1566
1567     if (!self->config || !self->server) {
1568         g_warning ("No SyncevoServer or Syncevoconfig set for SyncConfigWidget");
1569         return G_OBJECT (self);
1570     }
1571
1572     if (g_strcmp0 (self->config_name, "default") == 0) {
1573
1574         init_default_config (self);
1575         gtk_widget_show (self->entry);
1576         gtk_widget_hide (self->label);
1577     } else {
1578         gtk_widget_hide (self->entry);
1579         gtk_widget_show (self->label);
1580     }
1581
1582     syncevo_config_get_value (self->config, NULL, "WebURL", &url);
1583     syncevo_config_get_value (self->config, NULL, "IconURI", &icon);
1584
1585     buf = load_icon (icon, SYNC_UI_LIST_ICON_SIZE);
1586     gtk_image_set_from_pixbuf (GTK_IMAGE (self->image), buf);
1587     g_object_unref (buf);
1588
1589     if (url && strlen (url) > 0) {
1590         gtk_link_button_set_uri (GTK_LINK_BUTTON (self->link), url);
1591         gtk_widget_show (self->link);
1592     } else {
1593         gtk_widget_hide (self->link);
1594     }
1595
1596     sync_config_widget_update_label (self);
1597     sync_config_widget_update_expander (self);
1598
1599     /* hack to get focus in the right place on "Setup new service" */
1600     if (GTK_WIDGET_VISIBLE (self->entry)) {
1601         gtk_widget_grab_focus (self->entry);
1602     }
1603
1604     return G_OBJECT (self);
1605 }
1606
1607 static void
1608 sync_config_widget_map (GtkWidget *widget)
1609 {
1610     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
1611
1612     if (self->label_box && GTK_WIDGET_VISIBLE (self->expando_box)) {
1613         gtk_widget_map (self->label_box);
1614     }
1615     if (self->expando_box && GTK_WIDGET_VISIBLE (self->expando_box)) {
1616         gtk_widget_map (self->expando_box);
1617     }
1618     GTK_WIDGET_CLASS (sync_config_widget_parent_class)->map (widget);
1619 }
1620
1621 static void
1622 sync_config_widget_unmap (GtkWidget *widget)
1623 {
1624     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
1625
1626     GTK_WIDGET_CLASS (sync_config_widget_parent_class)->unmap (widget);
1627
1628     if (self->label_box) {
1629         gtk_widget_unmap (self->label_box);
1630     }
1631     if (self->expando_box) {
1632         gtk_widget_unmap (self->expando_box);
1633     }
1634 }
1635
1636 static void
1637 sync_config_widget_add (GtkContainer *container,
1638                         GtkWidget    *widget)
1639 {
1640     g_warning ("Can't add widgets in to SyncConfigWidget!");
1641 }
1642
1643 static void
1644 sync_config_widget_remove (GtkContainer *container,
1645                            GtkWidget    *widget)
1646 {
1647     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (container);
1648
1649     
1650     if (self->label_box == widget) {
1651         gtk_widget_unparent (widget);
1652         self->label_box = NULL;
1653     }
1654     if (self->expando_box == widget) {
1655         gtk_widget_unparent (widget);
1656         self->expando_box = NULL;
1657     }
1658 }
1659
1660 static void
1661 sync_config_widget_forall (GtkContainer *container,
1662                            gboolean      include_internals,
1663                            GtkCallback   callback,
1664                            gpointer      callback_data)
1665 {
1666     SyncConfigWidget *self = SYNC_CONFIG_WIDGET (container);
1667
1668     if (self->label_box) {
1669         (* callback) (self->label_box, callback_data);
1670     }
1671     if (self->expando_box) {
1672         (* callback) (self->expando_box, callback_data);
1673     }
1674 }
1675
1676
1677 static void
1678 sync_config_widget_class_init (SyncConfigWidgetClass *klass)
1679 {
1680     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1681     GtkWidgetClass *w_class = GTK_WIDGET_CLASS (klass);
1682     GtkContainerClass *c_class = GTK_CONTAINER_CLASS (klass);
1683     GParamSpec *pspec;
1684
1685     object_class->set_property = sync_config_widget_set_property;
1686     object_class->get_property = sync_config_widget_get_property;
1687     object_class->dispose = sync_config_widget_dispose;
1688     object_class->constructor = sync_config_widget_constructor;
1689
1690     w_class->expose_event = sync_config_widget_expose_event;
1691     w_class->size_request = sync_config_widget_size_request;
1692     w_class->size_allocate = sync_config_widget_size_allocate;
1693     w_class->map = sync_config_widget_map;
1694     w_class->unmap = sync_config_widget_unmap;
1695
1696     c_class->add = sync_config_widget_add;
1697     c_class->remove = sync_config_widget_remove;
1698     c_class->forall = sync_config_widget_forall;
1699
1700     pspec = g_param_spec_pointer ("server",
1701                                   "SyncevoServer",
1702                                   "The SyncevoServer to use in Syncevolution DBus calls",
1703                                   G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1704     g_object_class_install_property (object_class, PROP_SERVER, pspec);
1705
1706     pspec = g_param_spec_string ("name",
1707                                  "Configuration name",
1708                                  "The name of the Syncevolution service configuration",
1709                                  NULL,
1710                                  G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1711     g_object_class_install_property (object_class, PROP_NAME, pspec);
1712
1713     pspec = g_param_spec_pointer ("config",
1714                                   "SyncevoConfig",
1715                                   "The SyncevoConfig struct this widget represents. Takes ownership.",
1716                                   G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1717     g_object_class_install_property (object_class, PROP_CONFIG, pspec);
1718
1719     pspec = g_param_spec_boolean ("current",
1720                                   "Current",
1721                                   "Whether the service is currently used",
1722                                   FALSE,
1723                                   G_PARAM_READWRITE);
1724     g_object_class_install_property (object_class, PROP_CURRENT, pspec);
1725
1726     pspec = g_param_spec_boolean ("has-template",
1727                                   "has template",
1728                                   "Whether the service has a matching template",
1729                                   FALSE,
1730                                   G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1731     g_object_class_install_property (object_class, PROP_HAS_TEMPLATE, pspec);
1732
1733     pspec = g_param_spec_boolean ("configured",
1734                                   "Configured",
1735                                   "Whether the service has a configuration already",
1736                                   FALSE,
1737                                   G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1738     g_object_class_install_property (object_class, PROP_CONFIGURED, pspec);
1739
1740     pspec = g_param_spec_string ("current-service-name",
1741                                  "Current service name",
1742                                  "The name of the currently used service or NULL",
1743                                   NULL,
1744                                   G_PARAM_READWRITE);
1745     g_object_class_install_property (object_class, PROP_CURRENT_SERVICE_NAME, pspec);
1746
1747     pspec = g_param_spec_boolean ("expanded",
1748                                   "Expanded",
1749                                   "Whether the expander is open or closed",
1750                                   FALSE,
1751                                   G_PARAM_READWRITE);
1752     g_object_class_install_property (object_class, PROP_EXPANDED, pspec);
1753
1754     signals[SIGNAL_CHANGED] = 
1755             g_signal_new ("changed",
1756                           G_TYPE_FROM_CLASS (klass),
1757                           G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
1758                           G_STRUCT_OFFSET (SyncConfigWidgetClass, changed),
1759                           NULL, NULL,
1760                           g_cclosure_marshal_VOID__VOID,
1761                           G_TYPE_NONE, 
1762                           0);
1763
1764 }
1765
1766 static void
1767 label_enter_notify_cb (GtkWidget *widget,
1768                        GdkEventCrossing *event,
1769                        SyncConfigWidget *self)
1770 {
1771     if (!self->expanded) {
1772         gtk_widget_show (self->button);
1773     }
1774     gtk_widget_set_state (self->label_box, GTK_STATE_PRELIGHT);
1775 }
1776
1777 static void
1778 label_leave_notify_cb (GtkWidget *widget,
1779                        GdkEventCrossing *event,
1780                        SyncConfigWidget *self)
1781 {
1782     if (event->detail != GDK_NOTIFY_INFERIOR) {
1783         gtk_widget_hide (self->button);
1784         gtk_widget_set_state (self->label_box, GTK_STATE_NORMAL);
1785     }
1786 }
1787
1788 static void
1789 device_combo_changed (GtkComboBox *combo,
1790                       SyncConfigWidget *self)
1791 {
1792     char *selected;
1793
1794     selected = gtk_combo_box_get_active_text (GTK_COMBO_BOX (combo));
1795     gtk_widget_set_sensitive (self->device_select_btn, selected != NULL);
1796 }
1797
1798 static void
1799 label_button_release_cb (GtkWidget *widget,
1800                          GdkEventButton *event,
1801                          SyncConfigWidget *self)
1802
1803 {
1804     if (event->button == 1) {
1805         sync_config_widget_set_expanded (self,
1806                                          !sync_config_widget_get_expanded (self));
1807     }
1808 }
1809
1810 static gint
1811 compare_list_items (GtkTreeModel *model,
1812                     GtkTreeIter  *a,
1813                     GtkTreeIter  *b,
1814                     SyncConfigWidget *self)
1815 {
1816     int score_a, score_b;
1817
1818     gtk_tree_model_get(model, a, 2, &score_a, -1);
1819     gtk_tree_model_get(model, b, 2, &score_b, -1);
1820
1821     return score_a - score_b;
1822 }
1823
1824 static void
1825 sync_config_widget_init (SyncConfigWidget *self)
1826 {
1827     GtkWidget *tmp_box, *hbox, *cont, *vbox, *label;
1828     GtkListStore *store;
1829     GtkCellRenderer *renderer;
1830
1831     GTK_WIDGET_SET_FLAGS (GTK_WIDGET (self), GTK_NO_WINDOW);
1832
1833     self->label_box = gtk_event_box_new ();
1834     gtk_widget_set_app_paintable (self->label_box, TRUE);
1835     gtk_widget_show (self->label_box);
1836     gtk_widget_set_parent (self->label_box, GTK_WIDGET (self));
1837     gtk_widget_set_size_request (self->label_box, -1, SYNC_UI_LIST_ICON_SIZE + 6);
1838     g_signal_connect (self->label_box, "enter-notify-event",
1839                       G_CALLBACK (label_enter_notify_cb), self);
1840     g_signal_connect (self->label_box, "leave-notify-event",
1841                       G_CALLBACK (label_leave_notify_cb), self);
1842     g_signal_connect (self->label_box, "button-release-event",
1843                       G_CALLBACK (label_button_release_cb), self);
1844     g_signal_connect (self->label_box, "expose-event",
1845                       G_CALLBACK (label_button_expose_cb), self);
1846
1847     hbox = gtk_hbox_new (FALSE, 0);
1848     gtk_widget_show (hbox);
1849     gtk_container_add (GTK_CONTAINER (self->label_box), hbox);
1850
1851     self->image = gtk_image_new ();
1852     /* leave room for drawing the expander indicator in expose handler */
1853     gtk_widget_set_size_request (self->image, 
1854                                  SYNC_UI_LIST_ICON_SIZE + INDICATOR_SIZE,
1855                                  SYNC_UI_LIST_ICON_SIZE);
1856     gtk_misc_set_alignment (GTK_MISC (self->image), 1.0, 0.5);
1857     gtk_widget_show (self->image);
1858     gtk_box_pack_start (GTK_BOX (hbox), self->image, FALSE, FALSE, 8);
1859
1860     tmp_box = gtk_hbox_new (FALSE, 0);
1861     gtk_widget_show (tmp_box);
1862     gtk_box_pack_start (GTK_BOX (hbox), tmp_box, FALSE, FALSE, 8);
1863
1864     self->label = gtk_label_new ("");
1865     gtk_label_set_max_width_chars (GTK_LABEL (self->label), 60);
1866     gtk_label_set_ellipsize (GTK_LABEL (self->label), PANGO_ELLIPSIZE_END);
1867     gtk_misc_set_alignment (GTK_MISC (self->label), 0.0, 0.5);
1868     gtk_widget_show (self->label);
1869     gtk_box_pack_start (GTK_BOX (tmp_box), self->label, FALSE, FALSE, 0);
1870
1871     self->entry = gtk_entry_new ();
1872     gtk_widget_set_no_show_all (self->entry, TRUE);
1873     gtk_box_pack_start (GTK_BOX (tmp_box), self->entry, FALSE, FALSE, 4);
1874
1875     vbox = gtk_vbox_new (FALSE, 0);
1876     gtk_widget_show (vbox);
1877     gtk_box_pack_start (GTK_BOX (tmp_box), vbox, FALSE, FALSE, 0);
1878
1879     /* TRANSLATORS: link button in service configuration form */
1880     self->link = gtk_link_button_new_with_label ("", _("Launch website"));
1881     gtk_widget_set_no_show_all (self->link, TRUE);
1882     gtk_box_pack_start (GTK_BOX (vbox), self->link, TRUE, FALSE, 0);
1883
1884     vbox = gtk_vbox_new (FALSE, 0);
1885     gtk_widget_show (vbox);
1886     gtk_box_pack_end (GTK_BOX (hbox), vbox, FALSE, FALSE, 32);
1887
1888     /* TRANSLATORS: button in service configuration form */
1889     self->button = gtk_button_new_with_label (_("Setup now"));
1890     gtk_widget_set_size_request (self->button, SYNC_UI_LIST_BTN_WIDTH, -1);
1891     g_signal_connect (self->button, "clicked",
1892                       G_CALLBACK (setup_service_clicked), self);
1893     gtk_box_pack_start (GTK_BOX (vbox), self->button, TRUE, FALSE, 0);
1894
1895     /* label_box built, now build expando_box */
1896
1897     self->expando_box = gtk_hbox_new (FALSE, 0);
1898     gtk_widget_set_no_show_all (self->expando_box, TRUE);
1899     gtk_widget_set_parent (self->expando_box, GTK_WIDGET (self));
1900
1901     self->device_selector_box = gtk_vbox_new (FALSE, 0);
1902     gtk_box_pack_start (GTK_BOX (self->expando_box), self->device_selector_box,
1903                         TRUE, TRUE, 16);
1904
1905     hbox = gtk_hbox_new (FALSE, 8);
1906     gtk_widget_show (hbox);
1907     gtk_box_pack_start (GTK_BOX (self->device_selector_box), hbox,
1908                         FALSE, TRUE, 8);
1909     self->device_text = gtk_label_new (("We don't know what this device is exactly. "
1910                                         "Please take a look at the list of "
1911                                         "supported devices and pick yours if it "
1912                                         "is listed"));
1913     gtk_widget_show (self->device_text);
1914     gtk_label_set_line_wrap (GTK_LABEL (self->device_text), TRUE);
1915     gtk_widget_set_size_request (self->device_text, 600, -1);
1916     gtk_box_pack_start (GTK_BOX (hbox), self->device_text,
1917                         FALSE, TRUE, 0);
1918
1919
1920     hbox = gtk_hbox_new (FALSE, 16);
1921     gtk_widget_show (hbox);
1922     gtk_box_pack_start (GTK_BOX (self->device_selector_box), hbox,
1923                         FALSE, TRUE, 16);
1924
1925     store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
1926     gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
1927                                           2, GTK_SORT_DESCENDING);
1928     gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), 2,
1929                                      (GtkTreeIterCompareFunc)compare_list_items,
1930                                      NULL, NULL);
1931
1932     self->combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
1933     g_object_unref (G_OBJECT (store)); 
1934     gtk_widget_set_size_request (self->combo, 200, -1);
1935     gtk_widget_show (self->combo);
1936     gtk_box_pack_start (GTK_BOX (hbox), self->combo, FALSE, TRUE, 0);
1937
1938     renderer = gtk_cell_renderer_text_new ();
1939     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(self->combo), renderer, TRUE);
1940     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(self->combo), renderer,
1941                                     "text", 0, NULL);
1942
1943     g_signal_connect (self->combo, "changed",
1944                       G_CALLBACK (device_combo_changed), self);
1945
1946
1947     self->device_select_btn = gtk_button_new_with_label ("Use these settings");
1948     gtk_widget_set_sensitive (self->device_select_btn, FALSE);
1949     gtk_widget_show (self->device_select_btn);
1950     gtk_box_pack_start (GTK_BOX (hbox), self->device_select_btn,
1951                         FALSE, TRUE, 0);
1952     g_signal_connect (self->device_select_btn, "clicked",
1953                       G_CALLBACK (device_selection_btn_clicked_cb), self);
1954
1955     /* settings_box has normal expander contents */
1956     self->settings_box = gtk_vbox_new (FALSE, 0);
1957     gtk_widget_show (self->settings_box);
1958     gtk_box_pack_start (GTK_BOX (self->expando_box), self->settings_box,
1959                         TRUE, TRUE, 16);
1960
1961     vbox = gtk_vbox_new (FALSE, 8);
1962     gtk_widget_show (vbox);
1963     gtk_box_pack_start (GTK_BOX (self->settings_box), vbox, TRUE, TRUE, 0);
1964
1965     tmp_box = gtk_vbox_new (FALSE, 0);
1966     gtk_widget_show (tmp_box);
1967     gtk_box_pack_start (GTK_BOX (vbox), tmp_box, FALSE, FALSE, 8);
1968
1969     self->description_label = gtk_label_new ("");
1970     gtk_misc_set_alignment (GTK_MISC (self->description_label), 0.0, 0.5);
1971     gtk_widget_set_size_request (self->description_label, 700, -1);
1972     gtk_box_pack_start (GTK_BOX (tmp_box), self->description_label, FALSE, FALSE, 0);
1973
1974     tmp_box = gtk_hbox_new (FALSE, 0);
1975     gtk_widget_show (tmp_box);
1976     gtk_box_pack_start (GTK_BOX (vbox), tmp_box, FALSE, FALSE, 0);
1977
1978     self->userinfo_table = gtk_table_new (4, 2, FALSE);
1979     gtk_table_set_row_spacings (GTK_TABLE (self->userinfo_table), 2);
1980     gtk_table_set_col_spacings (GTK_TABLE (self->userinfo_table), 5);
1981     gtk_widget_show (self->userinfo_table);
1982     gtk_box_pack_start (GTK_BOX (tmp_box), self->userinfo_table, FALSE, FALSE, 0);
1983
1984     /* TRANSLATORS: labels of entries in service configuration form */
1985     label = gtk_label_new (_("Username"));
1986     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1987     gtk_widget_show (label);
1988     gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), label,
1989                                0, 1,
1990                                0, 1);
1991
1992     self->username_entry = gtk_entry_new ();
1993     gtk_widget_show (self->username_entry);
1994     gtk_entry_set_width_chars (GTK_ENTRY (self->username_entry), 40);
1995     gtk_entry_set_max_length (GTK_ENTRY (self->username_entry), 99);
1996     gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), self->username_entry,
1997                                1, 2,
1998                                0, 1);
1999
2000     label = gtk_label_new (_("Password"));
2001     gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2002     gtk_widget_show (label);
2003     gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), label,
2004                                0, 1,
2005                                1, 2);
2006
2007     self->password_entry = gtk_entry_new ();
2008     gtk_widget_show (self->password_entry);
2009     gtk_entry_set_width_chars (GTK_ENTRY (self->password_entry), 40);
2010     gtk_entry_set_visibility (GTK_ENTRY (self->password_entry), FALSE);
2011     gtk_entry_set_max_length (GTK_ENTRY (self->password_entry), 99);
2012     gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), self->password_entry,
2013                                1, 2,
2014                                1, 2);
2015
2016     self->complex_config_info_bar = gtk_info_bar_new ();
2017     gtk_info_bar_set_message_type (GTK_INFO_BAR (self->complex_config_info_bar),
2018                                    GTK_MESSAGE_WARNING);
2019     gtk_box_pack_start (GTK_BOX (vbox), self->complex_config_info_bar,
2020                         FALSE, FALSE, 0);
2021     /* TRANSLATORS: warning in service configuration form for people
2022        who have modified the configuration via other means. */
2023     label = gtk_label_new (_("Current configuration is more complex "
2024                              "than what can be shown here. Changes to sync "
2025                              "mode or synced data types will overwrite that "
2026                              "configuration."));
2027     gtk_widget_set_size_request (label, 600, -1);
2028     gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
2029     gtk_widget_show (label);
2030     cont = gtk_info_bar_get_content_area (
2031         GTK_INFO_BAR (self->complex_config_info_bar));
2032     gtk_container_add (GTK_CONTAINER (cont), label);
2033
2034     self->mode_table = gtk_table_new (4, 1, FALSE);
2035     gtk_table_set_row_spacings (GTK_TABLE (self->mode_table), 2);
2036     gtk_table_set_col_spacings (GTK_TABLE (self->mode_table), 5);
2037     gtk_widget_show (self->mode_table);
2038     gtk_box_pack_start (GTK_BOX (vbox), self->mode_table, FALSE, FALSE, 0);
2039
2040     /* TRANSLATORS: this is the epander label for server settings
2041        in service configuration form */
2042     self->expander = gtk_expander_new (_("Hide server settings"));
2043     gtk_box_pack_start (GTK_BOX (vbox), self->expander, FALSE, FALSE, 8);
2044
2045     tmp_box = gtk_hbox_new (FALSE, 0);
2046     gtk_widget_show (tmp_box);
2047     gtk_container_add (GTK_CONTAINER (self->expander), tmp_box);
2048
2049     self->server_settings_table = gtk_table_new (1, 1, FALSE);
2050     gtk_table_set_row_spacings (GTK_TABLE (self->server_settings_table), 2);
2051     gtk_table_set_col_spacings (GTK_TABLE (self->server_settings_table), 5);
2052     gtk_widget_show (self->server_settings_table);
2053     gtk_box_pack_start (GTK_BOX (tmp_box), self->server_settings_table, FALSE, FALSE, 0);
2054
2055
2056     tmp_box = gtk_hbox_new (FALSE, 0);
2057     gtk_widget_show (tmp_box);
2058     gtk_box_pack_start (GTK_BOX (vbox), tmp_box, FALSE, FALSE, 8);
2059
2060     /* TRANSLATORS: this is the epander label for server settings
2061        in service configuration form */
2062     self->fake_expander = gtk_expander_new (_("Show server settings"));
2063     gtk_widget_show (self->fake_expander);
2064     gtk_box_pack_start (GTK_BOX (tmp_box), self->fake_expander, FALSE, FALSE, 0);
2065     g_signal_connect (self->fake_expander, "notify::expanded",
2066                       G_CALLBACK (server_settings_notify_expand_cb), self);
2067
2068     self->use_button = gtk_button_new ();
2069     gtk_widget_show (self->use_button);
2070     gtk_box_pack_end (GTK_BOX (tmp_box), self->use_button, FALSE, FALSE, 8);
2071     g_signal_connect (self->use_button, "clicked",
2072                       G_CALLBACK (use_clicked_cb), self);
2073
2074     self->stop_button = gtk_button_new ();
2075     gtk_box_pack_end (GTK_BOX (tmp_box), self->stop_button, FALSE, FALSE, 8);
2076     g_signal_connect (self->stop_button, "clicked",
2077                       G_CALLBACK (stop_clicked_cb), self);
2078
2079     self->reset_delete_button = gtk_button_new ();
2080     gtk_widget_show (self->reset_delete_button);
2081     gtk_box_pack_end (GTK_BOX (tmp_box), self->reset_delete_button, FALSE, FALSE, 8);
2082     g_signal_connect (self->reset_delete_button, "clicked",
2083                       G_CALLBACK (reset_delete_clicked_cb), self);
2084 }
2085
2086
2087 GtkWidget*
2088 sync_config_widget_new (SyncevoServer *server,
2089                         const char *name,
2090                         SyncevoConfig *config,
2091                         gboolean current,
2092                         const char *current_service_name,
2093                         gboolean configured,
2094                         gboolean has_template)
2095 {
2096   return g_object_new (SYNC_TYPE_CONFIG_WIDGET,
2097                        "server", server,
2098                        "name", name,
2099                        "config", config,
2100                        "current", current,
2101                        "current-service-name", current_service_name,
2102                        "configured", configured,
2103                        "has-template", has_template,
2104                        NULL);
2105 }
2106
2107 void
2108 sync_config_widget_set_expanded (SyncConfigWidget *self, gboolean expanded)
2109 {
2110     g_return_if_fail (SYNC_IS_CONFIG_WIDGET (self));
2111
2112     if (self->expanded != expanded) {
2113
2114         self->expanded = expanded;
2115         if (self->expanded) {
2116             gtk_widget_hide (self->button);
2117             gtk_widget_show (self->expando_box);
2118             if (GTK_WIDGET_VISIBLE (self->entry)) {
2119                 gtk_widget_grab_focus (self->entry);
2120             } else {
2121                 gtk_widget_grab_focus (self->username_entry);
2122             }
2123         } else {
2124             gtk_widget_show (self->button);
2125             gtk_widget_hide (self->expando_box);
2126         }
2127         g_object_notify (G_OBJECT (self), "expanded");
2128
2129     }
2130 }
2131
2132 gboolean
2133 sync_config_widget_get_expanded (SyncConfigWidget *self)
2134 {
2135     return self->expanded;
2136 }
2137
2138 void
2139 sync_config_widget_set_has_template (SyncConfigWidget *self, gboolean has_template)
2140 {
2141     if (self->has_template != has_template) {
2142         self->has_template = has_template;
2143         update_buttons (self);
2144         sync_config_widget_update_label (self);
2145     }
2146 }
2147
2148 gboolean
2149 sync_config_widget_get_has_template (SyncConfigWidget *self)
2150 {
2151     return self->has_template;
2152 }
2153
2154 void
2155 sync_config_widget_set_configured (SyncConfigWidget *self, gboolean configured)
2156 {
2157     if (self->configured != configured) {
2158         self->configured = configured;
2159         self->device_template_selected = configured;
2160         update_buttons (self);
2161     }
2162 }
2163
2164 gboolean
2165 sync_config_widget_get_configured (SyncConfigWidget *self)
2166 {
2167     return self->configured;
2168 }
2169
2170
2171 gboolean
2172 sync_config_widget_get_current (SyncConfigWidget *widget)
2173 {
2174     return widget->current;
2175 }
2176
2177 const char*
2178 sync_config_widget_get_name (SyncConfigWidget *widget)
2179 {
2180     return widget->config_name;
2181 }
2182
2183 void
2184 sync_config_widget_add_alternative_config (SyncConfigWidget *self,
2185                                            const char *template_name,
2186                                            SyncevoConfig *config,
2187                                            gboolean configured)
2188 {
2189     sync_config_widget_add_config (self, template_name, config);
2190     if (configured) {
2191         sync_config_widget_set_config (self, config);
2192         sync_config_widget_set_configured (self, TRUE);
2193     }
2194
2195
2196     sync_config_widget_update_expander (self);
2197
2198 }