1 /*
2  * frogr-model.c -- Model in frogr
3  *
4  * Copyright (C) 2009-2012 Mario Sanchez Prada
5  * Authors: Mario Sanchez Prada <msanchez@gnome.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 3 of the GNU General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>
18  *
19  */
20 
21 #include "frogr-model.h"
22 
23 #include "frogr-account.h"
24 #include "frogr-file-loader.h"
25 
26 #define TAGS_DELIMITER " "
27 
28 
29 struct _FrogrModel
30 {
31   GObject parent;
32 
33   GSList *pictures;
34 
35   /* For sequential access of groups and sets */
36   GSList *remote_sets;
37   GSList *local_sets;
38   GSList *all_sets;
39   GSList *groups;
40 
41   /* For random acces (e.g. get a group by ID) */
42   GHashTable *sets_table;
43   GHashTable *groups_table;
44 
45   GSList *remote_tags;
46   GSList *local_tags;
47   GSList *all_tags;
48 };
49 
50 G_DEFINE_TYPE (FrogrModel, frogr_model, G_TYPE_OBJECT)
51 
52 
53 /* Signals */
54 enum {
55   PICTURE_ADDED,
56   PICTURE_REMOVED,
57   MODEL_CHANGED,
58   MODEL_DESERIALIZED,
59   N_SIGNALS
60 };
61 
62 static guint signals[N_SIGNALS] = { 0 };
63 
64 /* Private API */
65 
66 static void
_remove_remote_photosets(FrogrModel * self)67 _remove_remote_photosets (FrogrModel *self)
68 {
69   FrogrPhotoSet *set = NULL;
70   GSList *item = NULL;
71   const gchar *id = NULL;
72 
73   g_return_if_fail(FROGR_IS_MODEL (self));
74 
75   if (!self->remote_sets)
76     return;
77 
78   /* Remove from the hash table first */
79   for (item = self->remote_sets; item; item = g_slist_next (item))
80     {
81       set = FROGR_PHOTOSET (item->data);
82       id = frogr_photoset_get_id (set);
83       if (id)
84         g_hash_table_remove (self->sets_table, id);
85 
86       /* A remote photo set might be still indexed by its local ID */
87       id = frogr_photoset_get_local_id (set);
88       if (id)
89         g_hash_table_remove (self->sets_table, id);
90     }
91 
92   g_slist_free_full (self->remote_sets, g_object_unref);
93   self->remote_sets = NULL;
94 }
95 
96 static void
_remove_local_photosets(FrogrModel * self)97 _remove_local_photosets (FrogrModel *self)
98 {
99   FrogrPhotoSet *set = NULL;
100   GSList *item = NULL;
101 
102   g_return_if_fail(FROGR_IS_MODEL (self));
103 
104   if (!self->local_sets)
105     return;
106 
107   /* Remove from the hash table first */
108   for (item = self->remote_sets; item; item = g_slist_next (item))
109     {
110       set = FROGR_PHOTOSET (item->data);
111       g_hash_table_remove (self->sets_table, frogr_photoset_get_local_id (set));
112     }
113 
114   g_slist_free_full (self->local_sets, g_object_unref);
115   self->local_sets = NULL;
116 }
117 
118 static void
_remove_pictures(FrogrModel * self)119 _remove_pictures (FrogrModel *self)
120 {
121   FrogrPicture *picture = NULL;
122 
123   g_return_if_fail(FROGR_IS_MODEL (self));
124 
125   while (self->pictures)
126     {
127       picture = FROGR_PICTURE (self->pictures->data);
128       self->pictures = g_slist_remove (self->pictures, picture);
129       g_signal_emit (self, signals[PICTURE_REMOVED], 0, picture);
130       g_object_unref (picture);
131     }
132 
133   g_slist_free (self->pictures);
134   self->pictures = NULL;
135 
136   g_signal_emit (self, signals[MODEL_CHANGED], 0);
137 }
138 
139 static void
_remove_all_photosets(FrogrModel * self)140 _remove_all_photosets (FrogrModel *self)
141 {
142   g_return_if_fail(FROGR_IS_MODEL (self));
143 
144   if (self->all_sets)
145     {
146       g_slist_free (self->all_sets);
147       self->all_sets = NULL;
148     }
149 
150   _remove_remote_photosets (self);
151   _remove_local_photosets (self);
152 
153   if (self->sets_table)
154     g_hash_table_remove_all (self->sets_table);
155 }
156 
157 static void
_remove_groups(FrogrModel * self)158 _remove_groups (FrogrModel *self)
159 {
160   g_return_if_fail(FROGR_IS_MODEL (self));
161 
162   if (self->groups)
163     {
164       g_slist_free_full (self->groups, g_object_unref);
165       self->groups = NULL;
166     }
167 
168   if (self->groups_table)
169     g_hash_table_remove_all (self->groups_table);
170 }
171 
172 static void
_remove_remote_tags(FrogrModel * self)173 _remove_remote_tags (FrogrModel *self)
174 {
175   g_return_if_fail(FROGR_IS_MODEL (self));
176 
177   if (!self->remote_tags)
178     return;
179 
180   g_slist_free_full (self->remote_tags, g_free);
181   self->remote_tags = NULL;
182 }
183 
184 static void
_remove_local_tags(FrogrModel * self)185 _remove_local_tags (FrogrModel *self)
186 {
187   g_return_if_fail(FROGR_IS_MODEL (self));
188 
189   if (!self->local_tags)
190     return;
191 
192   g_slist_free_full (self->local_tags, g_free);
193   self->local_tags = NULL;
194 }
195 
196 static void
_remove_all_tags(FrogrModel * self)197 _remove_all_tags (FrogrModel *self)
198 {
199   g_return_if_fail(FROGR_IS_MODEL (self));
200 
201   if (self->all_tags)
202     {
203       g_slist_free (self->all_tags);
204       self->all_tags = NULL;
205     }
206 
207   _remove_remote_tags (self);
208   _remove_local_tags (self);
209 }
210 
211 static void
_set_local_tags(FrogrModel * self,GSList * tags_list)212 _set_local_tags (FrogrModel *self, GSList *tags_list)
213 {
214   g_return_if_fail(FROGR_IS_MODEL (self));
215   _remove_local_tags (self);
216   self->local_tags = tags_list;
217 }
218 
219 static JsonArray *
_serialize_list_to_json_array(GSList * list,GType g_type)220 _serialize_list_to_json_array (GSList *list, GType g_type)
221 {
222   JsonArray *json_array = NULL;
223   JsonNode *json_node = NULL;
224   GSList *item = NULL;
225 
226   /* Generate a JsonArray with contents */
227   json_array = json_array_new ();
228   for (item = list; item; item = g_slist_next (item))
229     {
230       if (g_type == G_TYPE_OBJECT)
231         json_node = json_gobject_serialize (G_OBJECT (item->data));
232       else if (g_type == G_TYPE_STRING)
233         {
234           json_node = json_node_new (JSON_NODE_VALUE);
235           json_node_set_string (json_node, (const gchar*)item->data);
236         }
237 
238       if (json_node)
239         json_array_add_element (json_array, json_node);
240     }
241 
242   return json_array;
243 }
244 
245 static GSList *
_deserialize_list_from_json_array(JsonArray * array,GType g_type)246 _deserialize_list_from_json_array (JsonArray *array, GType g_type)
247 {
248   JsonNode *json_node = NULL;
249   GSList *result_list = NULL;
250   gpointer element = NULL;
251   guint n_elements = 0;
252   guint i = 0;
253 
254   n_elements = json_array_get_length (array);
255   if (!n_elements)
256     return NULL;
257 
258   for (i = 0; i < n_elements; i++)
259     {
260       json_node = json_array_get_element (array, i);
261       if (JSON_NODE_HOLDS_OBJECT (json_node))
262         element = json_gobject_deserialize (g_type, json_node);
263       else if (g_type == G_TYPE_STRING)
264         element = json_node_dup_string (json_node);
265 
266       if (element)
267         result_list = g_slist_append (result_list, element);
268     }
269 
270   return result_list;
271 }
272 
273 static void
_on_file_loaded(FrogrFileLoader * loader,FrogrPicture * picture,FrogrModel * self)274 _on_file_loaded (FrogrFileLoader *loader, FrogrPicture *picture, FrogrModel *self)
275 {
276   g_return_if_fail (FROGR_IS_MODEL (self));
277   frogr_model_add_picture (self, picture);
278 }
279 
280 static void
_on_files_loaded(FrogrFileLoader * loader,FrogrModel * self)281 _on_files_loaded (FrogrFileLoader *loader, FrogrModel *self)
282 {
283   g_signal_emit (self, signals[MODEL_DESERIALIZED], 0);
284 }
285 
286 static void
_frogr_model_dispose(GObject * object)287 _frogr_model_dispose (GObject* object)
288 {
289   FrogrModel *self = FROGR_MODEL (object);
290 
291   _remove_pictures (self);
292   _remove_all_photosets (self);
293   _remove_groups (self);
294   _remove_all_tags (self);
295 
296   if (self->sets_table)
297     {
298       g_hash_table_destroy (self->sets_table);
299       self->sets_table = NULL;
300     }
301 
302   if (self->groups_table)
303     {
304       g_hash_table_destroy (self->groups_table);
305       self->groups_table = NULL;
306     }
307 
308   G_OBJECT_CLASS (frogr_model_parent_class)->dispose (object);
309 }
310 
311 static void
frogr_model_class_init(FrogrModelClass * klass)312 frogr_model_class_init(FrogrModelClass *klass)
313 {
314   GObjectClass *obj_class = G_OBJECT_CLASS(klass);
315   obj_class->dispose = _frogr_model_dispose;
316 
317   signals[PICTURE_ADDED] =
318     g_signal_new ("picture-added",
319                   G_OBJECT_CLASS_TYPE (klass),
320                   G_SIGNAL_RUN_FIRST,
321                   0, NULL, NULL,
322                   g_cclosure_marshal_VOID__OBJECT,
323                   G_TYPE_NONE, 1, FROGR_TYPE_PICTURE);
324 
325   signals[PICTURE_REMOVED] =
326     g_signal_new ("picture-removed",
327                   G_OBJECT_CLASS_TYPE (klass),
328                   G_SIGNAL_RUN_FIRST,
329                   0, NULL, NULL,
330                   g_cclosure_marshal_VOID__OBJECT,
331                   G_TYPE_NONE, 1, FROGR_TYPE_PICTURE);
332 
333   signals[MODEL_CHANGED] =
334     g_signal_new ("model-changed",
335                   G_OBJECT_CLASS_TYPE (klass),
336                   G_SIGNAL_RUN_FIRST,
337                   0, NULL, NULL,
338                   g_cclosure_marshal_VOID__VOID,
339                   G_TYPE_NONE, 0);
340 
341   signals[MODEL_DESERIALIZED] =
342     g_signal_new ("model-deserialized",
343                   G_OBJECT_CLASS_TYPE (klass),
344                   G_SIGNAL_RUN_FIRST,
345                   0, NULL, NULL,
346                   g_cclosure_marshal_VOID__VOID,
347                   G_TYPE_NONE, 0);
348 }
349 
350 static void
frogr_model_init(FrogrModel * self)351 frogr_model_init (FrogrModel *self)
352 {
353   /* Init private data */
354   self->pictures = NULL;
355   self->remote_sets = NULL;
356   self->local_sets = NULL;
357   self->all_sets = NULL;
358   self->groups = NULL;
359 
360   /* For random access */
361   self->sets_table = g_hash_table_new_full (g_str_hash, g_str_equal,
362                                             (GDestroyNotify)g_free,
363                                             (GDestroyNotify)g_object_unref);
364 
365   self->groups_table = g_hash_table_new_full (g_str_hash, g_str_equal,
366                                               (GDestroyNotify)g_free,
367                                               (GDestroyNotify)g_object_unref);
368 
369   self->remote_tags = NULL;
370   self->local_tags = NULL;
371   self->all_tags = NULL;
372 }
373 
374 /* Public API */
375 
376 FrogrModel *
frogr_model_new(void)377 frogr_model_new (void)
378 {
379   GObject *new = g_object_new(FROGR_TYPE_MODEL, NULL);
380   return FROGR_MODEL (new);
381 }
382 
383 void
frogr_model_add_picture(FrogrModel * self,FrogrPicture * picture)384 frogr_model_add_picture (FrogrModel *self,
385                          FrogrPicture *picture)
386 {
387   g_return_if_fail(FROGR_IS_MODEL (self));
388   g_return_if_fail(FROGR_IS_PICTURE (picture));
389 
390   self->pictures = g_slist_append (self->pictures, g_object_ref (picture));
391 
392   g_signal_emit (self, signals[PICTURE_ADDED], 0, picture);
393   g_signal_emit (self, signals[MODEL_CHANGED], 0);
394 }
395 
396 void
frogr_model_remove_picture(FrogrModel * self,FrogrPicture * picture)397 frogr_model_remove_picture (FrogrModel *self,
398                             FrogrPicture *picture)
399 {
400   g_return_if_fail(FROGR_IS_MODEL (self));
401 
402   self->pictures = g_slist_remove (self->pictures, picture);
403 
404   g_signal_emit (self, signals[PICTURE_REMOVED], 0, picture);
405   g_signal_emit (self, signals[MODEL_CHANGED], 0);
406   g_object_unref (picture);
407 }
408 
409 guint
frogr_model_n_pictures(FrogrModel * self)410 frogr_model_n_pictures (FrogrModel *self)
411 {
412   g_return_val_if_fail(FROGR_IS_MODEL (self), 0);
413   return g_slist_length (self->pictures);
414 }
415 
416 GSList *
frogr_model_get_pictures(FrogrModel * self)417 frogr_model_get_pictures (FrogrModel *self)
418 {
419   g_return_val_if_fail(FROGR_IS_MODEL (self), NULL);
420   return self->pictures;
421 }
422 
423 void
frogr_model_notify_changes_in_pictures(FrogrModel * self)424 frogr_model_notify_changes_in_pictures (FrogrModel *self)
425 {
426   /* Just emit the signal so the main view gets notified too */
427   g_signal_emit (self, signals[MODEL_CHANGED], 0);
428 }
429 
430 void
frogr_model_set_remote_photosets(FrogrModel * self,GSList * remote_sets)431 frogr_model_set_remote_photosets (FrogrModel *self,
432                                   GSList *remote_sets)
433 {
434   FrogrPhotoSet *set = NULL;
435   GSList *item = NULL;
436 
437   g_return_if_fail(FROGR_IS_MODEL (self));
438 
439   /* Remove all the remote photosets */
440   _remove_remote_photosets (self);
441 
442   /* Set photosets now (and update the hash table) */
443   for (item = remote_sets; item; item = g_slist_next (item))
444     {
445       set = FROGR_PHOTOSET (item->data);
446       g_hash_table_insert (self->sets_table,
447                            g_strdup (frogr_photoset_get_id (set)),
448                            g_object_ref (set));
449     }
450   self->remote_sets = remote_sets;
451 }
452 
453 void
frogr_model_add_local_photoset(FrogrModel * self,FrogrPhotoSet * set)454 frogr_model_add_local_photoset (FrogrModel *self,
455                                 FrogrPhotoSet *set)
456 {
457   g_return_if_fail(FROGR_IS_MODEL (self));
458   g_return_if_fail(FROGR_IS_PHOTOSET (set));
459 
460   /* When adding one by one we prepend always to keep the order */
461   self->local_sets = g_slist_prepend (self->local_sets, g_object_ref (set));
462 
463   /* Update the hash table too! */
464   g_hash_table_insert (self->sets_table,
465                        g_strdup (frogr_photoset_get_local_id (set)),
466                        g_object_ref (set));
467 
468   g_signal_emit (self, signals[MODEL_CHANGED], 0);
469 }
470 
471 GSList *
frogr_model_get_photosets(FrogrModel * self)472 frogr_model_get_photosets (FrogrModel *self)
473 {
474   GSList *list = NULL;
475   GSList *current = NULL;
476 
477   g_return_val_if_fail(FROGR_IS_MODEL (self), 0);
478 
479   /* Copy the list of remote sets and add those locally added */
480   list = g_slist_copy (self->remote_sets);
481   for (current = self->local_sets; current; current = g_slist_next (current))
482     {
483       if (!g_slist_find_custom (list, current->data, (GCompareFunc)frogr_photoset_compare))
484         list = g_slist_prepend (list, current->data);
485     }
486 
487   /* Update internal pointers to the result list */
488   if (self->all_sets)
489     g_slist_free (self->all_sets);
490   self->all_sets = list;
491 
492   return self->all_sets;
493 }
494 
495 void
frogr_model_set_photosets(FrogrModel * self,GSList * photosets)496 frogr_model_set_photosets (FrogrModel *self,
497                            GSList *photosets)
498 {
499   FrogrPhotoSet *set = NULL;
500   GSList *item = NULL;
501   GSList *next_item = NULL;
502 
503   g_return_if_fail(FROGR_IS_MODEL (self));
504 
505   /* Remove all sets */
506   _remove_all_photosets (self);
507 
508   /* Set groups now, separating them into two lists: local and remote */
509   item = photosets;
510   while (item)
511     {
512       set = FROGR_PHOTOSET(item->data);
513       if (frogr_photoset_is_local (set))
514         {
515           next_item = item->next;
516           photosets = g_slist_remove_link (photosets, item);
517           frogr_model_add_local_photoset (self, set);
518           g_object_unref (set);
519           g_slist_free (item);
520 
521           item = next_item;
522         }
523       else
524         item = g_slist_next (item);
525     }
526 
527   /* Once separated the local photosets, we assign the remote ones */
528   frogr_model_set_remote_photosets (self, photosets);
529 }
530 
531 guint
frogr_model_n_photosets(FrogrModel * self)532 frogr_model_n_photosets (FrogrModel *self)
533 {
534   g_return_val_if_fail(FROGR_IS_MODEL (self), 0);
535   return g_slist_length (self->remote_sets) + g_slist_length (self->local_sets);
536 }
537 
538 FrogrPhotoSet *
frogr_model_get_photoset_by_id(FrogrModel * self,const gchar * id)539 frogr_model_get_photoset_by_id (FrogrModel *self, const gchar *id)
540 {
541   g_return_val_if_fail(FROGR_IS_MODEL (self), NULL);
542   return g_hash_table_lookup (self->sets_table, id);
543 }
544 
545 guint
frogr_model_n_groups(FrogrModel * self)546 frogr_model_n_groups (FrogrModel *self)
547 {
548   g_return_val_if_fail(FROGR_IS_MODEL (self), 0);
549   return g_slist_length (self->groups);
550 }
551 
552 GSList *
frogr_model_get_groups(FrogrModel * self)553 frogr_model_get_groups (FrogrModel *self)
554 {
555   g_return_val_if_fail(FROGR_IS_MODEL (self), NULL);
556   return self->groups;
557 }
558 
559 void
frogr_model_set_groups(FrogrModel * self,GSList * groups)560 frogr_model_set_groups (FrogrModel *self,
561                         GSList *groups)
562 {
563   FrogrGroup *group = NULL;
564   GSList *item = NULL;
565 
566   g_return_if_fail(FROGR_IS_MODEL (self));
567 
568   /* Remove all groups */
569   _remove_groups (self);
570 
571   /* Set groups now (and update the hash table) */
572   for (item = groups; item; item = g_slist_next (item))
573     {
574       group = FROGR_GROUP (item->data);
575       g_hash_table_insert (self->groups_table,
576                            g_strdup (frogr_group_get_id (group)),
577                            g_object_ref (group));
578     }
579 
580   /* Set groups now */
581   self->groups = groups;
582 }
583 
584 FrogrGroup *
frogr_model_get_group_by_id(FrogrModel * self,const gchar * id)585 frogr_model_get_group_by_id (FrogrModel *self, const gchar *id)
586 {
587   g_return_val_if_fail(FROGR_IS_MODEL (self), NULL);
588   return g_hash_table_lookup (self->groups_table, id);
589 }
590 
591 void
frogr_model_set_remote_tags(FrogrModel * self,GSList * tags_list)592 frogr_model_set_remote_tags (FrogrModel *self, GSList *tags_list)
593 {
594   g_return_if_fail(FROGR_IS_MODEL (self));
595   _remove_remote_tags (self);
596   self->remote_tags = tags_list;
597 }
598 
599 void
frogr_model_remove_remote_tags(FrogrModel * self)600 frogr_model_remove_remote_tags (FrogrModel *self)
601 {
602   g_return_if_fail(FROGR_IS_MODEL (self));
603 
604   g_slist_free_full (self->remote_tags, g_free);
605   self->remote_tags = NULL;
606 }
607 
608 void
frogr_model_add_local_tags_from_string(FrogrModel * self,const gchar * tags_string)609 frogr_model_add_local_tags_from_string (FrogrModel *self,
610                                         const gchar *tags_string)
611 {
612   g_autofree gchar *stripped_tags = NULL;
613   gboolean added_new_tags = FALSE;
614 
615   g_return_if_fail(FROGR_IS_MODEL (self));
616 
617   if (!tags_string || !tags_string[0])
618     return;
619 
620   stripped_tags = g_strstrip (g_strdup (tags_string));
621   if (!g_str_equal (stripped_tags, ""))
622     {
623       g_auto(GStrv) tags_array = NULL;
624       gchar *tag;
625       gint i;
626 
627       /* Now iterate over every token, adding it to the list */
628       tags_array = g_strsplit (stripped_tags, TAGS_DELIMITER, -1);
629       for (i = 0; tags_array[i]; i++)
630         {
631           /* add stripped tag if not already set*/
632           tag = g_strstrip(g_strdup (tags_array[i]));
633           if (!g_str_equal (tag, "") && !g_slist_find_custom (self->local_tags, tag, (GCompareFunc)g_strcmp0))
634             {
635               self->local_tags = g_slist_prepend (self->local_tags, g_strdup (tag));
636               added_new_tags = TRUE;
637             }
638 
639           g_free (tag);
640         }
641 
642       self->local_tags = g_slist_sort (self->local_tags, (GCompareFunc)g_strcmp0);
643     }
644 
645   if (added_new_tags)
646     g_signal_emit (self, signals[MODEL_CHANGED], 0);
647 }
648 
649 GSList *
frogr_model_get_tags(FrogrModel * self)650 frogr_model_get_tags (FrogrModel *self)
651 {
652   GSList *list = NULL;
653   GSList *current = NULL;
654 
655   g_return_val_if_fail(FROGR_IS_MODEL (self), 0);
656 
657   /* Copy the list of remote tags and add those locally added */
658   list = g_slist_copy (self->remote_tags);
659   for (current = self->local_tags; current; current = g_slist_next (current))
660     {
661       if (!g_slist_find_custom (list, current->data, (GCompareFunc)g_strcmp0))
662         list = g_slist_prepend (list, current->data);
663     }
664   list = g_slist_sort (list, (GCompareFunc)g_strcmp0);
665 
666   /* Update internal pointers to the result list */
667   if (self->all_tags)
668     g_slist_free (self->all_tags);
669   self->all_tags = list;
670 
671   return self->all_tags;
672 }
673 
674 guint
frogr_model_n_tags(FrogrModel * self)675 frogr_model_n_tags (FrogrModel *self)
676 {
677   g_return_val_if_fail(FROGR_IS_MODEL (self), 0);
678   return g_slist_length (frogr_model_get_tags (self));
679 }
680 
681 guint
frogr_model_n_local_tags(FrogrModel * self)682 frogr_model_n_local_tags (FrogrModel *self)
683 {
684   g_return_val_if_fail(FROGR_IS_MODEL (self), 0);
685   return g_slist_length (self->local_tags);
686 }
687 
688 JsonObject *
frogr_model_serialize(FrogrModel * self)689 frogr_model_serialize (FrogrModel *self)
690 {
691   JsonArray *json_array = NULL;
692   JsonObject *root_object = NULL;
693   GSList *data_list = NULL;
694 
695   g_return_val_if_fail(FROGR_IS_MODEL (self), NULL);
696 
697   root_object = json_object_new ();
698 
699   data_list = frogr_model_get_pictures (self);
700   json_array = _serialize_list_to_json_array (data_list, G_TYPE_OBJECT);
701   json_object_set_array_member (root_object, "pictures", json_array);
702 
703   data_list = frogr_model_get_photosets (self);
704   json_array = _serialize_list_to_json_array (data_list, G_TYPE_OBJECT);
705   json_object_set_array_member (root_object, "photosets", json_array);
706 
707   data_list = frogr_model_get_groups (self);
708   json_array = _serialize_list_to_json_array (data_list, G_TYPE_OBJECT);
709   json_object_set_array_member (root_object, "groups", json_array);
710 
711   /* Only serialize the local tags, not to bloat the project file too much */
712   json_array = _serialize_list_to_json_array (self->local_tags,
713                                               G_TYPE_STRING);
714   json_object_set_array_member (root_object, "tags", json_array);
715 
716   return root_object;
717 }
718 
719 void
frogr_model_deserialize(FrogrModel * self,JsonObject * root_object)720 frogr_model_deserialize (FrogrModel *self, JsonObject *root_object)
721 {
722   JsonArray *array_member = NULL;
723   GSList *pictures = NULL;
724   GSList *sets = NULL;
725   GSList *groups = NULL;
726   GSList *tags = NULL;
727 
728   g_return_if_fail(FROGR_IS_MODEL (self));
729 
730   /* First we get the different lists with data for sets, groups and tags */
731   array_member = json_object_get_array_member (root_object, "photosets");
732   if (array_member)
733     sets = _deserialize_list_from_json_array (array_member, FROGR_TYPE_PHOTOSET);
734 
735   array_member = json_object_get_array_member (root_object, "groups");
736   if (array_member)
737     groups = _deserialize_list_from_json_array (array_member, FROGR_TYPE_GROUP);
738 
739   array_member = json_object_get_array_member (root_object, "tags");
740   if (array_member)
741     tags = _deserialize_list_from_json_array (array_member, G_TYPE_STRING);
742 
743   /* We set the sets and groups */
744   frogr_model_set_photosets (self, sets);
745   frogr_model_set_groups (self, groups);
746 
747   /* We only serialized local tags */
748   _set_local_tags (self, tags);
749 
750   /* Pictures must be deserialized at the end, since they will hold
751      references to sets and groups previously imported in the model */
752   array_member = json_object_get_array_member (root_object, "pictures");
753   if (array_member)
754     pictures = _deserialize_list_from_json_array (array_member, FROGR_TYPE_PICTURE);
755 
756   if (pictures)
757     {
758       FrogrFileLoader *loader = NULL;
759 
760       /* Now we take the list of pictures and add them into the
761          model as the associated thumbnails are being loaded */
762       loader = frogr_file_loader_new_from_pictures (pictures);
763 
764       g_signal_connect (G_OBJECT (loader), "file-loaded",
765                         G_CALLBACK (_on_file_loaded),
766                         self);
767 
768       g_signal_connect (G_OBJECT (loader), "files-loaded",
769                         G_CALLBACK (_on_files_loaded),
770                         self);
771       /* Load the pictures! */
772       _remove_pictures (self);
773       frogr_file_loader_load (loader);
774     }
775   else
776     {
777       /* We are done deserializing already now if there are no pictures */
778       g_signal_emit (self, signals[MODEL_DESERIALIZED], 0);
779     }
780 }
781