syncevolution/src/gtk3-ui/sync-config-widget.c

2200 lines
74 KiB
C

#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <glib/gi18n.h>
#include <dbus/dbus-glib.h>
#include "sync-ui.h"
#include "sync-config-widget.h"
#define INDICATOR_SIZE 16
#define CHILD_PADDING 3
G_DEFINE_TYPE (SyncConfigWidget, sync_config_widget, GTK_TYPE_CONTAINER)
typedef struct source_widgets {
char *name;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *check;
GtkWidget *source_toggle_label;
guint count;
} source_widgets;
enum
{
PROP_0,
PROP_SERVER,
PROP_NAME,
PROP_CONFIG,
PROP_CURRENT,
PROP_HAS_TEMPLATE,
PROP_CONFIGURED,
PROP_CURRENT_SERVICE_NAME,
PROP_EXPANDED,
};
enum {
SIGNAL_CHANGED,
LAST_SIGNAL
};
static guint32 signals[LAST_SIGNAL] = {0, };
typedef struct save_config_data {
SyncConfigWidget *widget;
gboolean delete;
gboolean temporary;
source_widgets *widgets;
char *basename;
} save_config_data;
static void start_session_for_config_write_cb (SyncevoServer *server, char *path, GError *error, save_config_data *data);
static void sync_config_widget_update_label (SyncConfigWidget *self);
static void sync_config_widget_set_name (SyncConfigWidget *self, const char *name);
static void
remove_child (GtkWidget *widget, GtkContainer *container)
{
gtk_container_remove (container, widget);
}
const char*
get_service_description (const char *service)
{
if (!service)
return NULL;
/* TRANSLATORS: Descriptions for specific services, shown in service
* configuration form */
if (strcmp (service, "ScheduleWorld") == 0) {
return _("ScheduleWorld enables you to keep your contacts, events, "
"tasks, and notes in sync.");
}else if (strcmp (service, "Google") == 0) {
return _("Google Sync can back up and synchronize your contacts "
"with your Gmail contacts.");
}else if (strcmp (service, "Funambol") == 0) {
/* TRANSLATORS: Please include the word "demo" (or the equivalent in
your language): Funambol is going to be a 90 day demo service
in the future */
return _("Back up your contacts and calendar. Sync with a single "
"click, anytime, anywhere (DEMO).");
}else if (strcmp (service, "Mobical") == 0) {
return _("Mobical Backup and Restore service allows you to securely "
"back up your personal mobile data for free.");
}else if (strcmp (service, "ZYB") == 0) {
return _("ZYB is a simple way for people to store and share mobile "
"information online.");
}else if (strcmp (service, "Memotoo") == 0) {
return _("Memotoo lets you access your personal data from any "
"computer connected to the Internet.");
}
return NULL;
}
static void
update_source_uri (char *name,
GHashTable *source_configuration,
SyncConfigWidget *self)
{
const char *uri;
source_widgets *widgets;
widgets = (source_widgets*)g_hash_table_lookup (self->sources, name);
if (!widgets) {
return;
}
uri = gtk_entry_get_text (GTK_ENTRY (widgets->entry));
g_hash_table_insert (source_configuration, g_strdup ("uri"), g_strdup (uri));
}
static source_widgets *
source_widgets_ref (source_widgets *widgets)
{
if (widgets) {
widgets->count++;
}
return widgets;
}
static void
source_widgets_unref (source_widgets *widgets)
{
if (widgets) {
widgets->count--;
if (widgets->count == 0)
g_slice_free (source_widgets, widgets);
}
}
static void
check_source_cb (SyncevoSession *session,
GError *error,
source_widgets *widgets)
{
gboolean show = TRUE;
if (error) {
if(error->code == DBUS_GERROR_REMOTE_EXCEPTION &&
dbus_g_error_has_name (error, SYNCEVO_DBUS_ERROR_SOURCE_UNUSABLE)) {
show = FALSE;
} else {
g_warning ("CheckSource failed: %s", error->message);
/* non-fatal, ignore in UI */
}
g_error_free (error);
}
if (widgets->count > 1) {
if (show) {
/* NOTE: with the new two sources per row layout not showing things
* may look weird in some cases... the layout should really only be
* done at this point */
gtk_widget_show (widgets->source_toggle_label);
gtk_widget_show (widgets->label);
gtk_widget_show (widgets->entry);
gtk_widget_show (widgets->check);
} else {
/* next save should disable this source */
gtk_switch_set_active (GTK_SWITCH (widgets->check), FALSE);
}
}
source_widgets_unref (widgets);
g_object_unref (session);
}
static void
set_config_cb (SyncevoSession *session,
GError *error,
save_config_data *data)
{
if (error) {
g_warning ("Error in Session.SetConfig: %s", error->message);
g_error_free (error);
g_object_unref (session);
show_error_dialog (GTK_WIDGET (data->widget),
_("Sorry, failed to save the configuration"));
return;
}
if (data->temporary) {
syncevo_session_check_source (session,
data->widgets->name,
(SyncevoSessionGenericCb)check_source_cb,
data->widgets);
} else {
data->widget->configured = TRUE;
g_signal_emit (data->widget, signals[SIGNAL_CHANGED], 0);
g_object_unref (session);
}
}
static void
get_config_for_overwrite_prevention_cb (SyncevoSession *session,
SyncevoConfig *config,
GError *error,
save_config_data *data)
{
static int index = 0;
char *name;
if (error) {
index = 0;
if (error->code == DBUS_GERROR_REMOTE_EXCEPTION &&
dbus_g_error_has_name (error, SYNCEVO_DBUS_ERROR_NO_SUCH_CONFIG)) {
/* Config does not exist (as expected), we can now save */
syncevo_session_set_config (session,
data->temporary,
data->temporary,
data->widget->config,
(SyncevoSessionGenericCb)set_config_cb,
data);
return;
}
g_warning ("Unexpected error in Session.GetConfig: %s", error->message);
g_error_free (error);
g_object_unref (session);
return;
}
/* Config exists when we are trying to create a new config...
* Need to start a new session with another name */
g_object_unref (session);
name = g_strdup_printf ("%s__%d", data->basename, ++index);
sync_config_widget_set_name (data->widget, name);
g_free (name);
syncevo_server_start_no_sync_session (data->widget->server,
data->widget->config_name,
(SyncevoServerStartSessionCb)start_session_for_config_write_cb,
data);
}
static void
save_config (save_config_data *data,
SyncevoSession *session)
{
SyncConfigWidget *w = data->widget;
if (data->delete) {
syncevo_config_free (w->config);
w->config = g_hash_table_new (g_str_hash, g_str_equal);
}
/* if this is a client peer (a device) and not configured, we
* need to test that we aren't overwriting existing
* configs */
/* TODO: This might be a good thing to do for any configurations.*/
if (peer_is_client (w->config) &&
!w->configured && !data->temporary) {
syncevo_session_get_config (session,
FALSE,
(SyncevoSessionGetConfigCb)get_config_for_overwrite_prevention_cb,
data);
} else {
syncevo_session_set_config (session,
data->temporary,
data->temporary,
data->widget->config,
(SyncevoSessionGenericCb)set_config_cb,
data);
}
}
static void
status_changed_for_config_write_cb (SyncevoSession *session,
SyncevoSessionStatus status,
guint error_code,
SyncevoSourceStatuses *source_statuses,
save_config_data *data)
{
if (status == SYNCEVO_STATUS_IDLE) {
save_config (data, session);
}
}
static void
get_status_for_config_write_cb (SyncevoSession *session,
SyncevoSessionStatus status,
guint error_code,
SyncevoSourceStatuses *source_statuses,
GError *error,
save_config_data *data)
{
if (error) {
g_warning ("Error in Session.GetStatus: %s", error->message);
g_error_free (error);
g_object_unref (session);
/* TODO show in UI: save failed in service list */
return;
}
syncevo_source_statuses_free (source_statuses);
if (status == SYNCEVO_STATUS_IDLE) {
save_config (data, session);
}
}
static void
start_session_for_config_write_cb (SyncevoServer *server,
char *path,
GError *error,
save_config_data *data)
{
SyncevoSession *session;
if (error) {
g_warning ("Error in Server.StartSession: %s", error->message);
g_error_free (error);
/* TODO show in UI: save failed in service list */
return;
}
session = syncevo_session_new (path);
/* we want to know about status changes to our session */
g_signal_connect (session, "status-changed",
G_CALLBACK (status_changed_for_config_write_cb), data);
syncevo_session_get_status (session,
(SyncevoSessionGetStatusCb)get_status_for_config_write_cb,
data);
}
static void
stop_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
{
save_config_data *data;
if (!self->config) {
return;
}
syncevo_config_set_value (self->config, NULL, "defaultPeer", "");
sync_config_widget_set_current (self, FALSE);
data = g_slice_new (save_config_data);
data->widget = self;
data->delete = FALSE;
data->temporary = FALSE;
syncevo_server_start_no_sync_session (self->server,
self->config_name,
(SyncevoServerStartSessionCb)start_session_for_config_write_cb,
data);
}
static void
use_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
{
save_config_data *data;
const char *username, *password, *sync_url, *pretty_name;
char *real_url, *device;
gboolean send, receive;
SyncevoSyncMode mode;
if (!self->config) {
return;
}
if (!self->config_name || strlen (self->config_name) == 0) {
g_free (self->config_name);
self->config_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry)));
}
if (self->mode_changed) {
GHashTableIter iter;
source_widgets *widgets;
char *name;
gboolean client = peer_is_client (self->config);
send = gtk_switch_get_active (GTK_SWITCH (self->send_check));
receive = gtk_switch_get_active (GTK_SWITCH (self->receive_check));
if (send && receive) {
mode = SYNCEVO_SYNC_TWO_WAY;
} else if (send) {
mode = client ?
SYNCEVO_SYNC_ONE_WAY_FROM_SERVER :
SYNCEVO_SYNC_ONE_WAY_FROM_CLIENT;
} else if (receive) {
mode = client ?
SYNCEVO_SYNC_ONE_WAY_FROM_CLIENT :
SYNCEVO_SYNC_ONE_WAY_FROM_SERVER;
} else {
mode = SYNCEVO_SYNC_NONE;
}
g_hash_table_iter_init (&iter, self->sources);
while (g_hash_table_iter_next (&iter, (gpointer)&name, (gpointer)&widgets)) {
const char *mode_str;
gboolean active;
active = gtk_switch_get_active (GTK_SWITCH (widgets->check)) &&
gtk_widget_get_sensitive (widgets->check);
if (active) {
mode_str = syncevo_sync_mode_to_string (mode);
} else {
mode_str = "none";
}
syncevo_config_set_value (self->config, name, "sync", mode_str);
}
}
username = gtk_entry_get_text (GTK_ENTRY (self->username_entry));
syncevo_config_set_value (self->config, NULL, "username", username);
sync_url = gtk_entry_get_text (GTK_ENTRY (self->baseurl_entry));
/* make a wild guess if no scheme in url */
if (strstr (sync_url, "://") == NULL) {
real_url = g_strdup_printf ("http://%s", sync_url);
} else {
real_url = g_strdup (sync_url);
}
syncevo_config_set_value (self->config, NULL, "syncURL", real_url);
password = gtk_entry_get_text (GTK_ENTRY (self->password_entry));
syncevo_config_set_value (self->config, NULL, "password", password);
syncevo_config_get_value (self->config, NULL, "deviceName", &device);
if (!device || strlen (device) == 0) {
if (!self->config_name || strlen (self->config_name) == 0 ||
!sync_url || strlen (sync_url) == 0) {
show_error_dialog (GTK_WIDGET (self),
_("Service must have a name and server URL"));
return;
}
}
syncevo_config_foreach_source (self->config,
(ConfigFunc)update_source_uri,
self);
pretty_name = gtk_entry_get_text (GTK_ENTRY (self->entry));
syncevo_config_set_value (self->config, NULL, "PeerName", pretty_name);
syncevo_config_get_value (self->config, NULL, "PeerName", &self->pretty_name);
syncevo_config_set_value (self->config, NULL, "defaultPeer", self->config_name);
sync_config_widget_set_current (self, TRUE);
data = g_slice_new (save_config_data);
data->widget = self;
data->delete = FALSE;
data->temporary = FALSE;
data->basename = g_strdup (self->config_name);
syncevo_server_start_no_sync_session (self->server,
self->config_name,
(SyncevoServerStartSessionCb)start_session_for_config_write_cb,
data);
g_free (real_url);
}
static void
reset_delete_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
{
char *msg, *yes, *no;
save_config_data *data;
if (!self->config) {
return;
}
if (self->has_template) {
/*TRANSLATORS: warning dialog text for resetting pre-defined
services */
msg = g_strdup_printf
(_("Do you want to reset the settings for %s? "
"This will not remove any synced information on either end."),
self->pretty_name);
/*TRANSLATORS: buttons in reset-service warning dialog */
yes = _("Yes, reset");
no = _("No, keep settings");
} else {
/*TRANSLATORS: warning dialog text for deleting user-defined
services */
msg = g_strdup_printf
(_("Do you want to delete the settings for %s? "
"This will not remove any synced information on either "
"end but it will remove these settings."),
self->pretty_name);
/*TRANSLATORS: buttons in delete-service warning dialog */
yes = _("Yes, delete");
no = _("No, keep settings");
}
/*TRANSLATORS: decline button in "Reset/delete service" warning dialogs */
if (!show_confirmation (GTK_WIDGET (self), msg, yes, no)) {
g_free (msg);
return;
}
g_free (msg);
if (self->current) {
sync_config_widget_set_current (self, FALSE);
}
data = g_slice_new (save_config_data);
data->widget = self;
data->delete = TRUE;
data->temporary = FALSE;
syncevo_server_start_no_sync_session (self->server,
self->config_name,
(SyncevoServerStartSessionCb)start_session_for_config_write_cb,
data);
}
static void update_buttons (SyncConfigWidget *self)
{
if (self->has_template) {
/* TRANSLATORS: button labels in service configuration form */
gtk_button_set_label (GTK_BUTTON (self->reset_delete_button),
_("Reset settings"));
} else {
gtk_button_set_label (GTK_BUTTON (self->reset_delete_button),
_("Delete settings"));
}
if (self->configured) {
gtk_widget_show (GTK_WIDGET (self->reset_delete_button));
} else {
gtk_widget_hide (GTK_WIDGET (self->reset_delete_button));
}
if (self->current || !self->current_service_name) {
gtk_button_set_label (GTK_BUTTON (self->use_button),
_("Save and use"));
} else {
gtk_button_set_label (GTK_BUTTON (self->use_button),
_("Save and replace\ncurrent service"));
}
if (self->current && self->config) {
if (peer_is_client (self->config)) {
gtk_button_set_label (GTK_BUTTON (self->stop_button),
_("Stop using device"));
} else {
gtk_button_set_label (GTK_BUTTON (self->stop_button),
_("Stop using service"));
}
gtk_widget_show (self->stop_button);
} else {
gtk_widget_hide (self->stop_button);
}
}
static void
mode_widget_notify_active_cb (GtkWidget *widget,
GParamSpec *pspec,
SyncConfigWidget *self)
{
self->mode_changed = TRUE;
}
static void
source_entry_notify_text_cb (GObject *gobject,
GParamSpec *pspec,
source_widgets *widgets)
{
gboolean new_editable, old_editable;
const char *text;
text = gtk_entry_get_text (GTK_ENTRY (widgets->entry));
new_editable = (strlen (text) > 0);
old_editable = gtk_widget_get_sensitive (widgets->check);
if (new_editable != old_editable) {
gtk_widget_set_sensitive (widgets->check, new_editable);
gtk_switch_set_active (GTK_SWITCH (widgets->check), new_editable);
}
}
static GtkWidget*
add_toggle_widget (SyncConfigWidget *self,
const char *title,
gboolean active,
guint row, guint col)
{
GtkWidget *toggle;
int padding;
GtkWidget *label;
padding = (col == 1) ? 0 : 32;
col = col * 2;
label = gtk_label_new (title);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
gtk_widget_set_size_request (label, 260, -1);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (self->mode_table), label,
col, col + 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
toggle = gtk_switch_new ();
g_signal_connect_swapped (toggle, "hide",
G_CALLBACK (gtk_widget_hide), label);
g_signal_connect_swapped (toggle, "show",
G_CALLBACK (gtk_widget_show), label);
gtk_switch_set_active (GTK_SWITCH (toggle), active);
g_signal_connect (toggle, "notify::active",
G_CALLBACK (mode_widget_notify_active_cb), self);
gtk_table_attach (GTK_TABLE (self->mode_table), toggle,
col + 1, col + 2, row, row + 1,
GTK_FILL, GTK_FILL, padding, 0);
return toggle;
}
/* check if config includes a virtual source that covers the given
* source */
static gboolean
virtual_source_exists (SyncevoConfig *config, const char *name)
{
GHashTableIter iter;
const char *source_string;
GHashTable *source_config;
g_hash_table_iter_init (&iter, config);
while (g_hash_table_iter_next (&iter,
(gpointer)&source_string,
(gpointer)&source_config)) {
char **strs;
if (g_str_has_prefix (source_string, "source/")) {
const char *uri, *type;
type = g_hash_table_lookup (source_config, "backend");
uri = g_hash_table_lookup (source_config, "uri");
if (!uri || !type || !g_str_has_prefix (type, "virtual:")) {
/* this source is not defined, or not virtual */
continue;
}
strs = g_strsplit (source_string + 7, "+", 0);
if (g_strv_length (strs) > 1) {
int i;
for (i = 0; strs[i]; i++) {
if (g_strcmp0 (name, strs[i]) == 0) {
g_strfreev (strs);
return TRUE;
}
}
}
g_strfreev (strs);
}
}
return FALSE;
}
static void
init_source (char *name,
GHashTable *source_configuration,
SyncConfigWidget *self)
{
char *str, *pretty_name;
const char *uri, *type;
guint rows;
guint row;
static guint col = 0;
source_widgets *widgets;
SyncevoSyncMode mode;
save_config_data *data;
type = g_hash_table_lookup (source_configuration, "backend");
uri = g_hash_table_lookup (source_configuration, "uri");
if (!type || strlen (type) == 0) {
return;
}
if (g_str_has_prefix (type, "virtual:") && !uri) {
/* undefined virtual source */
return;
}
if (virtual_source_exists (self->config, name)) {
return;
}
g_object_get (self->mode_table,
"n-rows", &rows,
NULL);
if (!self->no_source_toggles && col == 0) {
col = 1;
row = rows - 1;
} else {
col = 0;
row = rows;
}
self->no_source_toggles = FALSE;
widgets = g_slice_new0 (source_widgets);
widgets->name = name;
widgets->count = 1;
g_hash_table_insert (self->sources, name, widgets);
widgets->source_toggle_label = self->source_toggle_label;
pretty_name = get_pretty_source_name (name);
mode = syncevo_sync_mode_from_string
(g_hash_table_lookup (source_configuration, "sync"));
widgets->check = add_toggle_widget (self,
pretty_name,
(mode > SYNCEVO_SYNC_NONE),
row, col);
/* TRANSLATORS: label for an entry in service configuration form.
* Placeholder is a source name.
* Example: "Appointments URI" */
str = g_strdup_printf (_("%s URI"), pretty_name);
widgets->label = gtk_label_new (str);
g_free (str);
g_free (pretty_name);
g_object_get (self->server_settings_table,
"n-rows", &row,
NULL);
gtk_misc_set_alignment (GTK_MISC (widgets->label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (self->server_settings_table), widgets->label,
0, 1, row, row + 1, GTK_FILL, GTK_EXPAND, 0, 0);
widgets->entry = gtk_entry_new ();
gtk_entry_set_max_length (GTK_ENTRY (widgets->entry), 99);
gtk_entry_set_width_chars (GTK_ENTRY (widgets->entry), 80);
if (uri) {
gtk_entry_set_text (GTK_ENTRY (widgets->entry), uri);
}
gtk_table_attach_defaults (GTK_TABLE (self->server_settings_table),
widgets->entry,
1, 2, row, row + 1);
g_signal_connect (widgets->entry, "notify::text",
G_CALLBACK (source_entry_notify_text_cb), widgets);
gtk_widget_set_sensitive (widgets->check,
uri && strlen (uri) > 0);
/* start a session so we save a temporary config so we can do
* CheckSource, and show the source-related widgets if the
* source is available */
data = g_slice_new (save_config_data);
data->widget = self;
data->delete = FALSE;
data->temporary = TRUE;
data->widgets = source_widgets_ref (widgets);
syncevo_server_start_no_sync_session (self->server,
self->config_name,
(SyncevoServerStartSessionCb)start_session_for_config_write_cb,
data);
}
static void
get_common_mode (char *name,
GHashTable *source_configuration,
SyncevoSyncMode *common_mode)
{
SyncevoSyncMode mode;
char *mode_str, *type;
type = g_hash_table_lookup (source_configuration, "backend");
if (!type || strlen (type) == 0) {
return;
}
mode_str = g_hash_table_lookup (source_configuration, "sync");
mode = syncevo_sync_mode_from_string (mode_str);
if (mode == SYNCEVO_SYNC_NONE) {
return;
}
if (*common_mode == SYNCEVO_SYNC_NONE) {
*common_mode = mode;
} else if (mode != *common_mode) {
*common_mode = SYNCEVO_SYNC_UNKNOWN;
}
}
void
sync_config_widget_expand_id (SyncConfigWidget *self,
const char *id)
{
if (id && self->config) {
char *sync_url;
if (syncevo_config_get_value (self->config, NULL,
"syncURL", &sync_url) &&
strncmp (sync_url, id, strlen (id)) == 0) {
sync_config_widget_set_expanded (self, TRUE);
} else if (self->config_name &&
g_ascii_strcasecmp (self->config_name, id) == 0) {
sync_config_widget_set_expanded (self, TRUE);
}
}
}
static void
sync_config_widget_update_expander (SyncConfigWidget *self)
{
char *username = "";
char *password = "";
char *sync_url = "";
const char *descr;
char *str;
GtkWidget *label, *align;
SyncevoSyncMode mode = SYNCEVO_SYNC_NONE;
gboolean send, receive;
gboolean client;
gtk_container_foreach (GTK_CONTAINER (self->server_settings_table),
(GtkCallback)remove_child,
self->server_settings_table);
gtk_table_resize (GTK_TABLE (self->server_settings_table),
2, 1);
gtk_container_foreach (GTK_CONTAINER (self->mode_table),
(GtkCallback)remove_child,
self->mode_table);
gtk_table_resize (GTK_TABLE (self->mode_table),
2, 1);
client = peer_is_client (self->config);
if (client) {
if (!self->device_template_selected) {
gtk_widget_hide (self->settings_box);
gtk_widget_show (self->device_selector_box);
/* temporary solution for device template selection:
* show list of templates only */
} else {
gtk_widget_show (self->settings_box);
gtk_widget_hide (self->device_selector_box);
gtk_widget_hide (self->userinfo_table);
gtk_widget_hide (self->fake_expander);
}
} else {
gtk_widget_show (self->settings_box);
gtk_widget_hide (self->device_selector_box);
gtk_widget_show (self->userinfo_table);
gtk_widget_show (self->fake_expander);
}
syncevo_config_foreach_source (self->config,
(ConfigFunc)get_common_mode,
&mode);
switch (mode) {
case SYNCEVO_SYNC_TWO_WAY:
send = receive = TRUE;
break;
case SYNCEVO_SYNC_ONE_WAY_FROM_CLIENT:
if (client) {
send = FALSE;
receive = TRUE;
} else {
send = TRUE;
receive = FALSE;
}
break;
case SYNCEVO_SYNC_ONE_WAY_FROM_SERVER:
if (client) {
send = TRUE;
receive = FALSE;
} else {
send = FALSE;
receive = TRUE;
}
break;
default:
gtk_widget_show (self->complex_config_info_bar);
send = FALSE;
receive = FALSE;
}
self->mode_changed = FALSE;
if (self->pretty_name) {
gtk_entry_set_text (GTK_ENTRY (self->entry), self->pretty_name);
}
if (!self->config_name || strlen (self->config_name) == 0) {
gtk_expander_set_expanded (GTK_EXPANDER (self->expander), TRUE);
}
descr = get_service_description (self->config_name);
if (descr) {
gtk_label_set_text (GTK_LABEL (self->description_label),
get_service_description (self->config_name));
gtk_widget_show (self->description_label);
} else {
gtk_widget_hide (self->description_label);
}
update_buttons (self);
/* TRANSLATORS: toggles in service configuration form, placeholder is service
* or device name */
str = g_strdup_printf (_("Send changes to %s"), self->pretty_name);
self->send_check = add_toggle_widget (self, str, send, 0, 0);
gtk_widget_show (self->send_check);
g_free (str);
str = g_strdup_printf (_("Receive changes from %s"), self->pretty_name);
self->receive_check = add_toggle_widget (self, str, receive, 0, 1);
gtk_widget_show (self->receive_check);
g_free (str);
align = gtk_alignment_new (0.0, 1.0, 0.0, 0.0);
gtk_alignment_set_padding (GTK_ALIGNMENT (align), 10, 0, 0, 0);
gtk_widget_show (align);
gtk_table_attach (GTK_TABLE (self->mode_table), align,
0, 1, 1, 2,
GTK_FILL, GTK_FILL, 0, 0);
self->source_toggle_label = gtk_label_new ("");
/* TRANSLATORS: Label for the source toggles in configuration form.
This is a verb, as in "Sync Calendar". */
gtk_label_set_markup (GTK_LABEL (self->source_toggle_label),
_("<b>Sync</b>"));
gtk_widget_show (self->source_toggle_label);
gtk_container_add (GTK_CONTAINER (align), self->source_toggle_label);
syncevo_config_get_value (self->config, NULL, "username", &username);
syncevo_config_get_value (self->config, NULL, "password", &password);
syncevo_config_get_value (self->config, NULL, "syncURL", &sync_url);
if (username) {
gtk_entry_set_text (GTK_ENTRY (self->username_entry), username);
}
if (password) {
gtk_entry_set_text (GTK_ENTRY (self->password_entry), password);
}
// TRANSLATORS: label of a entry in service configuration
label = gtk_label_new (_("Server address"));
gtk_misc_set_alignment (GTK_MISC (label), 9.0, 0.5);
gtk_widget_show (label);
gtk_table_attach (GTK_TABLE (self->server_settings_table), label,
0, 1, 0, 1, GTK_FILL, GTK_EXPAND, 0, 0);
self->baseurl_entry = gtk_entry_new ();
gtk_entry_set_max_length (GTK_ENTRY (self->baseurl_entry), 99);
gtk_entry_set_width_chars (GTK_ENTRY (self->baseurl_entry), 80);
if (sync_url) {
gtk_entry_set_text (GTK_ENTRY (self->baseurl_entry), sync_url);
}
gtk_widget_show (self->baseurl_entry);
gtk_table_attach_defaults (GTK_TABLE (self->server_settings_table),
self->baseurl_entry,
1, 2, 0, 1);
/* update source widgets */
if (self->sources) {
g_hash_table_destroy (self->sources);
}
self->sources = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
(GDestroyNotify)source_widgets_unref);
self->no_source_toggles = TRUE;
syncevo_config_foreach_source (self->config,
(ConfigFunc)init_source,
self);
}
/* only adds config to hashtable and combo */
static void
sync_config_widget_add_config (SyncConfigWidget *self,
const char *name,
SyncevoConfig *config)
{
GtkListStore *store;
GtkTreeIter iter;
const char *guess_name;
SyncevoConfig *guess_config;
int score = 1;
int guess_score, second_guess_score = -1;
char *str;
store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (self->combo)));
if (syncevo_config_get_value (config, NULL, "score", &str)) {
score = (int)strtol (str, NULL, 10);
}
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
0, name,
1, config,
2, score,
-1);
/* make an educated guess if possible */
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
0, &guess_name,
1, &guess_config,
2, &guess_score,
-1);
if (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter)) {
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
2, &second_guess_score,
-1);
}
if (guess_score > 1 && guess_score > second_guess_score) {
gtk_combo_box_set_active (GTK_COMBO_BOX (self->combo), 0);
/* TRANSLATORS: explanation before a device template combobox.
* Placeholder is a device name like 'Nokia N85' or 'Syncevolution
* Client' */
str = g_strdup_printf (_("This device looks like it might be a '%s'. "
"If this is not correct, please take a look at "
"the list of supported devices and pick yours "
"if it is listed"), guess_name);
} else {
gtk_combo_box_set_active (GTK_COMBO_BOX (self->combo), -1);
str = g_strdup (_("We don't know what this device is exactly. "
"Please take a look at the list of "
"supported devices and pick yours if it "
"is listed"));
}
gtk_label_set_text (GTK_LABEL (self->device_text), str);
g_free (str);
}
static void
sync_config_widget_update_pretty_name (SyncConfigWidget *self)
{
self->pretty_name = NULL;
if (self->config) {
syncevo_config_get_value (self->config, NULL,
"PeerName", &self->pretty_name);
if (!self->pretty_name) {
syncevo_config_get_value (self->config, NULL,
"deviceName", &self->pretty_name);
}
}
if (!self->pretty_name) {
self->pretty_name = self->config_name;
}
}
static void
sync_config_widget_set_config (SyncConfigWidget *self,
SyncevoConfig *config)
{
self->config = config;
sync_config_widget_update_pretty_name (self);
}
static void
setup_service_clicked (GtkButton *btn, SyncConfigWidget *self)
{
sync_config_widget_set_expanded (self, TRUE);
}
static void
sync_config_widget_set_name (SyncConfigWidget *self,
const char *name)
{
g_free (self->config_name);
self->config_name = g_strdup (name);
sync_config_widget_update_pretty_name (self);
}
static void
device_selection_btn_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
{
GtkTreeIter iter;
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->combo), &iter)) {
const char *name;
SyncevoConfig *config;
GtkTreeModel *model;
self->device_template_selected = TRUE;
model = gtk_combo_box_get_model(GTK_COMBO_BOX (self->combo));
gtk_tree_model_get (model, &iter, 0, &name, -1 );
gtk_tree_model_get (model, &iter, 1, &config, -1 );
sync_config_widget_set_config (self, config);
sync_config_widget_update_expander (self);
}
}
static void
server_settings_notify_expand_cb (GtkExpander *expander,
GParamSpec *pspec,
SyncConfigWidget *self)
{
/* NOTE: expander can be the fake or real one... */
if (gtk_expander_get_expanded (GTK_EXPANDER (self->fake_expander))) {
g_signal_handlers_disconnect_by_func (self->fake_expander,
server_settings_notify_expand_cb,
self);
gtk_widget_hide (self->fake_expander);
gtk_expander_set_expanded (GTK_EXPANDER (self->fake_expander), FALSE);
gtk_expander_set_expanded (GTK_EXPANDER (self->expander), TRUE);
gtk_widget_show (self->expander);
g_signal_connect (self->expander, "notify::expanded",
G_CALLBACK (server_settings_notify_expand_cb), self);
} else {
g_signal_handlers_disconnect_by_func (self->expander,
server_settings_notify_expand_cb,
self);
gtk_widget_hide (self->expander);
gtk_widget_show (self->fake_expander);
g_signal_connect (self->fake_expander, "notify::expanded",
G_CALLBACK (server_settings_notify_expand_cb), self);
}
}
static GdkPixbuf*
load_icon (const char *uri, guint icon_size)
{
GError *error = NULL;
GdkPixbuf *pixbuf;
const char *filename;
if (uri && strlen (uri) > 0) {
if (g_str_has_prefix (uri, "file://")) {
filename = uri+7;
} else {
g_warning ("only file:// icon uri is supported: %s", uri);
filename = THEMEDIR "sync-generic.png";
}
} else {
filename = THEMEDIR "sync-generic.png";
}
pixbuf = gdk_pixbuf_new_from_file_at_scale (filename,
icon_size, icon_size,
TRUE, &error);
if (!pixbuf) {
g_warning ("Failed to load service icon: %s", error->message);
g_error_free (error);
return NULL;
}
return pixbuf;
}
static void
sync_config_widget_update_label (SyncConfigWidget *self)
{
if (self->config && self->pretty_name) {
char *url, *sync_url;
char *str;
syncevo_config_get_value (self->config, NULL, "WebURL", &url);
syncevo_config_get_value (self->config, NULL, "syncURL", &sync_url);
if (self->current) {
str = g_strdup_printf ("<b>%s</b>", self->pretty_name);
} else {
str = g_strdup_printf ("%s", self->pretty_name);
}
if (g_str_has_prefix (sync_url, "obex-bt://")) {
char *tmp = g_strdup_printf (_("%s - Bluetooth device"), str);
g_free (str);
str = tmp;
} else if (!self->has_template) {
/* TRANSLATORS: service title for services that are not based on a
* template in service list, the placeholder is the name of the service */
char *tmp = g_strdup_printf (_("%s - manually setup"), str);
g_free (str);
str = tmp;
} else if (url && strlen (url) > 0) {
char *tmp = g_strdup_printf ("%s -",str);
g_free (str);
str = tmp;
}
gtk_label_set_markup (GTK_LABEL (self->label), str);
g_free (str);
}
}
void
sync_config_widget_set_current_service_name (SyncConfigWidget *self,
const char *name)
{
g_free (self->current_service_name);
self->current_service_name = g_strdup (name);
update_buttons (self);
}
void
sync_config_widget_set_current (SyncConfigWidget *self,
gboolean current)
{
if (self->current != current) {
self->current = current;
sync_config_widget_update_label (self);
}
}
static void
set_session (SyncConfigWidget *self, const char *path)
{
g_free (self->running_session);
self->running_session = g_strdup (path);
gtk_widget_set_sensitive (GTK_WIDGET (self->reset_delete_button),
!self->running_session);
gtk_widget_set_sensitive (GTK_WIDGET (self->use_button),
!self->running_session);
/* TODO: maybe add a explanation text somewhere:
* "Configuration changes are not possible while a sync is in progress" */
}
static void
session_changed_cb (SyncevoServer *server,
char *path,
gboolean started,
SyncConfigWidget *self)
{
if (started) {
set_session (self, path);
} else if (g_strcmp0 (self->running_session, path) == 0 ) {
set_session (self, NULL);
}
}
static void
get_sessions_cb (SyncevoServer *server,
SyncevoSessions *sessions,
GError *error,
SyncConfigWidget *self)
{
if (error) {
g_warning ("Server.GetSessions failed: %s", error->message);
g_error_free (error);
/* non-fatal, ignore in UI */
g_object_unref (self);
return;
}
set_session (self, syncevo_sessions_index (sessions, 0));
syncevo_sessions_free (sessions);
g_object_unref (self);
}
void
sync_config_widget_set_server (SyncConfigWidget *self,
SyncevoServer *server)
{
if (self->server) {
g_signal_handlers_disconnect_by_func (self->server,
session_changed_cb,
self);
g_object_unref (self->server);
self->server = NULL;
}
if (!server && !self->server) {
return;
}
self->server = g_object_ref (server);
/* monitor sessions so we can set editing buttons insensitive */
g_signal_connect (self->server, "session-changed",
G_CALLBACK (session_changed_cb), self);
/* reference is released in callback */
g_object_ref (self);
syncevo_server_get_sessions (self->server,
(SyncevoServerGetSessionsCb)get_sessions_cb,
self);
}
static void
sync_config_widget_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (object);
switch (property_id) {
case PROP_SERVER:
sync_config_widget_set_server (self, g_value_get_pointer (value));
break;
case PROP_NAME:
sync_config_widget_set_name (self, g_value_get_string (value));
break;
case PROP_CONFIG:
sync_config_widget_set_config (self, g_value_get_pointer (value));
break;
case PROP_CURRENT:
sync_config_widget_set_current (self, g_value_get_boolean (value));
break;
case PROP_HAS_TEMPLATE:
sync_config_widget_set_has_template (self, g_value_get_boolean (value));
break;
case PROP_CONFIGURED:
sync_config_widget_set_configured (self, g_value_get_boolean (value));
break;
case PROP_CURRENT_SERVICE_NAME:
sync_config_widget_set_current_service_name (self, g_value_get_string (value));
break;
case PROP_EXPANDED:
sync_config_widget_set_expanded (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
sync_config_widget_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (object);
switch (property_id) {
case PROP_SERVER:
g_value_set_pointer (value, self->server);
case PROP_NAME:
g_value_set_string (value, self->config_name);
case PROP_CONFIG:
g_value_set_pointer (value, self->config);
case PROP_CURRENT:
g_value_set_boolean (value, self->current);
case PROP_HAS_TEMPLATE:
g_value_set_boolean (value, self->has_template);
case PROP_CONFIGURED:
g_value_set_boolean (value, self->configured);
case PROP_CURRENT_SERVICE_NAME:
g_value_set_string (value, self->current_service_name);
case PROP_EXPANDED:
g_value_set_boolean (value, self->expanded);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
sync_config_widget_dispose (GObject *object)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (object);
sync_config_widget_set_server (self, NULL);
if (self->config) {
syncevo_config_free (self->config);
}
self->config = NULL;
g_free (self->config_name);
self->config_name = NULL;
g_free (self->current_service_name);
self->current_service_name = NULL;
g_free (self->running_session);
self->running_session = NULL;
if (self->sources) {
g_hash_table_destroy (self->sources);
self->sources = NULL;
}
G_OBJECT_CLASS (sync_config_widget_parent_class)->dispose (object);
}
static void
init_default_config (SyncConfigWidget *self)
{
sync_config_widget_set_name (self, "");
self->has_template = FALSE;
syncevo_config_set_value (self->config, NULL, "username", "");
syncevo_config_set_value (self->config, NULL, "password", "");
syncevo_config_set_value (self->config, NULL, "syncURL", "");
syncevo_config_set_value (self->config, NULL, "WebURL", "");
syncevo_config_set_value (self->config, "memo", "uri", "");
syncevo_config_set_value (self->config, "todo", "uri", "");
syncevo_config_set_value (self->config, "addressbook", "uri", "");
syncevo_config_set_value (self->config, "calendar", "uri", "");
}
static gboolean
label_button_draw_cb (GtkWidget *widget,
cairo_t *cr,
SyncConfigWidget *self)
{
GtkExpanderStyle style;
gint indicator_x, indicator_y;
GtkAllocation alloc;
gtk_widget_get_allocation (widget, &alloc);
indicator_x = gtk_widget_get_style (widget)->xthickness + INDICATOR_SIZE / 2;
indicator_y = gtk_widget_get_style (widget)->ythickness +
alloc.height / 2;
if (self->expanded) {
style = GTK_EXPANDER_EXPANDED;
} else {
style = GTK_EXPANDER_COLLAPSED;
}
gtk_paint_expander (gtk_widget_get_style (widget),
cr,
gtk_widget_get_state (widget),
GTK_WIDGET (self),
NULL,
indicator_x,
indicator_y,
style);
return FALSE;
}
static gboolean
sync_config_widget_draw (GtkWidget *widget,
cairo_t *cr)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
GtkAllocation alloc;
gtk_widget_get_allocation (widget, &alloc);
/* should really use _render_frame() ... */
gtk_paint_box (gtk_widget_get_style (widget),
cr,
gtk_widget_get_state (widget),
GTK_SHADOW_OUT,
widget,
NULL,
0, 0,
alloc.width, alloc.height);
gtk_container_propagate_draw (GTK_CONTAINER (self),
self->label_box, cr);
gtk_container_propagate_draw (GTK_CONTAINER (self),
self->expando_box, cr);
return FALSE;
}
static void
sync_config_widget_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkRequisition req;
GtkAllocation alloc;
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
GTK_WIDGET_CLASS (sync_config_widget_parent_class)->size_allocate (widget,
allocation);
gtk_widget_size_request (self->label_box, &req);
alloc.x = allocation->x + gtk_widget_get_style (widget)->xthickness;
alloc.y = allocation->y + gtk_widget_get_style (widget)->ythickness;
alloc.width = allocation->width - 2 * gtk_widget_get_style (widget)->xthickness;
alloc.height = req.height;
gtk_widget_size_allocate (self->label_box, &alloc);
if (self->expanded) {
gtk_widget_size_request (self->expando_box, &req);
alloc.x = allocation->x + 2 * gtk_widget_get_style (widget)->xthickness;
alloc.y = allocation->y + gtk_widget_get_style (widget)->ythickness +
alloc.height + CHILD_PADDING;
alloc.width = allocation->width - 4 * gtk_widget_get_style (widget)->xthickness;
alloc.height = req.height;
gtk_widget_size_allocate (self->expando_box, &alloc);
}
}
static void
sync_config_widget_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
GtkRequisition req;
requisition->width = gtk_widget_get_style (widget)->xthickness * 2;
requisition->height = gtk_widget_get_style (widget)->ythickness * 2;
gtk_widget_size_request (self->label_box, &req);
requisition->width += req.width;
requisition->height = MAX (req.height, INDICATOR_SIZE) +
gtk_widget_get_style (widget)->ythickness * 2;
if (self->expanded) {
gtk_widget_size_request (self->expando_box, &req);
requisition->width = MAX (requisition->width,
req.width + gtk_widget_get_style (widget)->xthickness * 4);
requisition->height += req.height + 2 * gtk_widget_get_style (widget)->ythickness;
}
}
static void
sync_config_widget_get_preferred_width (GtkWidget *widget,
gint *minimal_width,
gint *natural_width)
{
GtkRequisition requisition;
sync_config_widget_size_request (widget, &requisition);
*minimal_width = *natural_width = requisition.width;
}
static void
sync_config_widget_get_preferred_height (GtkWidget *widget,
gint *minimal_height,
gint *natural_height)
{
GtkRequisition requisition;
sync_config_widget_size_request (widget, &requisition);
*minimal_height = *natural_height = requisition.height;
}
static GObject *
sync_config_widget_constructor (GType gtype,
guint n_properties,
GObjectConstructParam *properties)
{
SyncConfigWidget *self;
GObjectClass *parent_class;
char *url, *icon;
GdkPixbuf *buf;
parent_class = G_OBJECT_CLASS (sync_config_widget_parent_class);
self = SYNC_CONFIG_WIDGET (parent_class->constructor (gtype,
n_properties,
properties));
if (!self->config || !self->server) {
g_warning ("No SyncevoServer or Syncevoconfig set for SyncConfigWidget");
return G_OBJECT (self);
}
if (g_strcmp0 (self->config_name, "default") == 0) {
init_default_config (self);
gtk_widget_show (self->entry);
gtk_widget_hide (self->label);
} else {
gtk_widget_hide (self->entry);
gtk_widget_show (self->label);
}
syncevo_config_get_value (self->config, NULL, "WebURL", &url);
syncevo_config_get_value (self->config, NULL, "IconURI", &icon);
buf = load_icon (icon, SYNC_UI_LIST_ICON_SIZE);
gtk_image_set_from_pixbuf (GTK_IMAGE (self->image), buf);
g_object_unref (buf);
if (url && strlen (url) > 0) {
gtk_link_button_set_uri (GTK_LINK_BUTTON (self->link), url);
gtk_widget_show (self->link);
} else {
gtk_widget_hide (self->link);
}
sync_config_widget_update_label (self);
sync_config_widget_update_expander (self);
/* hack to get focus in the right place on "Setup new service" */
if (gtk_widget_get_visible (self->entry)) {
gtk_widget_grab_focus (self->entry);
}
return G_OBJECT (self);
}
static void
sync_config_widget_map (GtkWidget *widget)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
if (self->label_box && gtk_widget_get_visible (self->expando_box)) {
gtk_widget_map (self->label_box);
}
if (self->expando_box && gtk_widget_get_visible (self->expando_box)) {
gtk_widget_map (self->expando_box);
}
GTK_WIDGET_CLASS (sync_config_widget_parent_class)->map (widget);
}
static void
sync_config_widget_unmap (GtkWidget *widget)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
GTK_WIDGET_CLASS (sync_config_widget_parent_class)->unmap (widget);
if (self->label_box) {
gtk_widget_unmap (self->label_box);
}
if (self->expando_box) {
gtk_widget_unmap (self->expando_box);
}
}
static void
sync_config_widget_add (GtkContainer *container,
GtkWidget *widget)
{
g_warning ("Can't add widgets in to SyncConfigWidget!");
}
static void
sync_config_widget_remove (GtkContainer *container,
GtkWidget *widget)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (container);
if (self->label_box == widget) {
gtk_widget_unparent (widget);
self->label_box = NULL;
}
if (self->expando_box == widget) {
gtk_widget_unparent (widget);
self->expando_box = NULL;
}
}
static void
sync_config_widget_forall (GtkContainer *container,
gboolean include_internals,
GtkCallback callback,
gpointer callback_data)
{
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (container);
if (self->label_box) {
(* callback) (self->label_box, callback_data);
}
if (self->expando_box) {
(* callback) (self->expando_box, callback_data);
}
}
static void
sync_config_widget_class_init (SyncConfigWidgetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *w_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *c_class = GTK_CONTAINER_CLASS (klass);
GParamSpec *pspec;
object_class->set_property = sync_config_widget_set_property;
object_class->get_property = sync_config_widget_get_property;
object_class->dispose = sync_config_widget_dispose;
object_class->constructor = sync_config_widget_constructor;
w_class->draw = sync_config_widget_draw;
w_class->get_preferred_width = sync_config_widget_get_preferred_width;
w_class->get_preferred_height = sync_config_widget_get_preferred_height;
w_class->size_allocate = sync_config_widget_size_allocate;
w_class->map = sync_config_widget_map;
w_class->unmap = sync_config_widget_unmap;
c_class->add = sync_config_widget_add;
c_class->remove = sync_config_widget_remove;
c_class->forall = sync_config_widget_forall;
pspec = g_param_spec_pointer ("server",
"SyncevoServer",
"The SyncevoServer to use in Syncevolution DBus calls",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_SERVER, pspec);
pspec = g_param_spec_string ("name",
"Configuration name",
"The name of the Syncevolution service configuration",
NULL,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_NAME, pspec);
pspec = g_param_spec_pointer ("config",
"SyncevoConfig",
"The SyncevoConfig struct this widget represents. Takes ownership.",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_CONFIG, pspec);
pspec = g_param_spec_boolean ("current",
"Current",
"Whether the service is currently used",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_CURRENT, pspec);
pspec = g_param_spec_boolean ("has-template",
"has template",
"Whether the service has a matching template",
FALSE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_HAS_TEMPLATE, pspec);
pspec = g_param_spec_boolean ("configured",
"Configured",
"Whether the service has a configuration already",
FALSE,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_CONFIGURED, pspec);
pspec = g_param_spec_string ("current-service-name",
"Current service name",
"The name of the currently used service or NULL",
NULL,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_CURRENT_SERVICE_NAME, pspec);
pspec = g_param_spec_boolean ("expanded",
"Expanded",
"Whether the expander is open or closed",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_EXPANDED, pspec);
signals[SIGNAL_CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
G_STRUCT_OFFSET (SyncConfigWidgetClass, changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void
label_enter_notify_cb (GtkWidget *widget,
GdkEventCrossing *event,
SyncConfigWidget *self)
{
if (!self->expanded) {
gtk_widget_show (self->button);
}
gtk_widget_set_state (self->label_box, GTK_STATE_PRELIGHT);
}
static void
label_leave_notify_cb (GtkWidget *widget,
GdkEventCrossing *event,
SyncConfigWidget *self)
{
if (event->detail != GDK_NOTIFY_INFERIOR) {
gtk_widget_hide (self->button);
gtk_widget_set_state (self->label_box, GTK_STATE_NORMAL);
}
}
static void
device_combo_changed (GtkComboBox *combo,
SyncConfigWidget *self)
{
int active;
active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
gtk_widget_set_sensitive (self->device_select_btn, active > -1);
}
static void
label_button_release_cb (GtkWidget *widget,
GdkEventButton *event,
SyncConfigWidget *self)
{
if (event->button == 1) {
sync_config_widget_set_expanded (self,
!sync_config_widget_get_expanded (self));
}
}
static gint
compare_list_items (GtkTreeModel *model,
GtkTreeIter *a,
GtkTreeIter *b,
SyncConfigWidget *self)
{
int score_a, score_b;
gtk_tree_model_get(model, a, 2, &score_a, -1);
gtk_tree_model_get(model, b, 2, &score_b, -1);
return score_a - score_b;
}
static void
sync_config_widget_init (SyncConfigWidget *self)
{
GtkWidget *tmp_box, *hbox, *cont, *vbox, *label;
GtkListStore *store;
GtkCellRenderer *renderer;
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
self->label_box = gtk_event_box_new ();
gtk_widget_set_app_paintable (self->label_box, TRUE);
gtk_widget_show (self->label_box);
gtk_widget_set_parent (self->label_box, GTK_WIDGET (self));
gtk_widget_set_size_request (self->label_box, -1, SYNC_UI_LIST_ICON_SIZE + 6);
g_signal_connect (self->label_box, "enter-notify-event",
G_CALLBACK (label_enter_notify_cb), self);
g_signal_connect (self->label_box, "leave-notify-event",
G_CALLBACK (label_leave_notify_cb), self);
g_signal_connect (self->label_box, "button-release-event",
G_CALLBACK (label_button_release_cb), self);
g_signal_connect (self->label_box, "draw",
G_CALLBACK (label_button_draw_cb), self);
hbox = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox);
gtk_container_add (GTK_CONTAINER (self->label_box), hbox);
self->image = gtk_image_new ();
/* leave room for drawing the expander indicator in expose handler */
gtk_widget_set_size_request (self->image,
SYNC_UI_LIST_ICON_SIZE + INDICATOR_SIZE,
SYNC_UI_LIST_ICON_SIZE);
gtk_misc_set_alignment (GTK_MISC (self->image), 1.0, 0.5);
gtk_widget_show (self->image);
gtk_box_pack_start (GTK_BOX (hbox), self->image, FALSE, FALSE, 8);
tmp_box = gtk_hbox_new (FALSE, 0);
gtk_widget_show (tmp_box);
gtk_box_pack_start (GTK_BOX (hbox), tmp_box, FALSE, FALSE, 8);
self->label = gtk_label_new ("");
gtk_label_set_max_width_chars (GTK_LABEL (self->label), 60);
gtk_label_set_ellipsize (GTK_LABEL (self->label), PANGO_ELLIPSIZE_END);
gtk_misc_set_alignment (GTK_MISC (self->label), 0.0, 0.5);
gtk_widget_show (self->label);
gtk_box_pack_start (GTK_BOX (tmp_box), self->label, FALSE, FALSE, 0);
self->entry = gtk_entry_new ();
gtk_widget_set_no_show_all (self->entry, TRUE);
gtk_box_pack_start (GTK_BOX (tmp_box), self->entry, FALSE, FALSE, 4);
vbox = gtk_vbox_new (FALSE, 0);
gtk_widget_show (vbox);
gtk_box_pack_start (GTK_BOX (tmp_box), vbox, FALSE, FALSE, 0);
/* TRANSLATORS: link button in service configuration form */
self->link = gtk_link_button_new_with_label ("", _("Launch website"));
gtk_widget_set_no_show_all (self->link, TRUE);
gtk_box_pack_start (GTK_BOX (vbox), self->link, TRUE, FALSE, 0);
vbox = gtk_vbox_new (FALSE, 0);
gtk_widget_show (vbox);
gtk_box_pack_end (GTK_BOX (hbox), vbox, FALSE, FALSE, 32);
/* TRANSLATORS: button in service configuration form */
self->button = gtk_button_new_with_label (_("Set up now"));
gtk_widget_set_size_request (self->button, SYNC_UI_LIST_BTN_WIDTH, -1);
g_signal_connect (self->button, "clicked",
G_CALLBACK (setup_service_clicked), self);
gtk_box_pack_start (GTK_BOX (vbox), self->button, TRUE, FALSE, 0);
/* label_box built, now build expando_box */
self->expando_box = gtk_hbox_new (FALSE, 0);
gtk_widget_set_no_show_all (self->expando_box, TRUE);
gtk_widget_set_parent (self->expando_box, GTK_WIDGET (self));
self->device_selector_box = gtk_vbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (self->expando_box), self->device_selector_box,
TRUE, TRUE, 16);
hbox = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (self->device_selector_box), hbox,
FALSE, TRUE, 8);
self->device_text = gtk_label_new (_("We don't know what this device is exactly. "
"Please take a look at the list of "
"supported devices and pick yours if it "
"is listed"));
gtk_widget_show (self->device_text);
gtk_label_set_line_wrap (GTK_LABEL (self->device_text), TRUE);
gtk_widget_set_size_request (self->device_text, 600, -1);
gtk_box_pack_start (GTK_BOX (hbox), self->device_text,
FALSE, TRUE, 0);
hbox = gtk_hbox_new (FALSE, 16);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (self->device_selector_box), hbox,
FALSE, TRUE, 16);
store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
2, GTK_SORT_DESCENDING);
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), 2,
(GtkTreeIterCompareFunc)compare_list_items,
NULL, NULL);
self->combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
g_object_unref (G_OBJECT (store));
gtk_widget_set_size_request (self->combo, 200, -1);
gtk_widget_show (self->combo);
gtk_box_pack_start (GTK_BOX (hbox), self->combo, FALSE, TRUE, 0);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(self->combo), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(self->combo), renderer,
"text", 0, NULL);
g_signal_connect (self->combo, "changed",
G_CALLBACK (device_combo_changed), self);
self->device_select_btn = gtk_button_new_with_label (_("Use these settings"));
gtk_widget_set_sensitive (self->device_select_btn, FALSE);
gtk_widget_show (self->device_select_btn);
gtk_box_pack_start (GTK_BOX (hbox), self->device_select_btn,
FALSE, TRUE, 0);
g_signal_connect (self->device_select_btn, "clicked",
G_CALLBACK (device_selection_btn_clicked_cb), self);
/* settings_box has normal expander contents */
self->settings_box = gtk_vbox_new (FALSE, 0);
gtk_widget_show (self->settings_box);
gtk_box_pack_start (GTK_BOX (self->expando_box), self->settings_box,
TRUE, TRUE, 16);
vbox = gtk_vbox_new (FALSE, 8);
gtk_widget_show (vbox);
gtk_box_pack_start (GTK_BOX (self->settings_box), vbox, TRUE, TRUE, 0);
tmp_box = gtk_vbox_new (FALSE, 0);
gtk_widget_show (tmp_box);
gtk_box_pack_start (GTK_BOX (vbox), tmp_box, FALSE, FALSE, 8);
self->description_label = gtk_label_new ("");
gtk_misc_set_alignment (GTK_MISC (self->description_label), 0.0, 0.5);
gtk_widget_set_size_request (self->description_label, 700, -1);
gtk_label_set_line_wrap (GTK_LABEL (self->description_label), TRUE);
gtk_box_pack_start (GTK_BOX (tmp_box), self->description_label, FALSE, FALSE, 0);
tmp_box = gtk_hbox_new (FALSE, 0);
gtk_widget_show (tmp_box);
gtk_box_pack_start (GTK_BOX (vbox), tmp_box, FALSE, FALSE, 0);
self->userinfo_table = gtk_table_new (4, 2, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (self->userinfo_table), 2);
gtk_table_set_col_spacings (GTK_TABLE (self->userinfo_table), 5);
gtk_widget_show (self->userinfo_table);
gtk_box_pack_start (GTK_BOX (tmp_box), self->userinfo_table, FALSE, FALSE, 0);
/* TRANSLATORS: labels of entries in service configuration form */
label = gtk_label_new (_("Username"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_widget_show (label);
gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), label,
0, 1,
0, 1);
self->username_entry = gtk_entry_new ();
gtk_widget_show (self->username_entry);
gtk_entry_set_width_chars (GTK_ENTRY (self->username_entry), 40);
gtk_entry_set_max_length (GTK_ENTRY (self->username_entry), 99);
gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), self->username_entry,
1, 2,
0, 1);
label = gtk_label_new (_("Password"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_widget_show (label);
gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), label,
0, 1,
1, 2);
self->password_entry = gtk_entry_new ();
gtk_widget_show (self->password_entry);
gtk_entry_set_width_chars (GTK_ENTRY (self->password_entry), 40);
gtk_entry_set_visibility (GTK_ENTRY (self->password_entry), FALSE);
gtk_entry_set_max_length (GTK_ENTRY (self->password_entry), 99);
gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), self->password_entry,
1, 2,
1, 2);
self->complex_config_info_bar = gtk_info_bar_new ();
gtk_info_bar_set_message_type (GTK_INFO_BAR (self->complex_config_info_bar),
GTK_MESSAGE_WARNING);
gtk_box_pack_start (GTK_BOX (vbox), self->complex_config_info_bar,
FALSE, FALSE, 0);
/* TRANSLATORS: warning in service configuration form for people
who have modified the configuration via other means. */
label = gtk_label_new (_("Current configuration is more complex "
"than what can be shown here. Changes to sync "
"mode or synced data types will overwrite that "
"configuration."));
gtk_widget_set_size_request (label, 600, -1);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_widget_show (label);
cont = gtk_info_bar_get_content_area (
GTK_INFO_BAR (self->complex_config_info_bar));
gtk_container_add (GTK_CONTAINER (cont), label);
self->mode_table = gtk_table_new (4, 1, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (self->mode_table), 2);
gtk_table_set_col_spacings (GTK_TABLE (self->mode_table), 5);
gtk_widget_show (self->mode_table);
gtk_box_pack_start (GTK_BOX (vbox), self->mode_table, FALSE, FALSE, 0);
/* TRANSLATORS: this is the epander label for server settings
in service configuration form */
self->expander = gtk_expander_new (_("Hide server settings"));
gtk_box_pack_start (GTK_BOX (vbox), self->expander, FALSE, FALSE, 8);
tmp_box = gtk_hbox_new (FALSE, 0);
gtk_widget_show (tmp_box);
gtk_container_add (GTK_CONTAINER (self->expander), tmp_box);
self->server_settings_table = gtk_table_new (1, 1, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (self->server_settings_table), 2);
gtk_table_set_col_spacings (GTK_TABLE (self->server_settings_table), 5);
gtk_widget_show (self->server_settings_table);
gtk_box_pack_start (GTK_BOX (tmp_box), self->server_settings_table, FALSE, FALSE, 0);
tmp_box = gtk_hbox_new (FALSE, 0);
gtk_widget_show (tmp_box);
gtk_box_pack_start (GTK_BOX (vbox), tmp_box, FALSE, FALSE, 8);
/* TRANSLATORS: this is the epander label for server settings
in service configuration form */
self->fake_expander = gtk_expander_new (_("Show server settings"));
gtk_widget_show (self->fake_expander);
gtk_box_pack_start (GTK_BOX (tmp_box), self->fake_expander, FALSE, FALSE, 0);
g_signal_connect (self->fake_expander, "notify::expanded",
G_CALLBACK (server_settings_notify_expand_cb), self);
self->use_button = gtk_button_new ();
gtk_widget_show (self->use_button);
gtk_box_pack_end (GTK_BOX (tmp_box), self->use_button, FALSE, FALSE, 8);
g_signal_connect (self->use_button, "clicked",
G_CALLBACK (use_clicked_cb), self);
self->stop_button = gtk_button_new ();
gtk_box_pack_end (GTK_BOX (tmp_box), self->stop_button, FALSE, FALSE, 8);
g_signal_connect (self->stop_button, "clicked",
G_CALLBACK (stop_clicked_cb), self);
self->reset_delete_button = gtk_button_new ();
gtk_widget_show (self->reset_delete_button);
gtk_box_pack_end (GTK_BOX (tmp_box), self->reset_delete_button, FALSE, FALSE, 8);
g_signal_connect (self->reset_delete_button, "clicked",
G_CALLBACK (reset_delete_clicked_cb), self);
}
GtkWidget*
sync_config_widget_new (SyncevoServer *server,
const char *name,
SyncevoConfig *config,
gboolean current,
const char *current_service_name,
gboolean configured,
gboolean has_template)
{
return g_object_new (SYNC_TYPE_CONFIG_WIDGET,
"server", server,
"name", name,
"config", config,
"current", current,
"current-service-name", current_service_name,
"configured", configured,
"has-template", has_template,
NULL);
}
void
sync_config_widget_set_expanded (SyncConfigWidget *self, gboolean expanded)
{
g_return_if_fail (SYNC_IS_CONFIG_WIDGET (self));
if (self->expanded != expanded) {
self->expanded = expanded;
if (self->expanded) {
gtk_widget_hide (self->button);
gtk_widget_show (self->expando_box);
if (gtk_widget_get_visible (self->entry)) {
gtk_widget_grab_focus (self->entry);
} else {
gtk_widget_grab_focus (self->username_entry);
}
} else {
gtk_widget_show (self->button);
gtk_widget_hide (self->expando_box);
}
g_object_notify (G_OBJECT (self), "expanded");
}
}
gboolean
sync_config_widget_get_expanded (SyncConfigWidget *self)
{
return self->expanded;
}
void
sync_config_widget_set_has_template (SyncConfigWidget *self, gboolean has_template)
{
if (self->has_template != has_template) {
self->has_template = has_template;
update_buttons (self);
sync_config_widget_update_label (self);
}
}
gboolean
sync_config_widget_get_has_template (SyncConfigWidget *self)
{
return self->has_template;
}
void
sync_config_widget_set_configured (SyncConfigWidget *self, gboolean configured)
{
if (self->configured != configured) {
self->configured = configured;
self->device_template_selected = configured;
update_buttons (self);
}
}
gboolean
sync_config_widget_get_configured (SyncConfigWidget *self)
{
return self->configured;
}
gboolean
sync_config_widget_get_current (SyncConfigWidget *widget)
{
return widget->current;
}
const char*
sync_config_widget_get_name (SyncConfigWidget *widget)
{
return widget->config_name;
}
void
sync_config_widget_add_alternative_config (SyncConfigWidget *self,
const char *template_name,
SyncevoConfig *config,
gboolean configured)
{
sync_config_widget_add_config (self, template_name, config);
if (configured) {
sync_config_widget_set_config (self, config);
sync_config_widget_set_configured (self, TRUE);
}
sync_config_widget_update_expander (self);
}