2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
12 * You should have received a copy of the GNU General Public
13 * License along with this program; if not, write to the
14 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
15 * Boston, MA 02110-1301 USA
17 * Authors: Travis Reitter <treitter@gmail.com>
23 #include <glib/gi18n.h>
25 #include <hildon/hildon.h>
26 #include <rtm-glib/rtm-glib.h>
28 #include "milk-task-model.h"
29 #include "milk-auth.h"
30 #include "milk-cache.h"
33 milk_task_model_tree_model_init (GtkTreeModelIface *iface);
35 G_DEFINE_TYPE_EXTENDED (MilkTaskModel,
39 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
40 milk_task_model_tree_model_init));
42 /* less expensive than G_TYPE_INSTANCE_GET_PRIVATE */
43 #define MILK_TASK_MODEL_PRIVATE(o) ((MILK_TASK_MODEL ((o)))->priv)
45 struct _MilkTaskModelPrivate
57 static GtkTreeModelFlags
58 milk_task_model_get_flags (GtkTreeModel *model)
60 return GTK_TREE_MODEL_LIST_ONLY;
64 milk_task_model_get_n_columns (GtkTreeModel *model)
66 return MILK_TASK_MODEL_N_COLUMNS;
70 milk_task_model_get_column_type (GtkTreeModel *model,
74 case MILK_TASK_MODEL_COLUMN_TASK:
78 g_warning (G_STRLOC ": invalid column: %d", column);
79 return G_TYPE_INVALID;
84 milk_task_model_get_iter (GtkTreeModel *model,
88 MilkTaskModelPrivate *priv;
90 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
91 g_return_val_if_fail (iter, FALSE);
92 g_return_val_if_fail (gtk_tree_path_get_depth (path) == 1, FALSE);
94 priv = MILK_TASK_MODEL_PRIVATE (model);
96 return gtk_tree_model_get_iter (
97 GTK_TREE_MODEL (priv->store), iter, path);
101 milk_task_model_get_path (GtkTreeModel *model,
104 MilkTaskModelPrivate *priv;
106 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), NULL);
107 g_return_val_if_fail (iter, NULL);
109 priv = MILK_TASK_MODEL_PRIVATE (model);
111 return gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), iter);
115 milk_task_model_get_value (GtkTreeModel *model,
120 MilkTaskModelPrivate *priv;
122 g_return_if_fail (MILK_IS_TASK_MODEL (model));
123 g_return_if_fail (iter);
124 g_return_if_fail (value);
126 priv = MILK_TASK_MODEL_PRIVATE (model);
128 gtk_tree_model_get_value (
129 GTK_TREE_MODEL (priv->store), iter, column, value);
133 milk_task_model_iter_next (GtkTreeModel *model,
136 MilkTaskModelPrivate *priv;
138 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
139 g_return_val_if_fail (iter, FALSE);
141 priv = MILK_TASK_MODEL_PRIVATE (model);
143 return gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), iter);
147 milk_task_model_iter_nth_child (GtkTreeModel *model,
152 MilkTaskModelPrivate *priv;
154 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
155 g_return_val_if_fail (iter, FALSE);
156 /* we're one-dimensional */
157 g_return_val_if_fail (!parent, FALSE);
158 g_return_val_if_fail (index >= 0, FALSE);
160 priv = MILK_TASK_MODEL_PRIVATE (model);
162 return gtk_tree_model_iter_nth_child (
163 GTK_TREE_MODEL (priv->store), iter, parent, index);
167 milk_task_model_iter_children (GtkTreeModel *model,
171 MilkTaskModelPrivate *priv;
173 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
174 g_return_val_if_fail (iter, FALSE);
175 /* we're one-dimensional */
176 g_return_val_if_fail (!parent, FALSE);
178 priv = MILK_TASK_MODEL_PRIVATE (model);
180 return gtk_tree_model_iter_children (
181 GTK_TREE_MODEL (priv->store), iter, parent);
185 milk_task_model_iter_has_child (GtkTreeModel *model,
188 MilkTaskModelPrivate *priv;
190 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
191 g_return_val_if_fail (iter, FALSE);
193 priv = MILK_TASK_MODEL_PRIVATE (model);
195 return gtk_tree_model_iter_has_child (
196 GTK_TREE_MODEL (priv->store), iter);
200 milk_task_model_iter_n_children (GtkTreeModel *model,
203 MilkTaskModelPrivate *priv;
205 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), -1);
206 g_return_val_if_fail (iter, -1);
208 priv = MILK_TASK_MODEL_PRIVATE (model);
210 /* we're one-dimensional */
214 return gtk_tree_model_iter_n_children (
215 GTK_TREE_MODEL (priv->store), iter);
219 milk_task_model_iter_parent (GtkTreeModel *model,
223 MilkTaskModelPrivate *priv;
225 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
226 g_return_val_if_fail (iter, FALSE);
227 g_return_val_if_fail (child, FALSE);
229 priv = MILK_TASK_MODEL_PRIVATE (model);
231 return gtk_tree_model_iter_parent (
232 GTK_TREE_MODEL (priv->store), iter, child);
235 typedef gchar* (*RtmTaskAttrFunc) (RtmTask*);
238 model_store_find_task_by_attr (MilkTaskModel *model,
240 RtmTaskAttrFunc attr_func,
241 GtkTreeIter *iter_in)
243 MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (model);
246 gboolean found = FALSE;
248 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store),
250 while (valid && !found) {
253 gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
254 MILK_TASK_MODEL_COLUMN_TASK, &task,
257 if (!g_strcmp0 (attr_func (task_in),
263 g_object_unref (task);
265 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store),
273 model_store_find_task (MilkTaskModel *model,
275 GtkTreeIter *iter_in)
277 return model_store_find_task_by_attr (model, task_in, rtm_task_get_id,
282 model_store_find_local_only_task (MilkTaskModel *model,
284 GtkTreeIter *iter_in)
286 return model_store_find_task_by_attr (model, task_in,rtm_task_get_name,
291 row_changed_cb (GtkTreeModel *model,
296 gtk_tree_model_row_changed (GTK_TREE_MODEL (self), path, iter);
300 row_deleted_cb (GtkTreeModel *model,
304 gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), path);
308 row_inserted_cb (GtkTreeModel *model,
313 gtk_tree_model_row_inserted (GTK_TREE_MODEL (self), path, iter);
317 rows_reordered_cb (GtkTreeModel *model,
323 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (self), path, NULL,
328 cache_cleared_cb (MilkCache *cache,
329 MilkTaskModel *model)
331 MilkTaskModelPrivate *priv;
332 priv = MILK_TASK_MODEL_PRIVATE (model);
334 gtk_list_store_clear (priv->store);
338 cache_task_added_cb (MilkCache *cache,
340 MilkTaskModel *model)
342 MilkTaskModelPrivate *priv;
345 gboolean task_in_store;
347 priv = MILK_TASK_MODEL_PRIVATE (model);
349 /* local-only tasks don't have a set task ID */
350 id = rtm_task_get_id (task);
352 /* clear out any entries for the task created before we knew its
354 g_hash_table_remove (priv->tasks, rtm_task_get_name (task));
356 id = rtm_task_get_name (task);
358 g_return_if_fail (id);
360 g_hash_table_insert (priv->tasks, g_strdup (id),
361 g_object_ref (task));
363 task_in_store = model_store_find_task (model, task, &iter);
365 gtk_list_store_append (priv->store, &iter);
366 gtk_list_store_set (priv->store, &iter,
367 MILK_TASK_MODEL_COLUMN_TASK, task, -1);
371 cache_task_changed_cb (MilkCache *cache,
373 MilkTaskModel *model)
375 MilkTaskModelPrivate *priv;
378 gboolean task_in_store;
382 priv = MILK_TASK_MODEL_PRIVATE (model);
384 id = rtm_task_get_id (task);
385 g_hash_table_insert (priv->tasks, g_strdup (id),
386 g_object_ref (task));
388 /* try to find a local-only version of this task first, to upgrade it to
390 task_in_store = model_store_find_local_only_task (model, task, &iter);
391 if (!task_in_store) {
392 /* FIXME: cut this */
393 g_debug ("task (supposedly) was already known remotely");
395 task_in_store = model_store_find_task (model, task, &iter);
397 /* FIXME: cut this */
398 g_debug ("task was *NOT* known remotely");
401 /* rtm-glib doesn't re-use task structs when they're updated, so we have
402 * to replace the changed */
403 gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
404 MILK_TASK_MODEL_COLUMN_TASK, &old_task, -1);
406 gtk_list_store_set (priv->store, &iter,
407 MILK_TASK_MODEL_COLUMN_TASK, task, -1);
409 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
410 gtk_tree_model_row_changed (GTK_TREE_MODEL (priv->store), path, &iter);
411 gtk_tree_path_free (path);
413 g_object_unref (old_task);
417 cache_task_finished_cb (MilkCache *cache,
419 MilkTaskModel *model)
421 MilkTaskModelPrivate *priv;
424 gboolean task_in_store;
426 priv = MILK_TASK_MODEL_PRIVATE (model);
428 id = rtm_task_get_id (task);
429 g_hash_table_insert (priv->tasks, g_strdup (id),
430 g_object_ref (task));
432 task_in_store = model_store_find_task (model, task, &iter);
435 gtk_list_store_remove (priv->store, &iter);
439 set_cache (MilkTaskModel *model,
442 MilkTaskModelPrivate *priv;
445 g_return_if_fail (MILK_IS_TASK_MODEL (model));
446 g_return_if_fail (MILK_IS_CACHE (cache));
448 priv = MILK_TASK_MODEL_PRIVATE (model);
451 g_object_unref (priv->cache);
453 priv->cache = g_object_ref (cache);
455 gtk_list_store_clear (priv->store);
457 g_signal_connect (cache, "cleared", G_CALLBACK (cache_cleared_cb),
459 g_signal_connect (cache, "task-added", G_CALLBACK (cache_task_added_cb),
461 g_signal_connect (cache, "task-changed",
462 G_CALLBACK (cache_task_changed_cb), model);
463 g_signal_connect (cache, "task-finished",
464 G_CALLBACK (cache_task_finished_cb), model);
466 /* do the initial fill from the cache */
467 tasks = milk_cache_get_active_tasks (cache);
468 for (l = tasks; l; l = l->next) {
469 cache_task_added_cb (cache, l->data, model);
475 milk_task_model_get_property (GObject *object,
480 MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object);
485 g_value_set_object (value, priv->cache);
489 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
495 milk_task_model_set_property (GObject *object,
503 set_cache (MILK_TASK_MODEL (object),
504 g_value_get_object (value));
508 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
514 milk_task_model_dispose (GObject *object)
516 MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object);
518 g_signal_handlers_disconnect_by_func (priv->cache, cache_cleared_cb,
520 g_signal_handlers_disconnect_by_func (priv->cache, cache_task_added_cb,
522 g_signal_handlers_disconnect_by_func (priv->cache,
523 cache_task_changed_cb, object);
524 g_signal_handlers_disconnect_by_func (priv->cache,
525 cache_task_finished_cb, object);
528 g_object_unref (priv->cache);
532 g_signal_handlers_disconnect_by_func (priv->store, row_changed_cb,
534 g_signal_handlers_disconnect_by_func (priv->store, row_deleted_cb,
536 g_signal_handlers_disconnect_by_func (priv->store, row_inserted_cb,
538 g_signal_handlers_disconnect_by_func (priv->store, rows_reordered_cb,
542 g_object_unref (priv->store);
547 g_hash_table_destroy (priv->tasks);
551 G_OBJECT_CLASS (milk_task_model_parent_class)->dispose (object);
555 milk_task_model_class_init (MilkTaskModelClass *klass)
557 GObjectClass *object_class = G_OBJECT_CLASS (klass);
559 g_type_class_add_private (klass, sizeof (MilkTaskModelPrivate));
561 object_class->get_property = milk_task_model_get_property;
562 object_class->set_property = milk_task_model_set_property;
563 object_class->dispose = milk_task_model_dispose;
565 g_object_class_install_property
571 "Remember The Milk tasks cache.",
573 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
574 G_PARAM_STATIC_STRINGS));
578 milk_task_model_init (MilkTaskModel *self)
580 MilkTaskModelPrivate *priv;
582 self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (
583 self, MILK_TYPE_TASK_MODEL, MilkTaskModelPrivate);
585 priv->tasks = g_hash_table_new_full (g_str_hash, g_str_equal,
586 g_free, g_object_unref);
588 priv->store = gtk_list_store_new (
589 MILK_TASK_MODEL_N_COLUMNS, RTM_TYPE_TASK);
591 g_signal_connect (priv->store, "row-changed",
592 G_CALLBACK (row_changed_cb), self);
594 g_signal_connect (priv->store, "row-deleted",
595 G_CALLBACK (row_deleted_cb), self);
597 g_signal_connect (priv->store, "row-inserted",
598 G_CALLBACK (row_inserted_cb), self);
600 g_signal_connect (priv->store, "rows-reordered",
601 G_CALLBACK (rows_reordered_cb), self);
605 milk_task_model_tree_model_init (GtkTreeModelIface *iface)
607 iface->get_flags = milk_task_model_get_flags;
608 iface->get_n_columns = milk_task_model_get_n_columns;
609 iface->get_column_type = milk_task_model_get_column_type;
610 iface->get_iter = milk_task_model_get_iter;
611 iface->get_path = milk_task_model_get_path;
612 iface->get_value = milk_task_model_get_value;
613 iface->iter_next = milk_task_model_iter_next;
614 iface->iter_children = milk_task_model_iter_children;
615 iface->iter_has_child = milk_task_model_iter_has_child;
616 iface->iter_n_children = milk_task_model_iter_n_children;
617 iface->iter_nth_child = milk_task_model_iter_nth_child;
618 iface->iter_parent = milk_task_model_iter_parent;
622 milk_task_model_new ()
624 return g_object_new (MILK_TYPE_TASK_MODEL,
625 "cache", milk_cache_get_default (), NULL);