1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2010-2012 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <json-glib/json-glib.h>
26 #include <gthumb.h>
27 #include "facebook-photo.h"
28
29
30 static void facebook_photo_json_serializable_interface_init (JsonSerializableIface *iface);
31
32
33 G_DEFINE_TYPE_WITH_CODE (FacebookPhoto,
34 facebook_photo,
35 G_TYPE_OBJECT,
36 G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE,
37 facebook_photo_json_serializable_interface_init))
38
39
40 enum {
41 PROP_0,
42 PROP_ID,
43 PROP_PICTURE,
44 PROP_SOURCE,
45 PROP_WIDTH,
46 PROP_HEIGHT,
47 PROP_LINK,
48 PROP_CREATED_TIME,
49 PROP_UPDATED_TIME,
50 PROP_IMAGES
51 };
52
53
54 /* -- facebook_image -- */
55
56
57 static FacebookImage *
facebook_image_new(void)58 facebook_image_new (void)
59 {
60 FacebookImage *image;
61
62 image = g_new (FacebookImage, 1);
63 image->source = NULL;
64 image->width = 0;
65 image->height = 0;
66
67 return image;
68 }
69
70
71 static FacebookImage *
facebook_image_copy(FacebookImage * source)72 facebook_image_copy (FacebookImage *source)
73 {
74 FacebookImage *dest;
75
76 dest = facebook_image_new ();
77 _g_str_set (&dest->source, source->source);
78 dest->width = source->width;
79 dest->height = source->height;
80
81 return dest;
82 }
83
84
85 static void
facebook_image_free(FacebookImage * image)86 facebook_image_free (FacebookImage *image)
87 {
88 g_free (image->source);
89 g_free (image);
90 }
91
92
93 /* -- facebook_image_list -- */
94
95
96 #define FACEBOOK_TYPE_IMAGE_LIST (facebook_image_list_get_type ())
97
98
99 static GList *
facebook_image_list_copy(GList * source)100 facebook_image_list_copy (GList *source)
101 {
102 return g_list_copy_deep (source, (GCopyFunc) facebook_image_copy, NULL);
103 }
104
105
106 static void
facebook_image_list_free(GList * images)107 facebook_image_list_free (GList *images)
108 {
109 g_list_foreach (images, (GFunc) facebook_image_free, NULL);
110 g_list_free (images);
111 }
112
113
114 GType facebook_image_list_get_type (void);
115
G_DEFINE_BOXED_TYPE(GList,facebook_image_list,facebook_image_list_copy,facebook_image_list_free)116 G_DEFINE_BOXED_TYPE (GList, facebook_image_list, facebook_image_list_copy, facebook_image_list_free)
117
118
119 /* -- facebook_photo -- */
120
121
122 static void
123 facebook_photo_set_property (GObject *object,
124 guint property_id,
125 const GValue *value,
126 GParamSpec *pspec)
127 {
128 FacebookPhoto *self;
129
130 self = FACEBOOK_PHOTO (object);
131
132 switch (property_id) {
133 case PROP_ID:
134 _g_str_set (&self->id, g_value_get_string (value));
135 break;
136 case PROP_PICTURE:
137 _g_str_set (&self->picture, g_value_get_string (value));
138 break;
139 case PROP_SOURCE:
140 _g_str_set (&self->source, g_value_get_string (value));
141 break;
142 case PROP_WIDTH:
143 self->width = g_value_get_int (value);
144 break;
145 case PROP_HEIGHT:
146 self->height = g_value_get_int (value);
147 break;
148 case PROP_LINK:
149 _g_str_set (&self->link, g_value_get_string (value));
150 break;
151 case PROP_CREATED_TIME:
152 gth_datetime_free (self->created_time);
153 self->created_time = g_value_dup_boxed (value);
154 break;
155 case PROP_UPDATED_TIME:
156 gth_datetime_free (self->updated_time);
157 self->updated_time = g_value_dup_boxed (value);
158 break;
159 case PROP_IMAGES:
160 facebook_image_list_free (self->images);
161 self->images = g_value_dup_boxed (value);
162 break;
163 default:
164 break;
165 }
166 }
167
168
169 static void
facebook_photo_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)170 facebook_photo_get_property (GObject *object,
171 guint property_id,
172 GValue *value,
173 GParamSpec *pspec)
174 {
175 FacebookPhoto *self;
176
177 self = FACEBOOK_PHOTO (object);
178
179 switch (property_id) {
180 case PROP_ID:
181 g_value_set_string (value, self->id);
182 break;
183 case PROP_PICTURE:
184 g_value_set_string (value, self->picture);
185 break;
186 case PROP_SOURCE:
187 g_value_set_string (value, self->source);
188 break;
189 case PROP_WIDTH:
190 g_value_set_int (value, self->width);
191 break;
192 case PROP_HEIGHT:
193 g_value_set_int (value, self->height);
194 break;
195 case PROP_LINK:
196 g_value_set_string (value, self->link);
197 break;
198 case PROP_CREATED_TIME:
199 g_value_set_boxed (value, self->created_time);
200 break;
201 case PROP_UPDATED_TIME:
202 g_value_set_boxed (value, self->updated_time);
203 break;
204 case PROP_IMAGES:
205 g_value_set_boxed (value, self->images);
206 break;
207 default:
208 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
209 break;
210 }
211 }
212
213
214 static void
facebook_photo_finalize(GObject * obj)215 facebook_photo_finalize (GObject *obj)
216 {
217 FacebookPhoto *self;
218
219 self = FACEBOOK_PHOTO (obj);
220
221 g_free (self->id);
222 g_free (self->picture);
223 g_free (self->source);
224 g_free (self->link);
225 gth_datetime_free (self->created_time);
226 gth_datetime_free (self->updated_time);
227 facebook_image_list_free (self->images);
228
229 G_OBJECT_CLASS (facebook_photo_parent_class)->finalize (obj);
230 }
231
232
233 static void
facebook_photo_class_init(FacebookPhotoClass * klass)234 facebook_photo_class_init (FacebookPhotoClass *klass)
235 {
236 GObjectClass *object_class;
237
238 object_class = G_OBJECT_CLASS (klass);
239 object_class->finalize = facebook_photo_finalize;
240 object_class->set_property = facebook_photo_set_property;
241 object_class->get_property = facebook_photo_get_property;
242
243 /* properties */
244
245 g_object_class_install_property (object_class,
246 PROP_ID,
247 g_param_spec_string ("id",
248 "ID",
249 "",
250 NULL,
251 G_PARAM_READWRITE));
252 g_object_class_install_property (object_class,
253 PROP_PICTURE,
254 g_param_spec_string ("picture",
255 "Picture",
256 "",
257 NULL,
258 G_PARAM_READWRITE));
259 g_object_class_install_property (object_class,
260 PROP_SOURCE,
261 g_param_spec_string ("source",
262 "Source",
263 "",
264 NULL,
265 G_PARAM_READWRITE));
266 g_object_class_install_property (object_class,
267 PROP_WIDTH,
268 g_param_spec_int ("width",
269 "Width",
270 "",
271 0,
272 G_MAXINT,
273 0,
274 G_PARAM_READWRITE));
275 g_object_class_install_property (object_class,
276 PROP_HEIGHT,
277 g_param_spec_int ("height",
278 "Height",
279 "",
280 0,
281 G_MAXINT,
282 0,
283 G_PARAM_READWRITE));
284 g_object_class_install_property (object_class,
285 PROP_LINK,
286 g_param_spec_string ("link",
287 "Link",
288 "",
289 NULL,
290 G_PARAM_READWRITE));
291 g_object_class_install_property (object_class,
292 PROP_CREATED_TIME,
293 g_param_spec_boxed ("created-time",
294 "Created time",
295 "",
296 GTH_TYPE_DATETIME,
297 G_PARAM_READWRITE));
298 g_object_class_install_property (object_class,
299 PROP_UPDATED_TIME,
300 g_param_spec_boxed ("updated-time",
301 "Updated time",
302 "",
303 GTH_TYPE_DATETIME,
304 G_PARAM_READWRITE));
305 g_object_class_install_property (object_class,
306 PROP_IMAGES,
307 g_param_spec_boxed ("images",
308 "Images",
309 "",
310 FACEBOOK_TYPE_IMAGE_LIST,
311 G_PARAM_READWRITE));
312 }
313
314
315 static gboolean
facebook_photo_deserialize_property(JsonSerializable * serializable,const gchar * property_name,GValue * value,GParamSpec * pspec,JsonNode * property_node)316 facebook_photo_deserialize_property (JsonSerializable *serializable,
317 const gchar *property_name,
318 GValue *value,
319 GParamSpec *pspec,
320 JsonNode *property_node)
321 {
322 FacebookPhoto *self = FACEBOOK_PHOTO (serializable);
323
324 if (pspec->value_type == GTH_TYPE_DATETIME) {
325 GTimeVal timeval;
326
327 if (g_time_val_from_iso8601 (json_node_get_string (property_node), &timeval)) {
328 GthDateTime *datetime;
329
330 datetime = gth_datetime_new ();
331 gth_datetime_from_timeval (datetime, &timeval);
332 g_object_set (self, property_name, datetime, NULL);
333
334 gth_datetime_free (datetime);
335
336 return TRUE;
337 }
338
339 return FALSE;
340 }
341
342 if (pspec->value_type == FACEBOOK_TYPE_IMAGE_LIST) {
343 GList *images = NULL;
344 JsonArray *array;
345 int i;
346
347 array = json_node_get_array (property_node);
348 for (i = 0; i < json_array_get_length (array); i++) {
349 JsonObject *image_obj;
350
351 image_obj = json_array_get_object_element (array, i);
352 if (image_obj != NULL) {
353 FacebookImage *image;
354
355 image = facebook_image_new ();
356 _g_str_set (&image->source, json_object_get_string_member (image_obj, "source"));
357 image->width = json_object_get_int_member (image_obj, "width");
358 image->height = json_object_get_int_member (image_obj, "height");
359
360 images = g_list_prepend (images, image);
361 }
362 }
363
364 images = g_list_reverse (images);
365 g_object_set (self, property_name, images, NULL);
366
367 facebook_image_list_free (images);
368
369 return TRUE;
370 }
371
372 return json_serializable_default_deserialize_property (serializable,
373 property_name,
374 value,
375 pspec,
376 property_node);
377 }
378
379
380 static void
facebook_photo_json_serializable_interface_init(JsonSerializableIface * iface)381 facebook_photo_json_serializable_interface_init (JsonSerializableIface *iface)
382 {
383 iface->deserialize_property = facebook_photo_deserialize_property;
384 }
385
386
387 static void
facebook_photo_init(FacebookPhoto * self)388 facebook_photo_init (FacebookPhoto *self)
389 {
390 self->id = NULL;
391 self->picture = NULL;
392 self->source = NULL;
393 self->width = 0;
394 self->height = 0;
395 self->link = NULL;
396 self->created_time = NULL;
397 self->updated_time = NULL;
398 self->images = NULL;
399 }
400
401
402 FacebookPhoto *
facebook_photo_new(void)403 facebook_photo_new (void)
404 {
405 return g_object_new (FACEBOOK_TYPE_PHOTO, NULL);
406 }
407
408
409 const char *
facebook_photo_get_original_url(FacebookPhoto * photo)410 facebook_photo_get_original_url (FacebookPhoto *photo)
411 {
412 char *url;
413 GList *scan;
414 glong max_size;
415
416 url = photo->source;
417 max_size = photo->width * photo->height;
418
419 for (scan = photo->images; scan; scan = scan->next) {
420 FacebookImage *image = scan->data;
421 glong image_size;
422
423 image_size = image->width * image->height;
424 if (image_size > max_size) {
425 max_size = image_size;
426 url = image->source;
427 }
428 }
429
430 return url;
431 }
432
433
434 const char *
facebook_photo_get_thumbnail_url(FacebookPhoto * photo,int requested_size)435 facebook_photo_get_thumbnail_url (FacebookPhoto *photo,
436 int requested_size)
437 {
438 char *url;
439 GList *scan;
440 glong min_delta;
441
442 url = photo->picture;
443 requested_size = requested_size * requested_size;
444 min_delta = 0;
445
446 for (scan = photo->images; scan; scan = scan->next) {
447 FacebookImage *image = scan->data;
448 glong image_delta;
449
450 image_delta = labs ((image->width * image->height) - requested_size);
451 if ((scan == photo->images) || (image_delta < min_delta)) {
452 min_delta = image_delta;
453 url = image->source;
454 }
455 }
456
457 return url;
458 }
459