X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fmilk-task-model.c;fp=src%2Fmilk-task-model.c;h=605e4a58810d526b0d3342f885dfb8dfb5329626;hb=c53fd3e300223472eb6e455ad176d30a715753e4;hp=9e20765ffa9c5d9e3bb77654b5bc43f0cdb18938;hpb=a3cf6da4bd41ce528ddcf11c53691ff1a880adbe;p=milk diff --git a/src/milk-task-model.c b/src/milk-task-model.c index 9e20765..605e4a5 100644 --- a/src/milk-task-model.c +++ b/src/milk-task-model.c @@ -42,16 +42,30 @@ 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; }; enum { PROP_AUTH = 1, }; +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) { @@ -230,46 +244,129 @@ milk_task_model_iter_parent (GtkTreeModel *model, GTK_TREE_MODEL (priv->store), iter, child); } -static void -populate_model (MilkTaskModel *model) +static gboolean +model_store_find_task (MilkTaskModel *model, + RtmTask *task_in, + GtkTreeIter *iter_in) +{ + MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (model); + gboolean valid; + GtkTreeIter iter; + gboolean found = FALSE; + + valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), + &iter); + while (valid && !found) { + MilkTask *task; + char *task_id; + + gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, + MILK_TASK_MODEL_COLUMN_TASK, &task, + -1); + g_object_get (task, "id", &task_id, NULL); + + if (!g_strcmp0 (rtm_task_get_id (task_in), task_id)) { + *iter_in = iter; + found = TRUE; + } + + g_object_unref (task); + + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), + &iter); + } + + return found; +} + +static gboolean +update_model (MilkTaskModel *model) { MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (model); GList *rtm_tasks; GList *l; - GtkTreeIter iter; + GTimeVal current_time; + char *new_sync; + GError *error = NULL; - gtk_list_store_clear (priv->store); + 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); - /* FIXME: poll for new tasks periodically -- there's rtm-glib API to - * optimize just fetching the latest ones */ - rtm_tasks = milk_auth_get_tasks (priv->auth); + 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; MilkTask *task; + const char *id; + gboolean task_in_store; rtm_task = RTM_TASK (l->data); - /* XXX: if possible, avoid fetching these in the first place */ - /* Skip tasks deleted or completed. */ - if (rtm_task_get_completed_date (rtm_task) || - rtm_task_get_deleted_date (rtm_task)) { - continue; + 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) { + GtkTreePath *path; + + gtk_tree_model_get ( + GTK_TREE_MODEL (priv->store), &iter, + MILK_TASK_MODEL_COLUMN_TASK, &task, + -1); + + milk_task_set_title (task, + rtm_task_get_name (rtm_task)); + + 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 (task); + + /* Task is new */ + } else { + /* FIXME: remove the MilkTask class; just use RtmTask + * directly */ + task = milk_task_new (id, rtm_task_get_name (rtm_task), + /* FIXME: switch priority from int to + * string */ + g_ascii_strtod (rtm_task_get_priority + (rtm_task), NULL)); + + gtk_list_store_append (priv->store, &iter); + gtk_list_store_set ( + priv->store, &iter, + MILK_TASK_MODEL_COLUMN_TASK, task, + -1); } - - task = milk_task_new (rtm_task_get_id (rtm_task), - rtm_task_get_name (rtm_task), - /* FIXME: switch priority from int to string */ - g_ascii_strtod (rtm_task_get_priority - (rtm_task), NULL)); - - gtk_list_store_append (priv->store, &iter); - gtk_list_store_set ( - priv->store, &iter, - MILK_TASK_MODEL_COLUMN_TASK, task, - -1); } + + return TRUE; } static void @@ -278,7 +375,7 @@ auth_notify_cb (MilkAuth *auth, MilkTaskModel *model) { if (milk_auth_get_state (auth) == MILK_AUTH_STATE_CONNECTED) { - populate_model (model); + update_model (model); } } @@ -337,12 +434,17 @@ milk_task_model_set_auth (MilkTaskModel *model, } priv->auth = g_object_ref (auth); - if (milk_auth_get_state (priv->auth) == MILK_AUTH_STATE_CONNECTED) { - populate_model (model); - } else { - g_signal_connect (priv->auth, "notify::state", - G_CALLBACK (auth_notify_cb), model); + if (priv->update_id) { + g_source_remove (priv->update_id); } + priv->update_id = g_timeout_add (MODEL_UPDATE_PERIOD, + (GSourceFunc) update_model, model); + + 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); } static void @@ -408,10 +510,30 @@ 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; + } + G_OBJECT_CLASS (milk_task_model_parent_class)->dispose (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); @@ -421,6 +543,7 @@ 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, @@ -442,6 +565,11 @@ 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); + priv->store = gtk_list_store_new ( MILK_TASK_MODEL_N_COLUMNS, MILK_TYPE_TASK);