diff options
Diffstat (limited to 'sync/src/sync_collection.c')
-rw-r--r-- | sync/src/sync_collection.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/sync/src/sync_collection.c b/sync/src/sync_collection.c new file mode 100644 index 0000000..88b2d05 --- /dev/null +++ b/sync/src/sync_collection.c @@ -0,0 +1,406 @@ + +#include <glib.h> +#include "sync_group.h" +#include "sync_collection.h" + +G_DEFINE_TYPE (SyncCollection, sync_collection, G_TYPE_OBJECT); + +#define COLLECTION_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), SYNC_TYPE_COLLECTION, SyncCollectionPrivate)) + +typedef struct _SyncCollectionPrivate SyncCollectionPrivate; + +enum { + STARTED, + PROGRESS, + CONFLICT, + FINISHED, + FAILED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + SyncGroup *group; + gdouble progress; + gchar *error; +} SyncCollectionGroup; + +struct _SyncCollectionPrivate +{ + GList *groups; + + gboolean started; + gdouble progress; + gint num_groups; + gint num_finished; +}; + +static void +sync_collection_finalize (GObject *object) +{ + SyncCollection *collection = SYNC_COLLECTION (object); +/* SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);*/ + + /* TODO: Guard against, or cater for this happening during a sync */ + sync_collection_remove_all (collection); + + G_OBJECT_CLASS (sync_collection_parent_class)->finalize (object); +} + +static void +sync_collection_class_init (SyncCollectionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + signals[STARTED] = + g_signal_new ("started", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SyncCollectionClass, started), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[PROGRESS] = + g_signal_new ("progress", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SyncCollectionClass, progress), + NULL, NULL, + g_cclosure_marshal_VOID__DOUBLE, + G_TYPE_NONE, 1, G_TYPE_DOUBLE); + signals[CONFLICT] = + g_signal_new ("conflict", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SyncCollectionClass, conflict), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 0, G_TYPE_OBJECT); + signals[FINISHED] = + g_signal_new ("finished", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SyncCollectionClass, finished), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[FAILED] = + g_signal_new ("failed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SyncCollectionClass, failed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + g_type_class_add_private (klass, sizeof (SyncCollectionPrivate)); + + object_class->finalize = sync_collection_finalize; +} + +static void +sync_collection_init (SyncCollection *self) +{ +} + +SyncCollection* +sync_collection_new (void) +{ + return g_object_new (SYNC_TYPE_COLLECTION, NULL); +} + +static void +sync_collection_namespace_func (gpointer data, gpointer user_data) +{ + SyncCollectionGroup *col_group = data; + const gchar *namespace = user_data; + + sync_group_set_namespace (col_group->group, namespace); +} + +static void +sync_collection_start_func (gpointer data, gpointer user_data) +{ + SyncCollectionGroup *col_group = data; + gboolean *success = user_data; + + if (!sync_group_start (col_group->group)) + *success = FALSE; +} + +static void +sync_collection_abort_func (gpointer data, gpointer user_data) +{ + SyncCollectionGroup *col_group = data; + + sync_group_abort (col_group->group); +} + +static void +sync_collection_save_func (gpointer data, gpointer user_data) +{ + SyncCollectionGroup *col_group = data; + gboolean *success = user_data; + + if (!sync_group_save (col_group->group)) + *success = FALSE; +} + +static void +sync_collection_delete_func (gpointer data, gpointer user_data) +{ + SyncCollectionGroup *col_group = data; + gboolean *success = user_data; + + if (!sync_group_delete (col_group->group)) + *success = FALSE; +} + +static gint +sync_collection_find_func (gconstpointer a, gconstpointer b) +{ + const SyncCollectionGroup *col_group = a; + const SyncGroup *group = b; + + if (col_group->group == group) return 0; + else return -1; +} + +static void +sync_collection_started_cb (SyncGroup *group, SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + + if (!priv->started) { + priv->started = TRUE; + g_signal_emit (collection, signals[STARTED], 0); + } +} + +static void +sync_collection_progress_cb (SyncGroup *group, gdouble progress, + SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + SyncCollectionGroup *col_group = (SyncCollectionGroup *) + ((g_list_find_custom (priv->groups, group, + sync_collection_find_func))->data); + + priv->progress -= col_group->progress; + col_group->progress = progress; + priv->progress += col_group->progress; + + g_signal_emit (collection, signals[PROGRESS], 0, + priv->progress / (gdouble)priv->num_groups); +} + +static void +sync_collection_conflict_cb (SyncGroup *group, SyncCollection *collection) +{ + g_signal_emit (collection, signals[CONFLICT], 0, group); +} + +static void +sync_collection_finished (SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + + priv->num_finished ++; + if (priv->num_finished == priv->num_groups) { + GList *c; + gchar *error = NULL; + for (c = priv->groups; c; c = c->next) { + gchar *new_error; + SyncCollectionGroup *col_group = c->data; + + col_group->progress = 0; + if (!col_group->error) continue; + + if (!error) { + error = g_strdup (col_group->error); + continue; + } + new_error = g_strconcat (error, "\n", + col_group->error, NULL); + g_free (error); + error = new_error; + + g_free (col_group->error); + col_group->error = NULL; + } + priv->num_finished = 0; + priv->progress = 0; + priv->started = FALSE; + if (!error) { + g_signal_emit (collection, signals[FINISHED], 0); + } else { + g_signal_emit (collection, signals[FAILED], 0, error); + g_free (error); + } + } +} + +static void +sync_collection_finished_cb (SyncGroup *group, SyncCollection *collection) +{ + sync_collection_finished (collection); +} + +static void +sync_collection_failed_cb (SyncGroup *group, const gchar *error, + SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + SyncCollectionGroup *col_group = (SyncCollectionGroup *) + ((g_list_find_custom (priv->groups, group, + sync_collection_find_func))->data); + + col_group->error = g_strdup (error); + sync_collection_finished (collection); +} + +static SyncCollectionGroup * +sync_collection_group_new (SyncCollection *collection, SyncGroup *group) +{ + SyncCollectionGroup *col_group = g_new0 (SyncCollectionGroup, 1); + col_group->group = g_object_ref (group); + + g_signal_connect (G_OBJECT (group), "started", + G_CALLBACK (sync_collection_started_cb), collection); + g_signal_connect (G_OBJECT (group), "progress", + G_CALLBACK (sync_collection_progress_cb), collection); + g_signal_connect (G_OBJECT (group), "conflict", + G_CALLBACK (sync_collection_conflict_cb), collection); + g_signal_connect (G_OBJECT (group), "finished", + G_CALLBACK (sync_collection_finished_cb), collection); + g_signal_connect (G_OBJECT (group), "failed", + G_CALLBACK (sync_collection_failed_cb), collection); + + return col_group; +} + +static void +sync_collection_group_free (SyncCollection *collection, + SyncCollectionGroup *col_group) +{ + g_signal_handlers_disconnect_by_func ( + col_group->group, sync_collection_started_cb, collection); + g_signal_handlers_disconnect_by_func ( + col_group->group, sync_collection_progress_cb, collection); + g_signal_handlers_disconnect_by_func ( + col_group->group, sync_collection_conflict_cb, collection); + g_signal_handlers_disconnect_by_func ( + col_group->group, sync_collection_finished_cb, collection); + g_signal_handlers_disconnect_by_func ( + col_group->group, sync_collection_failed_cb, collection); + + g_object_unref (col_group->group); + g_free (col_group->error); + g_free (col_group); +} + +void +sync_collection_add_group (SyncCollection *collection, + SyncGroup *group) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + + priv->groups = g_list_prepend (priv->groups, sync_collection_group_new ( + collection, group)); + priv->num_groups ++; +} + +void +sync_collection_set_namespace (SyncCollection *collection, + const gchar *namespace) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + + g_list_foreach (priv->groups, + sync_collection_namespace_func, (gpointer)namespace); +} + +GList * +sync_collection_get_groups (SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + + return g_list_copy (priv->groups); +} + +gboolean +sync_collection_start (SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + gboolean success = TRUE; + + g_list_foreach (priv->groups, + sync_collection_start_func, &success); + + return success; +} + +void +sync_collection_abort (SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + + g_list_foreach (priv->groups, + sync_collection_abort_func, collection); +} + +void +sync_collection_remove_group (SyncCollection *collection, + SyncGroup *group) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + GList *col_group; + + col_group = g_list_find_custom ( + priv->groups, group, sync_collection_find_func); + if (col_group) { + sync_collection_group_free (collection, (SyncCollectionGroup *) + col_group->data); + priv->groups = g_list_delete_link (priv->groups, col_group); + } +} + +void +sync_collection_remove_all (SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + + while (priv->groups) { + SyncCollectionGroup *col_group = priv->groups->data; + + sync_collection_group_free (collection, col_group); + priv->groups = g_list_delete_link (priv->groups, priv->groups); + } +} + +gboolean +sync_collection_delete (SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + gboolean success = TRUE; + + g_list_foreach (priv->groups, + sync_collection_delete_func, &success); + + return success; +} + +gboolean +sync_collection_save (SyncCollection *collection) +{ + SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection); + gboolean success = TRUE; + + g_list_foreach (priv->groups, + sync_collection_save_func, &success); + + return success; +} + |