X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fmilk-task-model.c;fp=src%2Fmilk-task-model.c;h=cb2497448f2f9d53014a732036461a092fd50ccb;hb=52f46483b13ef3008c5a7089fa435d84541d09de;hp=a1d6594bbf132a6380009a02eede9c18eb6f2ad9;hpb=8b470693bda2399332d26b155b4a3d746145b680;p=milk diff --git a/src/milk-task-model.c b/src/milk-task-model.c index a1d6594..cb24974 100644 --- a/src/milk-task-model.c +++ b/src/milk-task-model.c @@ -27,6 +27,7 @@ #include "milk-task-model.h" #include "milk-auth.h" +#include "milk-cache.h" static void milk_task_model_tree_model_init (GtkTreeModelIface *iface); @@ -41,30 +42,18 @@ G_DEFINE_TYPE_EXTENDED (MilkTaskModel, /* less expensive than G_TYPE_INSTANCE_GET_PRIVATE */ #define MILK_TASK_MODEL_PRIVATE(o) ((MILK_TASK_MODEL ((o)))->priv) -/* FIXME: make this configurable at runtime, pref. as a gconf value */ -/* time between syncing with the server, in ms */ -#define MODEL_UPDATE_PERIOD 60000 - struct _MilkTaskModelPrivate { GHashTable *tasks; GtkListStore *store; - MilkAuth *auth; - guint update_id; - char *last_sync; + MilkCache *cache; }; enum { - PROP_AUTH = 1, + PROP_0, + PROP_CACHE, }; -static gboolean -task_is_finished (RtmTask *task) -{ - return (rtm_task_get_completed_date (task) || - rtm_task_get_deleted_date (task)); -} - static GtkTreeModelFlags milk_task_model_get_flags (GtkTreeModel *model) { @@ -243,10 +232,13 @@ milk_task_model_iter_parent (GtkTreeModel *model, GTK_TREE_MODEL (priv->store), iter, child); } +typedef gchar* (*RtmTaskAttrFunc) (RtmTask*); + static gboolean -model_store_find_task (MilkTaskModel *model, - RtmTask *task_in, - GtkTreeIter *iter_in) +model_store_find_task_by_attr (MilkTaskModel *model, + RtmTask *task_in, + RtmTaskAttrFunc attr_func, + GtkTreeIter *iter_in) { MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (model); gboolean valid; @@ -262,8 +254,8 @@ model_store_find_task (MilkTaskModel *model, MILK_TASK_MODEL_COLUMN_TASK, &task, -1); - if (!g_strcmp0 (rtm_task_get_id (task_in), - rtm_task_get_id (task))) { + if (!g_strcmp0 (attr_func (task_in), + attr_func (task))) { *iter_in = iter; found = TRUE; } @@ -278,99 +270,21 @@ model_store_find_task (MilkTaskModel *model, } static gboolean -update_model (MilkTaskModel *model) +model_store_find_task (MilkTaskModel *model, + RtmTask *task_in, + GtkTreeIter *iter_in) { - MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (model); - GList *rtm_tasks; - GList *l; - GTimeVal current_time; - char *new_sync; - GError *error = NULL; - - if (milk_auth_get_state (priv->auth) != MILK_AUTH_STATE_CONNECTED) { - return TRUE; - } - - g_get_current_time (¤t_time); - new_sync = g_time_val_to_iso8601 (¤t_time); - rtm_tasks = milk_auth_get_tasks (priv->auth, priv->last_sync, &error); - - if (error) { - g_error (G_STRLOC ": failed to retrieve latest tasks: %s", - error->message); - g_clear_error (&error); - } else { - g_free (priv->last_sync); - priv->last_sync = new_sync; - } - - /* Populate model */ - for (l = rtm_tasks; l; l = g_list_delete_link (l, l)) { - GtkTreeIter iter; - RtmTask *rtm_task; - const char *id; - gboolean task_in_store; - - rtm_task = RTM_TASK (l->data); - - id = rtm_task_get_id (rtm_task); - g_hash_table_insert (priv->tasks, g_strdup (id), - g_object_ref (rtm_task)); - - task_in_store = model_store_find_task (model, rtm_task, &iter); - - /* Task is deleted or completed */ - if (task_is_finished (rtm_task)) { - if (task_in_store) { - gtk_list_store_remove (priv->store, &iter); - } - /* Task has been changed */ - } else if (task_in_store) { - RtmTask *old_task; - GtkTreePath *path; - - /* rtm-glib doesn't re-use task structs when they're - * updated, so we have to replace the changed */ - gtk_tree_model_get ( - GTK_TREE_MODEL (priv->store), &iter, - MILK_TASK_MODEL_COLUMN_TASK, &old_task, - -1); - - gtk_list_store_set ( - priv->store, &iter, - MILK_TASK_MODEL_COLUMN_TASK, rtm_task, - -1); - - path = gtk_tree_model_get_path ( - GTK_TREE_MODEL (priv->store), &iter); - gtk_tree_model_row_changed ( - GTK_TREE_MODEL (priv->store), - path, &iter); - gtk_tree_path_free (path); - - g_object_unref (old_task); - - /* Task is new */ - } else { - gtk_list_store_append (priv->store, &iter); - gtk_list_store_set ( - priv->store, &iter, - MILK_TASK_MODEL_COLUMN_TASK, rtm_task, - -1); - } - } - - return TRUE; + return model_store_find_task_by_attr (model, task_in, rtm_task_get_id, + iter_in); } -static void -auth_notify_cb (MilkAuth *auth, - GParamSpec *spec, - MilkTaskModel *model) +static gboolean +model_store_find_local_only_task (MilkTaskModel *model, + RtmTask *task_in, + GtkTreeIter *iter_in) { - if (milk_auth_get_state (auth) == MILK_AUTH_STATE_CONNECTED) { - update_model (model); - } + return model_store_find_task_by_attr (model, task_in,rtm_task_get_name, + iter_in); } static void @@ -410,35 +324,151 @@ rows_reordered_cb (GtkTreeModel *model, new_order); } -void -milk_task_model_set_auth (MilkTaskModel *model, - MilkAuth *auth) +static void +cache_cleared_cb (MilkCache *cache, + MilkTaskModel *model) { MilkTaskModelPrivate *priv; + priv = MILK_TASK_MODEL_PRIVATE (model); - g_return_if_fail (model); - g_return_if_fail (MILK_IS_TASK_MODEL (model)); - g_return_if_fail (auth); - g_return_if_fail (MILK_IS_AUTH (auth)); + gtk_list_store_clear (priv->store); +} + +static void +cache_task_added_cb (MilkCache *cache, + RtmTask *task, + MilkTaskModel *model) +{ + MilkTaskModelPrivate *priv; + GtkTreeIter iter; + const char *id; + gboolean task_in_store; + + priv = MILK_TASK_MODEL_PRIVATE (model); + + /* local-only tasks don't have a set task ID */ + id = rtm_task_get_id (task); + if (id) { + /* clear out any entries for the task created before we knew its + * server-side ID */ + g_hash_table_remove (priv->tasks, rtm_task_get_name (task)); + } else { + id = rtm_task_get_name (task); + } + g_return_if_fail (id); + + g_hash_table_insert (priv->tasks, g_strdup (id), + g_object_ref (task)); + + task_in_store = model_store_find_task (model, task, &iter); + + gtk_list_store_append (priv->store, &iter); + gtk_list_store_set (priv->store, &iter, + MILK_TASK_MODEL_COLUMN_TASK, task, -1); +} + +static void +cache_task_changed_cb (MilkCache *cache, + RtmTask *task, + MilkTaskModel *model) +{ + MilkTaskModelPrivate *priv; + GtkTreeIter iter; + const char *id; + gboolean task_in_store; + RtmTask *old_task; + GtkTreePath *path; priv = MILK_TASK_MODEL_PRIVATE (model); - if (priv->auth) { - g_object_unref (priv->auth); + id = rtm_task_get_id (task); + g_hash_table_insert (priv->tasks, g_strdup (id), + g_object_ref (task)); + + /* try to find a local-only version of this task first, to upgrade it to + * remote status */ + task_in_store = model_store_find_local_only_task (model, task, &iter); + if (!task_in_store) { + /* FIXME: cut this */ + g_debug ("task (supposedly) was already known remotely"); + + task_in_store = model_store_find_task (model, task, &iter); + } else { + /* FIXME: cut this */ + g_debug ("task was *NOT* known remotely"); } - priv->auth = g_object_ref (auth); - if (priv->update_id) { - g_source_remove (priv->update_id); + /* rtm-glib doesn't re-use task structs when they're updated, so we have + * to replace the changed */ + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, + MILK_TASK_MODEL_COLUMN_TASK, &old_task, -1); + + gtk_list_store_set (priv->store, &iter, + MILK_TASK_MODEL_COLUMN_TASK, task, -1); + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter); + gtk_tree_model_row_changed (GTK_TREE_MODEL (priv->store), path, &iter); + gtk_tree_path_free (path); + + g_object_unref (old_task); +} + +static void +cache_task_finished_cb (MilkCache *cache, + RtmTask *task, + MilkTaskModel *model) +{ + MilkTaskModelPrivate *priv; + GtkTreeIter iter; + const char *id; + gboolean task_in_store; + + priv = MILK_TASK_MODEL_PRIVATE (model); + + id = rtm_task_get_id (task); + g_hash_table_insert (priv->tasks, g_strdup (id), + g_object_ref (task)); + + task_in_store = model_store_find_task (model, task, &iter); + + if (task_in_store) + gtk_list_store_remove (priv->store, &iter); +} + +static void +set_cache (MilkTaskModel *model, + MilkCache *cache) +{ + MilkTaskModelPrivate *priv; + GList *tasks, *l; + + g_return_if_fail (MILK_IS_TASK_MODEL (model)); + g_return_if_fail (MILK_IS_CACHE (cache)); + + priv = MILK_TASK_MODEL_PRIVATE (model); + + if (priv->cache) { + g_object_unref (priv->cache); } - priv->update_id = g_timeout_add (MODEL_UPDATE_PERIOD, - (GSourceFunc) update_model, model); + priv->cache = g_object_ref (cache); gtk_list_store_clear (priv->store); - g_signal_connect (priv->auth, "notify::state", - G_CALLBACK (auth_notify_cb), model); - auth_notify_cb (priv->auth, NULL, model); + g_signal_connect (cache, "cleared", G_CALLBACK (cache_cleared_cb), + model); + g_signal_connect (cache, "task-added", G_CALLBACK (cache_task_added_cb), + model); + g_signal_connect (cache, "task-changed", + G_CALLBACK (cache_task_changed_cb), model); + g_signal_connect (cache, "task-finished", + G_CALLBACK (cache_task_finished_cb), model); + + /* do the initial fill from the cache */ + tasks = milk_cache_get_active_tasks (cache); + for (l = tasks; l; l = l->next) { + cache_task_added_cb (cache, l->data, model); + } + g_list_free (tasks); } static void @@ -451,8 +481,8 @@ milk_task_model_get_property (GObject *object, switch (property_id) { - case PROP_AUTH: - g_value_set_object (value, priv->auth); + case PROP_CACHE: + g_value_set_object (value, priv->cache); break; default: @@ -469,8 +499,8 @@ milk_task_model_set_property (GObject *object, { switch (property_id) { - case PROP_AUTH: - milk_task_model_set_auth (MILK_TASK_MODEL (object), + case PROP_CACHE: + set_cache (MILK_TASK_MODEL (object), g_value_get_object (value)); break; @@ -485,9 +515,18 @@ milk_task_model_dispose (GObject *object) { MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object); - if (priv->auth) { - g_object_unref (priv->auth); - priv->auth = NULL; + g_signal_handlers_disconnect_by_func (priv->cache, cache_cleared_cb, + object); + g_signal_handlers_disconnect_by_func (priv->cache, cache_task_added_cb, + object); + g_signal_handlers_disconnect_by_func (priv->cache, + cache_task_changed_cb, object); + g_signal_handlers_disconnect_by_func (priv->cache, + cache_task_finished_cb, object); + + if (priv->cache) { + g_object_unref (priv->cache); + priv->cache = NULL; } g_signal_handlers_disconnect_by_func (priv->store, row_changed_cb, @@ -504,11 +543,6 @@ milk_task_model_dispose (GObject *object) priv->store = NULL; } - if (priv->update_id) { - g_source_remove (priv->update_id); - priv->update_id = 0; - } - if (priv->tasks) { g_hash_table_destroy (priv->tasks); priv->tasks = NULL; @@ -518,16 +552,6 @@ milk_task_model_dispose (GObject *object) } static void -milk_task_model_finalize (GObject *object) -{ - MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object); - - g_free (priv->last_sync); - - G_OBJECT_CLASS (milk_task_model_parent_class)->finalize (object); -} - -static void milk_task_model_class_init (MilkTaskModelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); @@ -537,16 +561,15 @@ milk_task_model_class_init (MilkTaskModelClass *klass) object_class->get_property = milk_task_model_get_property; object_class->set_property = milk_task_model_set_property; object_class->dispose = milk_task_model_dispose; - object_class->finalize = milk_task_model_finalize; g_object_class_install_property (object_class, - PROP_AUTH, + PROP_CACHE, g_param_spec_object - ("auth", - "Authentication proxy", - "Remember The Milk authentication proxy.", - MILK_TYPE_AUTH, + ("cache", + "Cache of tasks", + "Remember The Milk tasks cache.", + MILK_TYPE_CACHE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } @@ -559,8 +582,6 @@ milk_task_model_init (MilkTaskModel *self) self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE ( self, MILK_TYPE_TASK_MODEL, MilkTaskModelPrivate); - priv->last_sync = NULL; - priv->tasks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); @@ -598,7 +619,8 @@ milk_task_model_tree_model_init (GtkTreeModelIface *iface) } MilkTaskModel* -milk_task_model_new (MilkAuth *auth) +milk_task_model_new () { - return g_object_new (MILK_TYPE_TASK_MODEL, "auth", auth, NULL); + return g_object_new (MILK_TYPE_TASK_MODEL, + "cache", milk_cache_get_default (), NULL); }