1 /*
2 * frogr-picture.c -- A picture 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-picture.h"
22
23 #include "frogr-controller.h"
24 #include "frogr-model.h"
25
26 #include <json-glib/json-glib.h>
27
28 #define TAGS_DELIMITER " "
29
30 static void json_serializable_init (JsonSerializableIface *iface);
31
32
33 struct _FrogrPicture
34 {
35 GObject parent;
36
37 gchar *id;
38 gchar *fileuri;
39 gchar *title;
40 gchar *description;
41 gchar *tags_string;
42 GSList *tags_list;
43
44 gboolean is_public;
45 gboolean is_friend;
46 gboolean is_family;
47
48 FspSafetyLevel safety_level;
49 FspContentType content_type;
50 FspLicense license;
51 FrogrLocation *location;
52 gboolean show_in_search;
53 gboolean send_location;
54 gboolean replace_date_posted;
55
56 gboolean is_video;
57
58 guint filesize; /* In KB */
59 gchar *datetime; /* ASCII, locale dependent, string */
60
61 GSList *photosets;
62 GSList *groups;
63
64 GdkPixbuf *pixbuf;
65 };
66
67 G_DEFINE_TYPE_EXTENDED (FrogrPicture, frogr_picture, G_TYPE_OBJECT, 0,
68 G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE,
69 json_serializable_init))
70
71
72 /* Properties */
73 enum {
74 PROP_0,
75 PROP_ID,
76 PROP_FILEURI,
77 PROP_TITLE,
78 PROP_DESCRIPTION,
79 PROP_TAGS_STRING,
80 PROP_IS_PUBLIC,
81 PROP_IS_FAMILY,
82 PROP_IS_FRIEND,
83 PROP_SAFETY_LEVEL,
84 PROP_CONTENT_TYPE,
85 PROP_LICENSE,
86 PROP_LOCATION,
87 PROP_SHOW_IN_SEARCH,
88 PROP_SEND_LOCATION,
89 PROP_REPLACE_DATE_POSTED,
90 PROP_IS_VIDEO,
91 PROP_FILESIZE,
92 PROP_DATETIME,
93 PROP_PHOTOSETS,
94 PROP_GROUPS
95 };
96
97 /* Prototypes */
98
99 static gboolean _tag_is_set (FrogrPicture *self, const gchar *tag);
100 static void _add_tags_to_tags_list (FrogrPicture *self,
101 const gchar *tags_string);
102 static void _update_tags_string (FrogrPicture *self);
103
104 static JsonNode *_serialize_list (GSList *objects_list, GType g_type);
105 static gboolean _deserialize_list (JsonNode *node, GValue *value, GType g_type);
106
107 static JsonNode *_serialize_property (JsonSerializable *serializable,
108 const gchar *name,
109 const GValue *value,
110 GParamSpec *pspec);
111 static gboolean _deserialize_property (JsonSerializable *serializable,
112 const gchar *name,
113 GValue *value,
114 GParamSpec *pspec,
115 JsonNode *node);
116 /* Private API */
117
118 static gboolean
_tag_is_set(FrogrPicture * self,const gchar * tag)119 _tag_is_set (FrogrPicture *self, const gchar *tag)
120 {
121 GSList *item;
122 gboolean tag_found = FALSE;
123
124 for (item = self->tags_list; item; item = g_slist_next (item))
125 {
126 if (g_str_equal ((gchar *)item->data, tag))
127 {
128 tag_found = TRUE;
129 break;
130 }
131 }
132
133 return tag_found;
134 }
135
136 static void
_add_tags_to_tags_list(FrogrPicture * self,const gchar * tags_string)137 _add_tags_to_tags_list (FrogrPicture *self,
138 const gchar *tags_string)
139 {
140 /* Check if valid data is passed to the function */
141 if (tags_string != NULL)
142 {
143 g_autofree gchar *stripped_tags = g_strstrip (g_strdup (tags_string));
144 if (!g_str_equal (stripped_tags, ""))
145 {
146 g_auto(GStrv) tags_array = NULL;
147 gchar *tag;
148 gint i;
149
150 /* Now iterate over every token, adding it to the list */
151 tags_array = g_strsplit (stripped_tags, TAGS_DELIMITER, -1);
152 for (i = 0; tags_array[i]; i++)
153 {
154 /* add stripped tag if not already set*/
155 tag = g_strstrip(g_strdup (tags_array[i]));
156 if (!g_str_equal (tag, "") && !_tag_is_set (self, tag))
157 self->tags_list = g_slist_append (self->tags_list, tag);
158 }
159 }
160
161 /* Update internal tags string */
162 _update_tags_string (self);
163 }
164 }
165
166 static void
_update_tags_string(FrogrPicture * self)167 _update_tags_string (FrogrPicture *self)
168 {
169 /* Reset previous tags string */
170 g_free (self->tags_string);
171 self->tags_string = NULL;
172
173 /* Set the tags_string value, if needed */
174 if (self->tags_list != NULL)
175 {
176 GSList *item = NULL;
177 gchar *new_str = NULL;
178 gchar *tmp_str = NULL;
179
180 /* Init new_string to first item */
181 new_str = g_strdup ((gchar *)self->tags_list->data);
182
183 /* Continue with the remaining tags */
184 for (item = g_slist_next (self->tags_list);
185 item != NULL;
186 item = g_slist_next (item))
187 {
188 tmp_str = g_strconcat (new_str, " ", (gchar *)item->data, NULL);
189 g_free (new_str);
190
191 /* Update pointer */
192 new_str = tmp_str;
193 }
194
195 /* Store final result */
196 self->tags_string = new_str;
197 }
198 }
199
200 static JsonNode *
_serialize_list(GSList * objects_list,GType g_type)201 _serialize_list (GSList *objects_list, GType g_type)
202 {
203 JsonArray *json_array = NULL;
204 JsonNode *list_node = NULL;
205 GObject *object = NULL;
206 GSList *item = NULL;
207 const gchar *id = NULL;
208
209 json_array = json_array_new ();
210 for (item = objects_list; item; item = g_slist_next (item))
211 {
212 /* We just serialize the ID of the group / set */
213 object = G_OBJECT (item->data);
214 if (g_type == FROGR_TYPE_PHOTOSET)
215 {
216 id = frogr_photoset_get_id (FROGR_PHOTOSET (object));
217 if (!id)
218 id = frogr_photoset_get_local_id (FROGR_PHOTOSET (object));
219 }
220 else if (g_type == FROGR_TYPE_GROUP)
221 id = frogr_group_get_id (FROGR_GROUP (object));
222
223 if (id)
224 json_array_add_string_element (json_array, id);
225 }
226
227 list_node = json_node_new(JSON_NODE_ARRAY);
228 json_node_set_array (list_node, json_array);
229
230 return list_node;
231 }
232
233 static gboolean
_deserialize_list(JsonNode * node,GValue * value,GType g_type)234 _deserialize_list (JsonNode *node, GValue *value, GType g_type)
235 {
236 FrogrModel *model = NULL;
237 JsonArray *array = NULL;
238 GSList *objects = NULL;
239 GObject *object = NULL;
240 guint n_elements = 0;
241 guint i = 0;
242
243 g_return_val_if_fail (node != NULL, FALSE);
244 g_return_val_if_fail (JSON_NODE_HOLDS_ARRAY (node), FALSE);
245
246 array = json_node_get_array (node);
247 n_elements = json_array_get_length (array);
248 if (!n_elements)
249 return TRUE;
250
251 /* We need to get the groups and sets from the model by ID, so it's
252 mandatory to have imported those first for this to work OK */
253 model = frogr_controller_get_model (frogr_controller_get_instance ());
254 for (i = 0; i < n_elements; i++)
255 {
256 const gchar *id = NULL;
257 id = json_array_get_string_element (array, i);
258 if (g_type == FROGR_TYPE_PHOTOSET)
259 object = G_OBJECT (frogr_model_get_photoset_by_id (model, id));
260 if (g_type == FROGR_TYPE_GROUP)
261 object = G_OBJECT (frogr_model_get_group_by_id (model, id));
262
263 if (object)
264 objects = g_slist_prepend (objects, g_object_ref (object));
265 }
266 g_value_set_pointer (value, g_slist_reverse (objects));
267
268 return TRUE;
269 }
270
271 static JsonNode *
_serialize_property(JsonSerializable * serializable,const gchar * name,const GValue * value,GParamSpec * pspec)272 _serialize_property (JsonSerializable *serializable,
273 const gchar *name,
274 const GValue *value,
275 GParamSpec *pspec)
276 {
277 FrogrPicture *self = NULL;
278 JsonNode *json_node = NULL;
279
280 g_return_val_if_fail (FROGR_IS_PICTURE (serializable), FALSE);
281
282 self = FROGR_PICTURE (serializable);
283 if (g_str_equal (name, "photosets"))
284 json_node = _serialize_list (self->photosets, FROGR_TYPE_PHOTOSET);
285 else if (g_str_equal (name, "groups"))
286 json_node = _serialize_list (self->groups, FROGR_TYPE_GROUP);
287 else
288 {
289 /* Default serialization here */
290 JsonSerializableIface *iface = NULL;
291 iface = g_type_default_interface_peek (JSON_TYPE_SERIALIZABLE);
292 json_node = iface->serialize_property (serializable,
293 name,
294 value,
295 pspec);
296 }
297
298 return json_node; /* NULL indicates default deserializer */
299 }
300
301 static gboolean
_deserialize_property(JsonSerializable * serializable,const gchar * name,GValue * value,GParamSpec * pspec,JsonNode * node)302 _deserialize_property (JsonSerializable *serializable,
303 const gchar *name,
304 GValue *value,
305 GParamSpec *pspec,
306 JsonNode *node)
307 {
308 gboolean result = FALSE;
309
310 g_return_val_if_fail (node != NULL, FALSE);
311
312 if (g_str_equal (name, "photosets"))
313 result = _deserialize_list (node, value, FROGR_TYPE_PHOTOSET);
314 else if (g_str_equal (name, "groups"))
315 result = _deserialize_list (node, value, FROGR_TYPE_GROUP);
316 else
317 {
318 /* Default deserialization */
319 JsonSerializableIface *iface = NULL;
320
321 iface = g_type_default_interface_peek (JSON_TYPE_SERIALIZABLE);
322 result = iface->deserialize_property (serializable,
323 name,
324 value,
325 pspec,
326 node);
327 }
328
329 return result;
330 }
331
332 static void
json_serializable_init(JsonSerializableIface * iface)333 json_serializable_init (JsonSerializableIface *iface)
334 {
335 iface->serialize_property = _serialize_property;
336 iface->deserialize_property = _deserialize_property;
337 }
338
339 static void
_frogr_picture_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)340 _frogr_picture_set_property (GObject *object,
341 guint prop_id,
342 const GValue *value,
343 GParamSpec *pspec)
344 {
345 FrogrPicture *self = FROGR_PICTURE (object);
346
347 switch (prop_id)
348 {
349 case PROP_ID:
350 frogr_picture_set_id (self, g_value_get_string (value));
351 break;
352 case PROP_FILEURI:
353 self->fileuri = g_value_dup_string (value);
354 break;
355 case PROP_TITLE:
356 frogr_picture_set_title (self, g_value_get_string (value));
357 break;
358 case PROP_DESCRIPTION:
359 frogr_picture_set_description (self, g_value_get_string (value));
360 break;
361 case PROP_TAGS_STRING:
362 frogr_picture_set_tags (self, g_value_get_string (value));
363 break;
364 case PROP_IS_PUBLIC:
365 frogr_picture_set_public (self, g_value_get_boolean (value));
366 break;
367 case PROP_IS_FAMILY:
368 frogr_picture_set_family (self, g_value_get_boolean (value));
369 break;
370 case PROP_IS_FRIEND:
371 frogr_picture_set_friend (self, g_value_get_boolean (value));
372 break;
373 case PROP_SAFETY_LEVEL:
374 frogr_picture_set_safety_level (self, g_value_get_int (value));
375 break;
376 case PROP_CONTENT_TYPE:
377 frogr_picture_set_content_type (self, g_value_get_int (value));
378 break;
379 case PROP_LICENSE:
380 frogr_picture_set_license (self, g_value_get_int (value));
381 break;
382 case PROP_LOCATION:
383 frogr_picture_set_location (self, FROGR_LOCATION (g_value_get_object (value)));
384 break;
385 case PROP_SHOW_IN_SEARCH:
386 frogr_picture_set_show_in_search (self, g_value_get_boolean (value));
387 break;
388 case PROP_SEND_LOCATION:
389 frogr_picture_set_send_location (self, g_value_get_boolean (value));
390 break;
391 case PROP_REPLACE_DATE_POSTED:
392 frogr_picture_set_replace_date_posted (self, g_value_get_boolean (value));
393 break;
394 case PROP_IS_VIDEO:
395 self->is_video = g_value_get_boolean (value);
396 break;
397 case PROP_FILESIZE:
398 frogr_picture_set_filesize (self, g_value_get_uint (value));
399 break;
400 case PROP_DATETIME:
401 frogr_picture_set_datetime (self, g_value_get_string (value));
402 break;
403 case PROP_PHOTOSETS:
404 frogr_picture_set_photosets (self, (GSList *) g_value_get_pointer (value));
405 break;
406 case PROP_GROUPS:
407 frogr_picture_set_groups (self, (GSList *) g_value_get_pointer (value));
408 break;
409 default:
410 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
411 break;
412 }
413 }
414
415 static void
_frogr_picture_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)416 _frogr_picture_get_property (GObject *object,
417 guint prop_id,
418 GValue *value,
419 GParamSpec *pspec)
420 {
421 FrogrPicture *self = FROGR_PICTURE (object);
422
423 switch (prop_id)
424 {
425 case PROP_ID:
426 g_value_set_string (value, self->id);
427 break;
428 case PROP_FILEURI:
429 g_value_set_string (value, self->fileuri);
430 break;
431 case PROP_TITLE:
432 g_value_set_string (value, self->title);
433 break;
434 case PROP_DESCRIPTION:
435 g_value_set_string (value, self->description);
436 break;
437 case PROP_TAGS_STRING:
438 g_value_set_string (value, self->tags_string);
439 break;
440 case PROP_IS_PUBLIC:
441 g_value_set_boolean (value, self->is_public);
442 break;
443 case PROP_IS_FAMILY:
444 g_value_set_boolean (value, self->is_family);
445 break;
446 case PROP_IS_FRIEND:
447 g_value_set_boolean (value, self->is_friend);
448 break;
449 case PROP_SAFETY_LEVEL:
450 g_value_set_int (value, self->safety_level);
451 break;
452 case PROP_CONTENT_TYPE:
453 g_value_set_int (value, self->content_type);
454 break;
455 case PROP_LICENSE:
456 g_value_set_int (value, self->license);
457 break;
458 case PROP_LOCATION:
459 g_value_set_object (value, self->location);
460 break;
461 case PROP_SHOW_IN_SEARCH:
462 g_value_set_boolean (value, self->show_in_search);
463 break;
464 case PROP_SEND_LOCATION:
465 g_value_set_boolean (value, self->send_location);
466 break;
467 case PROP_REPLACE_DATE_POSTED:
468 g_value_set_boolean (value, self->replace_date_posted);
469 break;
470 case PROP_IS_VIDEO:
471 g_value_set_boolean (value, self->is_video);
472 break;
473 case PROP_FILESIZE:
474 g_value_set_uint (value, self->filesize);
475 break;
476 case PROP_DATETIME:
477 g_value_set_string (value, self->datetime);
478 break;
479 case PROP_PHOTOSETS:
480 g_value_set_pointer (value, self->photosets);
481 break;
482 case PROP_GROUPS:
483 g_value_set_pointer (value, self->groups);
484 break;
485 default:
486 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
487 break;
488 }
489 }
490
491 static void
_frogr_picture_dispose(GObject * object)492 _frogr_picture_dispose (GObject* object)
493 {
494 FrogrPicture *self = FROGR_PICTURE (object);
495
496 g_clear_object (&self->pixbuf);
497 g_clear_object (&self->location);
498
499 if (self->photosets)
500 {
501 g_slist_free_full (self->photosets, g_object_unref);
502 self->photosets = NULL;
503 }
504
505 if (self->groups)
506 {
507 g_slist_free_full (self->groups, g_object_unref);
508 self->groups = NULL;
509 }
510
511 /* call super class */
512 G_OBJECT_CLASS (frogr_picture_parent_class)->dispose(object);
513 }
514
515 static void
_frogr_picture_finalize(GObject * object)516 _frogr_picture_finalize (GObject* object)
517 {
518 FrogrPicture *self = FROGR_PICTURE (object);
519
520 /* free strings */
521 g_free (self->id);
522 g_free (self->fileuri);
523 g_free (self->title);
524 g_free (self->description);
525 g_free (self->tags_string);
526 g_free (self->datetime);
527
528 /* free GSList of tags */
529 g_slist_free_full (self->tags_list, g_free);
530
531 /* call super class */
532 G_OBJECT_CLASS (frogr_picture_parent_class)->finalize(object);
533 }
534
535 static void
frogr_picture_class_init(FrogrPictureClass * klass)536 frogr_picture_class_init(FrogrPictureClass *klass)
537 {
538 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
539
540 /* GtkObject signals */
541 obj_class->set_property = _frogr_picture_set_property;
542 obj_class->get_property = _frogr_picture_get_property;
543 obj_class->dispose = _frogr_picture_dispose;
544 obj_class->finalize = _frogr_picture_finalize;
545
546 /* Install properties */
547 g_object_class_install_property (obj_class,
548 PROP_ID,
549 g_param_spec_string ("id",
550 "id",
551 "Photo ID from flickr",
552 NULL,
553 G_PARAM_READWRITE));
554
555 g_object_class_install_property (obj_class,
556 PROP_FILEURI,
557 g_param_spec_string ("fileuri",
558 "fileuri",
559 "Full fileuri at disk "
560 "for the picture",
561 NULL,
562 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
563 g_object_class_install_property (obj_class,
564 PROP_TITLE,
565 g_param_spec_string ("title",
566 "title",
567 "Picture's title",
568 NULL,
569 G_PARAM_READWRITE));
570 g_object_class_install_property (obj_class,
571 PROP_DESCRIPTION,
572 g_param_spec_string ("description",
573 "description",
574 "Picture's description",
575 NULL,
576 G_PARAM_READWRITE));
577 g_object_class_install_property (obj_class,
578 PROP_TAGS_STRING,
579 g_param_spec_string ("tags-string",
580 "tags-string",
581 "List of tags separated"
582 " with blanks between",
583 NULL,
584 G_PARAM_READWRITE));
585 g_object_class_install_property (obj_class,
586 PROP_IS_PUBLIC,
587 g_param_spec_boolean ("is-public",
588 "is-public",
589 "Whether the picture "
590 "is public or not",
591 FALSE,
592 G_PARAM_READWRITE));
593 g_object_class_install_property (obj_class,
594 PROP_IS_FAMILY,
595 g_param_spec_boolean ("is-family",
596 "is-family",
597 "Whether the picture "
598 "will be seen by "
599 "relatives or not",
600 FALSE,
601 G_PARAM_READWRITE));
602 g_object_class_install_property (obj_class,
603 PROP_IS_FRIEND,
604 g_param_spec_boolean ("is-friend",
605 "is-friend",
606 "Whether the picture "
607 "will be seen by "
608 "friends or not",
609 FALSE,
610 G_PARAM_READWRITE));
611 g_object_class_install_property (obj_class,
612 PROP_SAFETY_LEVEL,
613 g_param_spec_int ("safety-level",
614 "safety-level",
615 "Safety level for this picture "
616 "(safe/moderate/restricted)",
617 FSP_SAFETY_LEVEL_NONE,
618 FSP_SAFETY_LEVEL_RESTRICTED,
619 FSP_SAFETY_LEVEL_SAFE,
620 G_PARAM_READWRITE));
621 g_object_class_install_property (obj_class,
622 PROP_CONTENT_TYPE,
623 g_param_spec_int ("content-type",
624 "content-type",
625 "Content type for this picture "
626 "(photo/screenshot/other)",
627 FSP_CONTENT_TYPE_NONE,
628 FSP_CONTENT_TYPE_OTHER,
629 FSP_CONTENT_TYPE_PHOTO,
630 G_PARAM_READWRITE));
631 g_object_class_install_property (obj_class,
632 PROP_LICENSE,
633 g_param_spec_int ("license",
634 "license",
635 "License for this picture",
636 FSP_LICENSE_NONE,
637 FSP_LICENSE_ND,
638 FSP_LICENSE_NONE,
639 G_PARAM_READWRITE));
640 g_object_class_install_property (obj_class,
641 PROP_LOCATION,
642 g_param_spec_object ("location",
643 "location",
644 "Location for this picture",
645 FROGR_TYPE_LOCATION,
646 G_PARAM_READWRITE));
647 g_object_class_install_property (obj_class,
648 PROP_SHOW_IN_SEARCH,
649 g_param_spec_boolean ("show-in-search",
650 "show-in-search",
651 "Whether to show the "
652 "picture in global "
653 "search results",
654 FALSE,
655 G_PARAM_READWRITE));
656 g_object_class_install_property (obj_class,
657 PROP_SEND_LOCATION,
658 g_param_spec_boolean ("send-location",
659 "send-location",
660 "Whether to send the location "
661 "to flickr, if available",
662 FALSE,
663 G_PARAM_READWRITE));
664 g_object_class_install_property (obj_class,
665 PROP_REPLACE_DATE_POSTED,
666 g_param_spec_boolean ("replace-date-posted",
667 "replace-date-posted",
668 "Whether to replace the 'date posted'"
669 "with 'date taken', after uploading",
670 FALSE,
671 G_PARAM_READWRITE));
672 g_object_class_install_property (obj_class,
673 PROP_FILESIZE,
674 g_param_spec_uint ("filesize",
675 "filesize",
676 "Filesize in KB for the file",
677 0,
678 G_MAXUINT,
679 0,
680 G_PARAM_READWRITE));
681 g_object_class_install_property (obj_class,
682 PROP_IS_VIDEO,
683 g_param_spec_boolean ("is-video",
684 "is-video",
685 "Whether FrogrPicture represents a video",
686 FALSE,
687 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
688 g_object_class_install_property (obj_class,
689 PROP_DATETIME,
690 g_param_spec_string ("datetime",
691 "datetime",
692 "Date and time string for the file",
693 NULL,
694 G_PARAM_READWRITE));
695 g_object_class_install_property (obj_class,
696 PROP_PHOTOSETS,
697 g_param_spec_pointer ("photosets",
698 "photosets",
699 "List of sets the picture is in",
700 G_PARAM_READWRITE));
701 g_object_class_install_property (obj_class,
702 PROP_GROUPS,
703 g_param_spec_pointer ("groups",
704 "groups",
705 "List of groups the picture is in",
706 G_PARAM_READWRITE));
707 }
708
709 static void
frogr_picture_init(FrogrPicture * self)710 frogr_picture_init (FrogrPicture *self)
711 {
712 /* Default values */
713 self->id = NULL;
714 self->fileuri = NULL;
715 self->title = NULL;
716 self->description = NULL;
717 self->tags_string = NULL;
718 self->tags_list = NULL;
719
720 self->is_public = FALSE;
721 self->is_friend = FALSE;
722 self->is_family = FALSE;
723
724 self->safety_level = FSP_SAFETY_LEVEL_SAFE;
725 self->content_type = FSP_CONTENT_TYPE_PHOTO;
726 self->license = FSP_LICENSE_NONE;
727 self->location = NULL;
728
729 self->show_in_search = TRUE;
730 self->send_location = FALSE;
731 self->replace_date_posted = FALSE;
732
733 self->is_video = FALSE;
734
735 self->filesize = 0;
736 self->datetime = NULL;
737
738 self->photosets = NULL;
739 self->groups = NULL;
740
741 self->pixbuf = NULL;
742 }
743
744
745 /* Public API */
746
747 FrogrPicture *
frogr_picture_new(const gchar * fileuri,const gchar * title,gboolean public,gboolean family,gboolean friend,gboolean is_video)748 frogr_picture_new (const gchar *fileuri,
749 const gchar *title,
750 gboolean public,
751 gboolean family,
752 gboolean friend,
753 gboolean is_video)
754 {
755 g_return_val_if_fail (fileuri, NULL);
756 g_return_val_if_fail (title, NULL);
757
758 return FROGR_PICTURE (g_object_new(FROGR_TYPE_PICTURE,
759 "fileuri", fileuri,
760 "title", title,
761 "is-public", public,
762 "is-family", family,
763 "is-friend", friend,
764 "is-video", is_video,
765 NULL));
766 }
767
768
769 /* Data Managing functions */
770
771 const gchar *
frogr_picture_get_id(FrogrPicture * self)772 frogr_picture_get_id (FrogrPicture *self)
773 {
774 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
775 return (const gchar *)self->id;
776 }
777
778 void
frogr_picture_set_id(FrogrPicture * self,const gchar * id)779 frogr_picture_set_id (FrogrPicture *self,
780 const gchar *id)
781 {
782 g_return_if_fail(FROGR_IS_PICTURE(self));
783 g_free (self->id);
784 self->id = g_strdup (id);
785 }
786
787 const gchar *
frogr_picture_get_fileuri(FrogrPicture * self)788 frogr_picture_get_fileuri (FrogrPicture *self)
789 {
790 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
791 return (const gchar *)self->fileuri;
792 }
793
794 const gchar *
frogr_picture_get_title(FrogrPicture * self)795 frogr_picture_get_title (FrogrPicture *self)
796 {
797 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
798 return (const gchar *)self->title;
799 }
800
801 void
frogr_picture_set_title(FrogrPicture * self,const gchar * title)802 frogr_picture_set_title (FrogrPicture *self,
803 const gchar *title)
804 {
805 g_return_if_fail(FROGR_IS_PICTURE(self));
806 g_return_if_fail(title != NULL);
807
808 g_free (self->title);
809 self->title = g_strdup (title);
810 }
811
812 const gchar *
frogr_picture_get_description(FrogrPicture * self)813 frogr_picture_get_description (FrogrPicture *self)
814 {
815 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
816 return (const gchar *)self->description;
817 }
818
819 void
frogr_picture_set_description(FrogrPicture * self,const gchar * description)820 frogr_picture_set_description (FrogrPicture *self,
821 const gchar *description)
822 {
823 g_return_if_fail(FROGR_IS_PICTURE(self));
824 g_free (self->description);
825 self->description = g_strdup (description);
826 }
827
828 const GSList *
frogr_picture_get_tags_list(FrogrPicture * self)829 frogr_picture_get_tags_list (FrogrPicture *self)
830 {
831 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
832 return self->tags_list;
833 }
834
835 const gchar *
frogr_picture_get_tags(FrogrPicture * self)836 frogr_picture_get_tags (FrogrPicture *self)
837 {
838 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
839 return self->tags_string;
840 }
841
842 void
frogr_picture_set_tags(FrogrPicture * self,const gchar * tags_string)843 frogr_picture_set_tags (FrogrPicture *self, const gchar *tags_string)
844 {
845 g_return_if_fail(FROGR_IS_PICTURE(self));
846
847 /* First remove all the previous tags list */
848 g_slist_free_full (self->tags_list, g_free);
849 self->tags_list = NULL;
850
851 /* Add to internal tags_list */
852 _add_tags_to_tags_list (self, tags_string);
853 }
854
855 void
frogr_picture_add_tags(FrogrPicture * self,const gchar * tags_string)856 frogr_picture_add_tags (FrogrPicture *self, const gchar *tags_string)
857 {
858 g_return_if_fail(FROGR_IS_PICTURE(self));
859
860 _add_tags_to_tags_list (self, tags_string);
861 }
862
863 void
frogr_picture_remove_tags(FrogrPicture * self)864 frogr_picture_remove_tags (FrogrPicture *self)
865 {
866 g_return_if_fail(FROGR_IS_PICTURE(self));
867
868 frogr_picture_set_tags (self, NULL);
869 }
870
871 gboolean
frogr_picture_is_public(FrogrPicture * self)872 frogr_picture_is_public (FrogrPicture *self)
873 {
874 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
875 return self->is_public;
876 }
877
878 void
frogr_picture_set_public(FrogrPicture * self,gboolean public)879 frogr_picture_set_public (FrogrPicture *self,
880 gboolean public)
881 {
882 g_return_if_fail(FROGR_IS_PICTURE(self));
883 self->is_public = public;
884 }
885
886 gboolean
frogr_picture_is_friend(FrogrPicture * self)887 frogr_picture_is_friend (FrogrPicture *self)
888 {
889 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
890 return self->is_friend;
891 }
892
893 void
frogr_picture_set_friend(FrogrPicture * self,gboolean friend)894 frogr_picture_set_friend (FrogrPicture *self,
895 gboolean friend)
896 {
897 g_return_if_fail(FROGR_IS_PICTURE(self));
898 self->is_friend = friend;
899 }
900
901 gboolean
frogr_picture_is_family(FrogrPicture * self)902 frogr_picture_is_family (FrogrPicture *self)
903 {
904 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
905 return self->is_family;
906 }
907
908 void
frogr_picture_set_family(FrogrPicture * self,gboolean family)909 frogr_picture_set_family (FrogrPicture *self,
910 gboolean family)
911 {
912 g_return_if_fail(FROGR_IS_PICTURE(self));
913 self->is_family = family;
914 }
915
916 FspSafetyLevel
frogr_picture_get_safety_level(FrogrPicture * self)917 frogr_picture_get_safety_level (FrogrPicture *self)
918 {
919 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
920 return self->safety_level;
921 }
922
923 void
frogr_picture_set_safety_level(FrogrPicture * self,FspSafetyLevel safety_level)924 frogr_picture_set_safety_level (FrogrPicture *self,
925 FspSafetyLevel safety_level)
926 {
927 g_return_if_fail(FROGR_IS_PICTURE(self));
928 self->safety_level = safety_level;
929 }
930
931 FspContentType
frogr_picture_get_content_type(FrogrPicture * self)932 frogr_picture_get_content_type (FrogrPicture *self)
933 {
934 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
935 return self->content_type;
936 }
937
938 void
frogr_picture_set_content_type(FrogrPicture * self,FspContentType content_type)939 frogr_picture_set_content_type (FrogrPicture *self,
940 FspContentType content_type)
941 {
942 g_return_if_fail(FROGR_IS_PICTURE(self));
943 self->content_type = content_type;
944 }
945
946 FspLicense
frogr_picture_get_license(FrogrPicture * self)947 frogr_picture_get_license (FrogrPicture *self)
948 {
949 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
950 return self->license;
951 }
952
953 void
frogr_picture_set_license(FrogrPicture * self,FspLicense license)954 frogr_picture_set_license (FrogrPicture *self, FspLicense license)
955 {
956 g_return_if_fail(FROGR_IS_PICTURE(self));
957 self->license = license;
958 }
959
960 FrogrLocation *
frogr_picture_get_location(FrogrPicture * self)961 frogr_picture_get_location (FrogrPicture *self)
962 {
963 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
964 return self->location;
965 }
966
967 void
frogr_picture_set_location(FrogrPicture * self,FrogrLocation * location)968 frogr_picture_set_location (FrogrPicture *self, FrogrLocation *location)
969 {
970 g_return_if_fail(FROGR_IS_PICTURE(self));
971
972 if (self->location)
973 g_object_unref (self->location);
974
975 self->location = FROGR_IS_LOCATION (location) ? g_object_ref (location) : NULL;
976 }
977
978 gboolean
frogr_picture_show_in_search(FrogrPicture * self)979 frogr_picture_show_in_search (FrogrPicture *self)
980 {
981 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
982 return self->show_in_search;
983 }
984
985 void
frogr_picture_set_show_in_search(FrogrPicture * self,gboolean show_in_search)986 frogr_picture_set_show_in_search (FrogrPicture *self,
987 gboolean show_in_search)
988 {
989 g_return_if_fail(FROGR_IS_PICTURE(self));
990 self->show_in_search = show_in_search;
991 }
992
993 gboolean
frogr_picture_send_location(FrogrPicture * self)994 frogr_picture_send_location (FrogrPicture *self)
995 {
996 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
997 return self->send_location;
998 }
999
1000 void
frogr_picture_set_send_location(FrogrPicture * self,gboolean send_location)1001 frogr_picture_set_send_location (FrogrPicture *self, gboolean send_location)
1002 {
1003 g_return_if_fail(FROGR_IS_PICTURE(self));
1004 self->send_location = send_location;
1005 }
1006
1007 gboolean
frogr_picture_replace_date_posted(FrogrPicture * self)1008 frogr_picture_replace_date_posted (FrogrPicture *self)
1009 {
1010 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
1011 return self->replace_date_posted;
1012 }
1013
1014 void
frogr_picture_set_replace_date_posted(FrogrPicture * self,gboolean replace_date_posted)1015 frogr_picture_set_replace_date_posted (FrogrPicture *self, gboolean replace_date_posted)
1016 {
1017 g_return_if_fail(FROGR_IS_PICTURE(self));
1018 self->replace_date_posted = replace_date_posted;
1019 }
1020
1021 GdkPixbuf *
frogr_picture_get_pixbuf(FrogrPicture * self)1022 frogr_picture_get_pixbuf (FrogrPicture *self)
1023 {
1024 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
1025 return self->pixbuf;
1026 }
1027
1028 void
frogr_picture_set_pixbuf(FrogrPicture * self,GdkPixbuf * pixbuf)1029 frogr_picture_set_pixbuf (FrogrPicture *self,
1030 GdkPixbuf *pixbuf)
1031 {
1032 g_return_if_fail(FROGR_IS_PICTURE(self));
1033
1034 if (self->pixbuf)
1035 g_object_unref (self->pixbuf);
1036
1037 self->pixbuf = GDK_IS_PIXBUF (pixbuf) ? g_object_ref (pixbuf) : NULL;
1038 }
1039
frogr_picture_is_video(FrogrPicture * self)1040 gboolean frogr_picture_is_video (FrogrPicture *self)
1041 {
1042 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
1043 return self->is_video;
1044 }
1045
frogr_picture_get_filesize(FrogrPicture * self)1046 guint frogr_picture_get_filesize (FrogrPicture *self)
1047 {
1048 g_return_val_if_fail(FROGR_IS_PICTURE(self), 0);
1049 return self->filesize;
1050 }
1051
frogr_picture_set_filesize(FrogrPicture * self,guint filesize)1052 void frogr_picture_set_filesize (FrogrPicture *self, guint filesize)
1053 {
1054 g_return_if_fail(FROGR_IS_PICTURE(self));
1055 self->filesize = filesize;
1056 }
1057
1058 void
frogr_picture_set_datetime(FrogrPicture * self,const gchar * datetime)1059 frogr_picture_set_datetime (FrogrPicture *self, const gchar *datetime)
1060 {
1061 g_return_if_fail(FROGR_IS_PICTURE(self));
1062 g_free (self->datetime);
1063 self->datetime = g_strdup (datetime);
1064 }
1065
1066 const gchar *
frogr_picture_get_datetime(FrogrPicture * self)1067 frogr_picture_get_datetime (FrogrPicture *self)
1068 {
1069 g_return_val_if_fail(FROGR_IS_PICTURE(self), 0);
1070 return (const gchar *)self->datetime;
1071 }
1072
1073 GSList *
frogr_picture_get_photosets(FrogrPicture * self)1074 frogr_picture_get_photosets (FrogrPicture *self)
1075 {
1076 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
1077 return self->photosets;
1078 }
1079
1080 void
frogr_picture_set_photosets(FrogrPicture * self,GSList * photosets)1081 frogr_picture_set_photosets (FrogrPicture *self, GSList *photosets)
1082 {
1083 g_return_if_fail(FROGR_IS_PICTURE(self));
1084
1085 /* First remove all the previous sets list */
1086 g_slist_free_full (self->photosets, g_object_unref);
1087 self->photosets = photosets;
1088 }
1089
1090 void
frogr_picture_add_photoset(FrogrPicture * self,FrogrPhotoSet * photoset)1091 frogr_picture_add_photoset (FrogrPicture *self, FrogrPhotoSet *photoset)
1092 {
1093 g_return_if_fail(FROGR_IS_PICTURE(self));
1094 g_return_if_fail(FROGR_IS_PHOTOSET(photoset));
1095
1096 /* Do not add the same set twice */
1097 if (frogr_picture_in_photoset (self, photoset))
1098 return;
1099
1100 self->photosets = g_slist_append (self->photosets, g_object_ref (photoset));
1101 }
1102
1103 void
frogr_picture_remove_photosets(FrogrPicture * self)1104 frogr_picture_remove_photosets (FrogrPicture *self)
1105 {
1106 g_return_if_fail(FROGR_IS_PICTURE(self));
1107
1108 frogr_picture_set_photosets (self, NULL);
1109 }
1110
1111 gboolean
frogr_picture_in_photoset(FrogrPicture * self,FrogrPhotoSet * photoset)1112 frogr_picture_in_photoset (FrogrPicture *self, FrogrPhotoSet *photoset)
1113 {
1114 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
1115
1116 if (g_slist_find_custom (self->photosets, photoset,
1117 (GCompareFunc)frogr_photoset_compare))
1118 return TRUE;
1119
1120 return FALSE;
1121 }
1122
1123 GSList *
frogr_picture_get_groups(FrogrPicture * self)1124 frogr_picture_get_groups (FrogrPicture *self)
1125 {
1126 g_return_val_if_fail(FROGR_IS_PICTURE(self), NULL);
1127 return self->groups;
1128 }
1129
1130 void
frogr_picture_set_groups(FrogrPicture * self,GSList * groups)1131 frogr_picture_set_groups (FrogrPicture *self, GSList *groups)
1132 {
1133 g_return_if_fail(FROGR_IS_PICTURE(self));
1134
1135 /* First remove all the previous groups list */
1136 g_slist_free_full (self->groups, g_object_unref);
1137 self->groups = groups;
1138 }
1139
1140 void
frogr_picture_add_group(FrogrPicture * self,FrogrGroup * group)1141 frogr_picture_add_group (FrogrPicture *self, FrogrGroup *group)
1142 {
1143 g_return_if_fail(FROGR_IS_PICTURE(self));
1144 g_return_if_fail(FROGR_IS_GROUP(group));
1145
1146 /* Do not add the same set twice */
1147 if (frogr_picture_in_group (self, group))
1148 return;
1149
1150 self->groups = g_slist_append (self->groups, g_object_ref (group));
1151 }
1152
1153 void
frogr_picture_remove_groups(FrogrPicture * self)1154 frogr_picture_remove_groups (FrogrPicture *self)
1155 {
1156 g_return_if_fail(FROGR_IS_PICTURE(self));
1157
1158 frogr_picture_set_groups (self, NULL);
1159 }
1160
1161 gboolean
frogr_picture_in_group(FrogrPicture * self,FrogrGroup * group)1162 frogr_picture_in_group (FrogrPicture *self, FrogrGroup *group)
1163 {
1164 g_return_val_if_fail(FROGR_IS_PICTURE(self), FALSE);
1165
1166 if (g_slist_find_custom (self->groups, group,
1167 (GCompareFunc)frogr_group_compare))
1168 return TRUE;
1169
1170 return FALSE;
1171 }
1172
1173 gint
frogr_picture_compare_by_property(FrogrPicture * self,FrogrPicture * other,const gchar * property_name)1174 frogr_picture_compare_by_property (FrogrPicture *self, FrogrPicture *other,
1175 const gchar *property_name)
1176 {
1177 GParamSpec *pspec1 = NULL;
1178 GParamSpec *pspec2 = NULL;
1179 GValue value1 = { 0 };
1180 GValue value2 = { 0 };
1181 gint result = 0;
1182
1183 g_return_val_if_fail (FROGR_IS_PICTURE (self), 1);
1184 g_return_val_if_fail (FROGR_IS_PICTURE (other), -1);
1185
1186 pspec1 = g_object_class_find_property (G_OBJECT_GET_CLASS (self), property_name);
1187 pspec2 = g_object_class_find_property (G_OBJECT_GET_CLASS (other), property_name);
1188
1189 /* They should be the same! */
1190 if (pspec1->value_type != pspec2->value_type)
1191 return 0;
1192
1193 g_value_init (&value1, pspec1->value_type);
1194 g_value_init (&value2, pspec1->value_type);
1195
1196 g_object_get_property (G_OBJECT (self), property_name, &value1);
1197 g_object_get_property (G_OBJECT (other), property_name, &value2);
1198
1199 if (G_VALUE_HOLDS_BOOLEAN (&value1))
1200 result = g_value_get_boolean (&value1) - g_value_get_boolean (&value2);
1201 else if (G_VALUE_HOLDS_INT (&value1))
1202 result = g_value_get_int (&value1) - g_value_get_int (&value2);
1203 else if (G_VALUE_HOLDS_UINT (&value1))
1204 result = g_value_get_uint (&value1) - g_value_get_uint (&value2);
1205 else if (G_VALUE_HOLDS_LONG (&value1))
1206 result = g_value_get_long (&value1) - g_value_get_long (&value2);
1207 else if (G_VALUE_HOLDS_STRING (&value1))
1208 {
1209 const gchar *str1 = NULL;
1210 const gchar *str2 = NULL;
1211 g_autofree gchar *str1_cf = NULL;
1212 g_autofree gchar *str2_cf = NULL;
1213
1214 /* Comparison of strings require some additional work to take
1215 into account the different rules for each locale */
1216 str1 = g_value_get_string (&value1);
1217 str2 = g_value_get_string (&value2);
1218
1219 str1_cf = g_utf8_casefold (str1 ? str1 : "", -1);
1220 str2_cf = g_utf8_casefold (str2 ? str2 : "", -1);
1221
1222 result = g_utf8_collate (str1_cf, str2_cf);
1223 }
1224 else
1225 g_warning ("Unsupported type for property used for sorting");
1226
1227 g_value_unset (&value1);
1228 g_value_unset (&value2);
1229
1230 return result;
1231 }
1232