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-task.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 /* FIXME: make this configurable at runtime, pref. as a gconf value */
46 /* time between syncing with the server, in ms */
47 #define MODEL_UPDATE_PERIOD 60000
49 struct _MilkTaskModelPrivate
63 task_is_finished (RtmTask *task)
65 return (rtm_task_get_completed_date (task) ||
66 rtm_task_get_deleted_date (task));
69 static GtkTreeModelFlags
70 milk_task_model_get_flags (GtkTreeModel *model)
72 return GTK_TREE_MODEL_LIST_ONLY;
76 milk_task_model_get_n_columns (GtkTreeModel *model)
78 return MILK_TASK_MODEL_N_COLUMNS;
82 milk_task_model_get_column_type (GtkTreeModel *model,
86 case MILK_TASK_MODEL_COLUMN_TASK:
87 return MILK_TYPE_TASK;
90 g_warning (G_STRLOC ": invalid column: %d", column);
91 return G_TYPE_INVALID;
96 milk_task_model_get_iter (GtkTreeModel *model,
100 MilkTaskModelPrivate *priv;
102 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
103 g_return_val_if_fail (iter, FALSE);
104 g_return_val_if_fail (gtk_tree_path_get_depth (path) == 1, FALSE);
106 priv = MILK_TASK_MODEL_PRIVATE (model);
108 return gtk_tree_model_get_iter (
109 GTK_TREE_MODEL (priv->store), iter, path);
113 milk_task_model_get_path (GtkTreeModel *model,
116 MilkTaskModelPrivate *priv;
118 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), NULL);
119 g_return_val_if_fail (iter, NULL);
121 priv = MILK_TASK_MODEL_PRIVATE (model);
123 return gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), iter);
127 milk_task_model_get_value (GtkTreeModel *model,
132 MilkTaskModelPrivate *priv;
134 g_return_if_fail (MILK_IS_TASK_MODEL (model));
135 g_return_if_fail (iter);
136 g_return_if_fail (value);
138 priv = MILK_TASK_MODEL_PRIVATE (model);
140 gtk_tree_model_get_value (
141 GTK_TREE_MODEL (priv->store), iter, column, value);
145 milk_task_model_iter_next (GtkTreeModel *model,
148 MilkTaskModelPrivate *priv;
150 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
151 g_return_val_if_fail (iter, FALSE);
153 priv = MILK_TASK_MODEL_PRIVATE (model);
155 return gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), iter);
159 milk_task_model_iter_nth_child (GtkTreeModel *model,
164 MilkTaskModelPrivate *priv;
166 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
167 g_return_val_if_fail (iter, FALSE);
168 /* we're one-dimensional */
169 g_return_val_if_fail (!parent, FALSE);
170 g_return_val_if_fail (index >= 0, FALSE);
172 priv = MILK_TASK_MODEL_PRIVATE (model);
174 return gtk_tree_model_iter_nth_child (
175 GTK_TREE_MODEL (priv->store), iter, parent, index);
179 milk_task_model_iter_children (GtkTreeModel *model,
183 MilkTaskModelPrivate *priv;
185 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
186 g_return_val_if_fail (iter, FALSE);
187 /* we're one-dimensional */
188 g_return_val_if_fail (!parent, FALSE);
190 priv = MILK_TASK_MODEL_PRIVATE (model);
192 return gtk_tree_model_iter_children (
193 GTK_TREE_MODEL (priv->store), iter, parent);
197 milk_task_model_iter_has_child (GtkTreeModel *model,
200 MilkTaskModelPrivate *priv;
202 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
203 g_return_val_if_fail (iter, FALSE);
205 priv = MILK_TASK_MODEL_PRIVATE (model);
207 return gtk_tree_model_iter_has_child (
208 GTK_TREE_MODEL (priv->store), iter);
212 milk_task_model_iter_n_children (GtkTreeModel *model,
215 MilkTaskModelPrivate *priv;
217 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), -1);
218 g_return_val_if_fail (iter, -1);
220 priv = MILK_TASK_MODEL_PRIVATE (model);
222 /* we're one-dimensional */
226 return gtk_tree_model_iter_n_children (
227 GTK_TREE_MODEL (priv->store), iter);
231 milk_task_model_iter_parent (GtkTreeModel *model,
235 MilkTaskModelPrivate *priv;
237 g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
238 g_return_val_if_fail (iter, FALSE);
239 g_return_val_if_fail (child, FALSE);
241 priv = MILK_TASK_MODEL_PRIVATE (model);
243 return gtk_tree_model_iter_parent (
244 GTK_TREE_MODEL (priv->store), iter, child);
248 model_store_find_task (MilkTaskModel *model,
250 GtkTreeIter *iter_in)
252 MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (model);
255 gboolean found = FALSE;
257 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store),
259 while (valid && !found) {
263 gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
264 MILK_TASK_MODEL_COLUMN_TASK, &task,
266 g_object_get (task, "id", &task_id, NULL);
268 if (!g_strcmp0 (rtm_task_get_id (task_in), task_id)) {
273 g_object_unref (task);
275 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store),
283 update_model (MilkTaskModel *model)
285 MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (model);
288 GTimeVal current_time;
290 GError *error = NULL;
292 if (milk_auth_get_state (priv->auth) != MILK_AUTH_STATE_CONNECTED) {
296 g_get_current_time (¤t_time);
297 new_sync = g_time_val_to_iso8601 (¤t_time);
298 rtm_tasks = milk_auth_get_tasks (priv->auth, priv->last_sync, &error);
301 g_error (G_STRLOC ": failed to retrieve latest tasks: %s",
303 g_clear_error (&error);
305 g_free (priv->last_sync);
306 priv->last_sync = new_sync;
310 for (l = rtm_tasks; l; l = g_list_delete_link (l, l)) {
315 gboolean task_in_store;
317 rtm_task = RTM_TASK (l->data);
319 id = rtm_task_get_id (rtm_task);
320 g_hash_table_insert (priv->tasks, g_strdup (id),
321 g_object_ref (rtm_task));
323 task_in_store = model_store_find_task (model, rtm_task, &iter);
325 /* Task is deleted or completed */
326 if (task_is_finished (rtm_task)) {
328 gtk_list_store_remove (priv->store, &iter);
330 /* Task has been changed */
331 } else if (task_in_store) {
335 GTK_TREE_MODEL (priv->store), &iter,
336 MILK_TASK_MODEL_COLUMN_TASK, &task,
339 milk_task_set_title (task,
340 rtm_task_get_name (rtm_task));
342 path = gtk_tree_model_get_path (
343 GTK_TREE_MODEL (priv->store), &iter);
344 gtk_tree_model_row_changed (
345 GTK_TREE_MODEL (priv->store),
347 gtk_tree_path_free (path);
349 g_object_unref (task);
353 /* FIXME: remove the MilkTask class; just use RtmTask
355 task = milk_task_new (id, rtm_task_get_name (rtm_task),
356 /* FIXME: switch priority from int to
358 g_ascii_strtod (rtm_task_get_priority
361 gtk_list_store_append (priv->store, &iter);
364 MILK_TASK_MODEL_COLUMN_TASK, task,
373 auth_notify_cb (MilkAuth *auth,
375 MilkTaskModel *model)
377 if (milk_auth_get_state (auth) == MILK_AUTH_STATE_CONNECTED) {
378 update_model (model);
383 row_changed_cb (GtkTreeModel *model,
388 gtk_tree_model_row_changed (GTK_TREE_MODEL (self), path, iter);
392 row_deleted_cb (GtkTreeModel *model,
396 gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), path);
400 row_inserted_cb (GtkTreeModel *model,
405 gtk_tree_model_row_inserted (GTK_TREE_MODEL (self), path, iter);
409 rows_reordered_cb (GtkTreeModel *model,
415 gtk_tree_model_rows_reordered (GTK_TREE_MODEL (self), path, NULL,
420 milk_task_model_set_auth (MilkTaskModel *model,
423 MilkTaskModelPrivate *priv;
425 g_return_if_fail (model);
426 g_return_if_fail (MILK_IS_TASK_MODEL (model));
427 g_return_if_fail (auth);
428 g_return_if_fail (MILK_IS_AUTH (auth));
430 priv = MILK_TASK_MODEL_PRIVATE (model);
433 g_object_unref (priv->auth);
435 priv->auth = g_object_ref (auth);
437 if (priv->update_id) {
438 g_source_remove (priv->update_id);
440 priv->update_id = g_timeout_add (MODEL_UPDATE_PERIOD,
441 (GSourceFunc) update_model, model);
443 gtk_list_store_clear (priv->store);
445 g_signal_connect (priv->auth, "notify::state",
446 G_CALLBACK (auth_notify_cb), model);
447 auth_notify_cb (priv->auth, NULL, model);
451 milk_task_model_get_property (GObject *object,
456 MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object);
461 g_value_set_object (value, priv->auth);
465 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
471 milk_task_model_set_property (GObject *object,
479 milk_task_model_set_auth (MILK_TASK_MODEL (object),
480 g_value_get_object (value));
484 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
490 milk_task_model_dispose (GObject *object)
492 MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object);
495 g_object_unref (priv->auth);
499 g_signal_handlers_disconnect_by_func (priv->store, row_changed_cb,
501 g_signal_handlers_disconnect_by_func (priv->store, row_deleted_cb,
503 g_signal_handlers_disconnect_by_func (priv->store, row_inserted_cb,
505 g_signal_handlers_disconnect_by_func (priv->store, rows_reordered_cb,
509 g_object_unref (priv->store);
513 if (priv->update_id) {
514 g_source_remove (priv->update_id);
519 g_hash_table_destroy (priv->tasks);
523 G_OBJECT_CLASS (milk_task_model_parent_class)->dispose (object);
527 milk_task_model_finalize (GObject *object)
529 MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object);
531 g_free (priv->last_sync);
533 G_OBJECT_CLASS (milk_task_model_parent_class)->finalize (object);
537 milk_task_model_class_init (MilkTaskModelClass *klass)
539 GObjectClass *object_class = G_OBJECT_CLASS (klass);
541 g_type_class_add_private (klass, sizeof (MilkTaskModelPrivate));
543 object_class->get_property = milk_task_model_get_property;
544 object_class->set_property = milk_task_model_set_property;
545 object_class->dispose = milk_task_model_dispose;
546 object_class->finalize = milk_task_model_finalize;
548 g_object_class_install_property
553 "Authentication proxy",
554 "Remember The Milk authentication proxy.",
556 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
557 G_PARAM_STATIC_STRINGS));
561 milk_task_model_init (MilkTaskModel *self)
563 MilkTaskModelPrivate *priv;
565 self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (
566 self, MILK_TYPE_TASK_MODEL, MilkTaskModelPrivate);
568 priv->last_sync = NULL;
570 priv->tasks = g_hash_table_new_full (g_str_hash, g_str_equal,
571 g_free, g_object_unref);
573 priv->store = gtk_list_store_new (
574 MILK_TASK_MODEL_N_COLUMNS, MILK_TYPE_TASK);
576 g_signal_connect (priv->store, "row-changed",
577 G_CALLBACK (row_changed_cb), self);
579 g_signal_connect (priv->store, "row-deleted",
580 G_CALLBACK (row_deleted_cb), self);
582 g_signal_connect (priv->store, "row-inserted",
583 G_CALLBACK (row_inserted_cb), self);
585 g_signal_connect (priv->store, "rows-reordered",
586 G_CALLBACK (rows_reordered_cb), self);
590 milk_task_model_tree_model_init (GtkTreeModelIface *iface)
592 iface->get_flags = milk_task_model_get_flags;
593 iface->get_n_columns = milk_task_model_get_n_columns;
594 iface->get_column_type = milk_task_model_get_column_type;
595 iface->get_iter = milk_task_model_get_iter;
596 iface->get_path = milk_task_model_get_path;
597 iface->get_value = milk_task_model_get_value;
598 iface->iter_next = milk_task_model_iter_next;
599 iface->iter_children = milk_task_model_iter_children;
600 iface->iter_has_child = milk_task_model_iter_has_child;
601 iface->iter_n_children = milk_task_model_iter_n_children;
602 iface->iter_nth_child = milk_task_model_iter_nth_child;
603 iface->iter_parent = milk_task_model_iter_parent;
607 milk_task_model_new (MilkAuth *auth)
609 return g_object_new (MILK_TYPE_TASK_MODEL, "auth", auth, NULL);