#include "milk-task-model.h"
#include "milk-auth.h"
+#include "milk-cache.h"
static void
milk_task_model_tree_model_init (GtkTreeModelIface *iface);
/* 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)
{
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;
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;
}
}
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
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
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:
{
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;
{
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,
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;
}
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);
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));
}
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);
}
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);
}