Fix two trivial build warnings
[milk] / src / milk-task-model.c
1 /*
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.
6  *
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.
11  *
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
16  *
17  * Authors: Travis Reitter <treitter@gmail.com>
18  */
19
20 #include <config.h>
21
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <gtk/gtk.h>
25 #include <hildon/hildon.h>
26 #include <rtm-glib/rtm-glib.h>
27
28 #include "milk-task-model.h"
29 #include "milk-auth.h"
30 #include "milk-cache.h"
31
32 static void
33 milk_task_model_tree_model_init (GtkTreeModelIface *iface);
34 static void
35 milk_task_model_tree_sortable_init (GtkTreeSortableIface *iface);
36
37 G_DEFINE_TYPE_WITH_CODE (MilkTaskModel,
38                          milk_task_model,
39                          G_TYPE_OBJECT,
40                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
41                                  milk_task_model_tree_model_init)
42                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
43                                  milk_task_model_tree_sortable_init));
44
45 /* less expensive than G_TYPE_INSTANCE_GET_PRIVATE */
46 #define MILK_TASK_MODEL_PRIVATE(o) ((MILK_TASK_MODEL ((o)))->priv)
47
48 struct _MilkTaskModelPrivate
49 {
50         GHashTable *tasks;
51         GtkListStore *store;
52         MilkCache *cache;
53 };
54
55 enum {
56         PROP_0,
57         PROP_CACHE,
58 };
59
60 static GtkTreeModelFlags
61 milk_task_model_get_flags (GtkTreeModel *model)
62 {
63         return GTK_TREE_MODEL_LIST_ONLY;
64 }
65
66 static gint
67 milk_task_model_get_n_columns (GtkTreeModel *model)
68 {
69         return MILK_TASK_MODEL_N_COLUMNS;
70 }
71
72 static GType
73 milk_task_model_get_column_type (GtkTreeModel *model,
74                                  gint          column)
75 {
76         switch (column) {
77                 case MILK_TASK_MODEL_COLUMN_TASK:
78                         return RTM_TYPE_TASK;
79
80                 default:
81                         g_warning (G_STRLOC ": invalid column: %d", column);
82                         return G_TYPE_INVALID;
83         }
84 }
85
86 static gboolean
87 milk_task_model_get_iter (GtkTreeModel *model,
88                           GtkTreeIter  *iter,
89                           GtkTreePath  *path)
90 {
91         MilkTaskModelPrivate *priv;
92
93         g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
94         g_return_val_if_fail (iter, FALSE);
95         g_return_val_if_fail (gtk_tree_path_get_depth (path) == 1, FALSE);
96
97         priv = MILK_TASK_MODEL_PRIVATE (model);
98
99         return gtk_tree_model_get_iter (
100                         GTK_TREE_MODEL (priv->store), iter, path);
101 }
102
103 static GtkTreePath*
104 milk_task_model_get_path (GtkTreeModel *model,
105                           GtkTreeIter  *iter)
106 {
107         MilkTaskModelPrivate *priv;
108
109         g_return_val_if_fail (MILK_IS_TASK_MODEL (model), NULL);
110         g_return_val_if_fail (iter, NULL);
111
112         priv = MILK_TASK_MODEL_PRIVATE (model);
113
114         return gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), iter);
115 }
116
117 static void
118 milk_task_model_get_value (GtkTreeModel *model,
119                            GtkTreeIter  *iter,
120                            gint          column,
121                            GValue       *value)
122 {
123         MilkTaskModelPrivate *priv;
124
125         g_return_if_fail (MILK_IS_TASK_MODEL (model));
126         g_return_if_fail (iter);
127         g_return_if_fail (value);
128
129         priv = MILK_TASK_MODEL_PRIVATE (model);
130
131         gtk_tree_model_get_value (
132                         GTK_TREE_MODEL (priv->store), iter, column, value);
133 }
134
135 static gboolean
136 milk_task_model_iter_next (GtkTreeModel *model,
137                            GtkTreeIter  *iter)
138 {
139         MilkTaskModelPrivate *priv;
140
141         g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
142         g_return_val_if_fail (iter, FALSE);
143
144         priv = MILK_TASK_MODEL_PRIVATE (model);
145
146         return gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), iter);
147 }
148
149 static gboolean
150 milk_task_model_iter_nth_child (GtkTreeModel *model,
151                                 GtkTreeIter  *iter,
152                                 GtkTreeIter  *parent,
153                                 gint          index)
154 {
155         MilkTaskModelPrivate *priv;
156
157         g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
158         g_return_val_if_fail (iter, FALSE);
159         /* we're one-dimensional */
160         g_return_val_if_fail (!parent, FALSE);
161         g_return_val_if_fail (index >= 0, FALSE);
162
163         priv = MILK_TASK_MODEL_PRIVATE (model);
164
165         return gtk_tree_model_iter_nth_child (
166                         GTK_TREE_MODEL (priv->store), iter, parent, index);
167 }
168
169 static gboolean
170 milk_task_model_iter_children (GtkTreeModel *model,
171                                GtkTreeIter  *iter,
172                                GtkTreeIter  *parent)
173 {
174         MilkTaskModelPrivate *priv;
175
176         g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
177         g_return_val_if_fail (iter, FALSE);
178         /* we're one-dimensional */
179         g_return_val_if_fail (!parent, FALSE);
180
181         priv = MILK_TASK_MODEL_PRIVATE (model);
182
183         return gtk_tree_model_iter_children (
184                         GTK_TREE_MODEL (priv->store), iter, parent);
185 }
186
187 static gboolean
188 milk_task_model_iter_has_child (GtkTreeModel *model,
189                                 GtkTreeIter  *iter)
190 {
191         MilkTaskModelPrivate *priv;
192
193         g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
194         g_return_val_if_fail (iter, FALSE);
195
196         priv = MILK_TASK_MODEL_PRIVATE (model);
197
198         return gtk_tree_model_iter_has_child (
199                         GTK_TREE_MODEL (priv->store), iter);
200 }
201
202 static gint
203 milk_task_model_iter_n_children (GtkTreeModel *model,
204                                  GtkTreeIter  *iter)
205 {
206         MilkTaskModelPrivate *priv;
207
208         g_return_val_if_fail (MILK_IS_TASK_MODEL (model), -1);
209         g_return_val_if_fail (iter, -1);
210
211         priv = MILK_TASK_MODEL_PRIVATE (model);
212
213         /* we're one-dimensional */
214         if (iter)
215                 return 0;
216
217         return gtk_tree_model_iter_n_children (
218                         GTK_TREE_MODEL (priv->store), iter);
219 }
220
221 static gboolean
222 milk_task_model_iter_parent (GtkTreeModel *model,
223                              GtkTreeIter  *iter,
224                              GtkTreeIter  *child)
225 {
226         MilkTaskModelPrivate *priv;
227
228         g_return_val_if_fail (MILK_IS_TASK_MODEL (model), FALSE);
229         g_return_val_if_fail (iter, FALSE);
230         g_return_val_if_fail (child, FALSE);
231
232         priv = MILK_TASK_MODEL_PRIVATE (model);
233
234         return gtk_tree_model_iter_parent (
235                         GTK_TREE_MODEL (priv->store), iter, child);
236 }
237
238 static gboolean
239 milk_task_model_get_sort_column_id (GtkTreeSortable *sortable,
240                                     gint            *column_id,
241                                     GtkSortType     *order)
242 {
243         MilkTaskModel *model;
244         MilkTaskModelPrivate *priv;
245
246         g_return_if_fail (MILK_IS_TASK_MODEL (sortable));
247
248         model = MILK_TASK_MODEL (model);
249         priv = MILK_TASK_MODEL_PRIVATE (model);
250
251         return gtk_tree_sortable_get_sort_column_id (
252                         GTK_TREE_SORTABLE (priv->store), column_id, order);
253 }
254
255 static void
256 milk_task_model_set_sort_column_id (GtkTreeSortable *sortable,
257                                     gint             column_id,
258                                     GtkSortType      order)
259 {
260         MilkTaskModel *model;
261         MilkTaskModelPrivate *priv;
262
263         g_return_if_fail (MILK_IS_TASK_MODEL (sortable));
264
265         model = MILK_TASK_MODEL (model);
266         priv = MILK_TASK_MODEL_PRIVATE (model);
267
268         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->store),
269                         column_id, order);
270 }
271
272 static void
273 milk_task_model_set_default_sort_func (GtkTreeSortable        *sortable,
274                                        GtkTreeIterCompareFunc  callback,
275                                        gpointer                user_data,
276                                        GDestroyNotify          destroy_data)
277 {
278         MilkTaskModel *model;
279         MilkTaskModelPrivate *priv;
280
281         g_return_if_fail (MILK_IS_TASK_MODEL (sortable));
282
283         model = MILK_TASK_MODEL (model);
284         priv = MILK_TASK_MODEL_PRIVATE (model);
285
286         gtk_tree_sortable_set_default_sort_func (
287                         GTK_TREE_SORTABLE (priv->store), callback, user_data,
288                         destroy_data);
289 }
290
291 typedef gchar* (*RtmTaskAttrFunc) (RtmTask*);
292
293 static gboolean
294 model_store_find_task_by_attr (MilkTaskModel   *model,
295                                RtmTask         *task_in,
296                                RtmTaskAttrFunc  attr_func,
297                                GtkTreeIter     *iter_in)
298 {
299         MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (model);
300         gboolean valid;
301         GtkTreeIter iter;
302         gboolean found = FALSE;
303
304         valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store),
305                         &iter);
306         while (valid && !found) {
307                 RtmTask *task;
308
309                 gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
310                                         MILK_TASK_MODEL_COLUMN_TASK, &task,
311                                         -1);
312
313                 if (!g_strcmp0 (attr_func (task_in),
314                                 attr_func (task))) {
315                         *iter_in = iter;
316                         found = TRUE;
317                 }
318
319                 g_object_unref (task);
320
321                 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store),
322                                 &iter);
323         }
324
325         return found;
326 }
327
328 static gboolean
329 model_store_find_task (MilkTaskModel *model,
330                        RtmTask       *task_in,
331                        GtkTreeIter   *iter_in)
332 {
333         return model_store_find_task_by_attr (model, task_in, rtm_task_get_id,
334                         iter_in);
335 }
336
337 static gboolean
338 model_store_find_local_only_task (MilkTaskModel *model,
339                                   RtmTask       *task_in,
340                                   GtkTreeIter   *iter_in)
341 {
342         return model_store_find_task_by_attr (model, task_in,rtm_task_get_name, 
343                         iter_in);
344 }
345
346 static void
347 row_changed_cb (GtkTreeModel  *model,
348                 GtkTreePath   *path,
349                 GtkTreeIter   *iter,
350                 MilkTaskModel *self)
351 {
352         gtk_tree_model_row_changed (GTK_TREE_MODEL (self), path, iter);
353 }
354
355 static void
356 row_deleted_cb (GtkTreeModel  *model,
357                 GtkTreePath   *path,
358                 MilkTaskModel *self)
359 {
360         gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), path);
361 }
362
363 static void
364 row_inserted_cb (GtkTreeModel  *model,
365                  GtkTreePath   *path,
366                  GtkTreeIter   *iter,
367                  MilkTaskModel *self)
368 {
369         gtk_tree_model_row_inserted (GTK_TREE_MODEL (self), path, iter);
370 }
371
372 static void
373 rows_reordered_cb (GtkTreeModel  *model,
374                    GtkTreePath   *path,
375                    GtkTreeIter   *iter,
376                    gint          *new_order,
377                    MilkTaskModel *self)
378 {
379         gtk_tree_model_rows_reordered (GTK_TREE_MODEL (self), path, NULL,
380                         new_order);
381 }
382
383 static gint
384 model_priority_sort_func (GtkTreeModel *model,
385                           GtkTreeIter  *a,
386                           GtkTreeIter  *b,
387                           gpointer      user_data)
388 {
389         gint retval;
390         RtmTask *task_a, *task_b;
391         const char *priority_str_a, *priority_str_b;
392         gint64 priority_a, priority_b;
393         const char *name_a, *name_b;
394
395         gtk_tree_model_get (model, a,
396                         MILK_TASK_MODEL_COLUMN_TASK, &task_a,
397                         -1);
398
399         gtk_tree_model_get (model, b,
400                         MILK_TASK_MODEL_COLUMN_TASK, &task_b,
401                         -1);
402
403         priority_str_a = rtm_task_get_priority (task_a);
404         priority_str_b = rtm_task_get_priority (task_b);
405
406         /* these will be assigned 0 if they're not the well-known priorites
407          * (1-3) */
408         priority_a = g_ascii_strtoll (priority_str_a, NULL, 10);
409         priority_b = g_ascii_strtoll (priority_str_b, NULL, 10);
410
411         priority_a = (priority_a <= 0) ? G_MAXINT : priority_a;
412         priority_b = (priority_b <= 0) ? G_MAXINT : priority_b;
413
414         retval = (priority_a - priority_b);
415         if (retval != 0)
416                 return retval;
417
418         /* secondary sort, by name */
419         name_a = rtm_task_get_name (task_a);
420         name_b = rtm_task_get_name (task_b);
421
422         return g_utf8_collate (name_a, name_b);
423 }
424
425 static void
426 cache_cleared_cb (MilkCache     *cache,
427                   MilkTaskModel *model)
428 {
429         MilkTaskModelPrivate *priv;
430         priv = MILK_TASK_MODEL_PRIVATE (model);
431
432         gtk_list_store_clear (priv->store);
433 }
434
435 static void
436 cache_task_added_cb (MilkCache     *cache,
437                      RtmTask       *task,
438                      MilkTaskModel *model)
439 {
440         MilkTaskModelPrivate *priv;
441         GtkTreeIter iter;
442         const char *id;
443         gboolean task_in_store;
444
445         priv = MILK_TASK_MODEL_PRIVATE (model);
446
447         /* local-only tasks don't have a set task ID */
448         id = rtm_task_get_id (task);
449         if (id) {
450                 /* clear out any entries for the task created before we knew its
451                  * server-side ID */
452                 g_hash_table_remove (priv->tasks, rtm_task_get_name (task));
453         } else {
454                 id = rtm_task_get_name (task);
455         }
456         g_return_if_fail (id);
457
458         g_hash_table_insert (priv->tasks, g_strdup (id),
459                         g_object_ref (task));
460
461         task_in_store = model_store_find_task (model, task, &iter);
462
463         gtk_list_store_append (priv->store, &iter);
464         gtk_list_store_set (priv->store, &iter,
465                         MILK_TASK_MODEL_COLUMN_TASK, task, -1);
466 }
467
468 static void
469 cache_task_changed_cb (MilkCache     *cache,
470                        RtmTask       *task,
471                        MilkTaskModel *model)
472 {
473         MilkTaskModelPrivate *priv;
474         GtkTreeIter iter;
475         const char *id;
476         gboolean task_in_store;
477         RtmTask *old_task;
478         GtkTreePath *path;
479
480         priv = MILK_TASK_MODEL_PRIVATE (model);
481
482         id = rtm_task_get_id (task);
483         g_hash_table_insert (priv->tasks, g_strdup (id),
484                         g_object_ref (task));
485
486         /* try to find a local-only version of this task first, to upgrade it to
487          * remote status */
488         task_in_store = model_store_find_local_only_task (model, task, &iter);
489         if (!task_in_store) {
490                 /* FIXME: cut this */
491                 g_debug ("task (supposedly) was already known remotely");
492
493                 task_in_store = model_store_find_task (model, task, &iter);
494         } else {
495                 /* FIXME: cut this */
496                 g_debug ("task was *NOT* known remotely");
497         }
498
499         /* rtm-glib doesn't re-use task structs when they're updated, so we have
500          * to replace the changed */
501         gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
502                         MILK_TASK_MODEL_COLUMN_TASK, &old_task, -1);
503
504         gtk_list_store_set (priv->store, &iter,
505                         MILK_TASK_MODEL_COLUMN_TASK, task, -1);
506
507         path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
508         gtk_tree_model_row_changed (GTK_TREE_MODEL (priv->store), path, &iter);
509         gtk_tree_path_free (path);
510
511         g_object_unref (old_task);
512 }
513
514 static void
515 cache_task_finished_cb (MilkCache     *cache,
516                         RtmTask       *task,
517                         MilkTaskModel *model)
518 {
519         MilkTaskModelPrivate *priv;
520         GtkTreeIter iter;
521         const char *id;
522         gboolean task_in_store;
523
524         priv = MILK_TASK_MODEL_PRIVATE (model);
525
526         id = rtm_task_get_id (task);
527         g_hash_table_insert (priv->tasks, g_strdup (id),
528                         g_object_ref (task));
529
530         task_in_store = model_store_find_task (model, task, &iter);
531
532         if (task_in_store)
533                 gtk_list_store_remove (priv->store, &iter);
534 }
535
536 static void
537 set_cache (MilkTaskModel *model,
538            MilkCache     *cache)
539 {
540         MilkTaskModelPrivate *priv;
541         GList *tasks, *l;
542
543         g_return_if_fail (MILK_IS_TASK_MODEL (model));
544         g_return_if_fail (MILK_IS_CACHE (cache));
545
546         priv = MILK_TASK_MODEL_PRIVATE (model);
547
548         if (priv->cache) {
549                 g_object_unref (priv->cache);
550         }
551         priv->cache = g_object_ref (cache);
552
553         gtk_list_store_clear (priv->store);
554
555         g_signal_connect (cache, "cleared", G_CALLBACK (cache_cleared_cb),
556                         model);
557         g_signal_connect (cache, "task-added", G_CALLBACK (cache_task_added_cb),
558                         model);
559         g_signal_connect (cache, "task-changed",
560                         G_CALLBACK (cache_task_changed_cb), model);
561         g_signal_connect (cache, "task-finished",
562                         G_CALLBACK (cache_task_finished_cb), model);
563
564         /* do the initial fill from the cache */
565         tasks = milk_cache_get_active_tasks (cache);
566         for (l = tasks; l; l = l->next) {
567                 cache_task_added_cb (cache, l->data, model);
568         }
569         g_list_free (tasks);
570 }
571
572 static void
573 milk_task_model_get_property (GObject    *object,
574                               guint       property_id,
575                               GValue     *value,
576                               GParamSpec *pspec)
577 {
578         MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object);
579
580         switch (property_id)
581         {
582                 case PROP_CACHE:
583                         g_value_set_object (value, priv->cache);
584                 break;
585
586                 default:
587                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
588                                         pspec);
589         }
590 }
591
592 static void
593 milk_task_model_set_property (GObject      *object,
594                               guint         property_id,
595                               const GValue *value,
596                               GParamSpec   *pspec)
597 {
598         switch (property_id)
599         {
600                 case PROP_CACHE:
601                         set_cache (MILK_TASK_MODEL (object),
602                                         g_value_get_object (value));
603                 break;
604
605                 default:
606                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id,
607                                         pspec);
608         }
609 }
610
611 static void
612 milk_task_model_dispose (GObject *object)
613 {
614         MilkTaskModelPrivate *priv = MILK_TASK_MODEL_PRIVATE (object);
615
616         g_signal_handlers_disconnect_by_func (priv->cache, cache_cleared_cb,
617                         object);
618         g_signal_handlers_disconnect_by_func (priv->cache, cache_task_added_cb,
619                         object);
620         g_signal_handlers_disconnect_by_func (priv->cache,
621                         cache_task_changed_cb, object);
622         g_signal_handlers_disconnect_by_func (priv->cache,
623                         cache_task_finished_cb, object);
624
625         if (priv->cache) {
626                 g_object_unref (priv->cache);
627                 priv->cache = NULL;
628         }
629
630         g_signal_handlers_disconnect_by_func (priv->store, row_changed_cb,
631                         object);
632         g_signal_handlers_disconnect_by_func (priv->store, row_deleted_cb,
633                         object);
634         g_signal_handlers_disconnect_by_func (priv->store, row_inserted_cb,
635                         object);
636         g_signal_handlers_disconnect_by_func (priv->store, rows_reordered_cb,
637                         object);
638
639         if (priv->store) {
640                 g_object_unref (priv->store);
641                 priv->store = NULL;
642         }
643
644         if (priv->tasks) {
645                 g_hash_table_destroy (priv->tasks);
646                 priv->tasks = NULL;
647         }
648
649         G_OBJECT_CLASS (milk_task_model_parent_class)->dispose (object);
650 }
651
652 static void
653 milk_task_model_class_init (MilkTaskModelClass *klass)
654 {
655         GObjectClass *object_class = G_OBJECT_CLASS (klass);
656
657         g_type_class_add_private (klass, sizeof (MilkTaskModelPrivate));
658
659         object_class->get_property = milk_task_model_get_property;
660         object_class->set_property = milk_task_model_set_property;
661         object_class->dispose = milk_task_model_dispose;
662
663         g_object_class_install_property
664                 (object_class,
665                  PROP_CACHE,
666                  g_param_spec_object
667                          ("cache",
668                           "Cache of tasks",
669                           "Remember The Milk tasks cache.",
670                           MILK_TYPE_CACHE,
671                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
672                           G_PARAM_STATIC_STRINGS));
673 }
674
675 static void
676 milk_task_model_init (MilkTaskModel *self)
677 {
678         MilkTaskModelPrivate *priv;
679
680         self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (
681                         self, MILK_TYPE_TASK_MODEL, MilkTaskModelPrivate);
682
683         priv->tasks = g_hash_table_new_full (g_str_hash, g_str_equal,
684                         g_free, g_object_unref);
685
686         priv->store = gtk_list_store_new (
687                         MILK_TASK_MODEL_N_COLUMNS, RTM_TYPE_TASK);
688
689         gtk_tree_sortable_set_default_sort_func (
690                         GTK_TREE_SORTABLE (priv->store),
691                         model_priority_sort_func, g_object_ref (self),
692                         g_object_unref);
693
694         gtk_tree_sortable_set_sort_column_id (
695                         GTK_TREE_SORTABLE (priv->store),
696                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
697                         GTK_SORT_ASCENDING);
698
699         g_signal_connect (priv->store, "row-changed",
700                         G_CALLBACK (row_changed_cb), self);
701
702         g_signal_connect (priv->store, "row-deleted",
703                         G_CALLBACK (row_deleted_cb), self);
704
705         g_signal_connect (priv->store, "row-inserted",
706                         G_CALLBACK (row_inserted_cb), self);
707
708         g_signal_connect (priv->store, "rows-reordered",
709                         G_CALLBACK (rows_reordered_cb), self);
710 }
711
712 static void
713 milk_task_model_tree_model_init (GtkTreeModelIface *iface)
714 {
715         iface->get_flags       = milk_task_model_get_flags;
716         iface->get_n_columns   = milk_task_model_get_n_columns;
717         iface->get_column_type = milk_task_model_get_column_type;
718         iface->get_iter        = milk_task_model_get_iter;
719         iface->get_path        = milk_task_model_get_path;
720         iface->get_value       = milk_task_model_get_value;
721         iface->iter_next       = milk_task_model_iter_next;
722         iface->iter_children   = milk_task_model_iter_children;
723         iface->iter_has_child  = milk_task_model_iter_has_child;
724         iface->iter_n_children = milk_task_model_iter_n_children;
725         iface->iter_nth_child  = milk_task_model_iter_nth_child;
726         iface->iter_parent     = milk_task_model_iter_parent;
727 }
728
729 static void
730 milk_task_model_tree_sortable_init (GtkTreeSortableIface *iface)
731 {
732         iface->get_sort_column_id    = milk_task_model_get_sort_column_id;
733         iface->set_sort_column_id    = milk_task_model_set_sort_column_id;
734         iface->set_default_sort_func = milk_task_model_set_default_sort_func;
735 }
736
737 MilkTaskModel*
738 milk_task_model_new ()
739 {
740         return g_object_new (MILK_TYPE_TASK_MODEL,
741                         "cache", milk_cache_get_default (), NULL);
742 }