1 /*
2 * frogr-file-loader.c -- Asynchronous file loader in frogr
3 *
4 * Copyright (C) 2009-2017 Mario Sanchez Prada
5 * Authors: Mario Sanchez Prada <msanchez@gnome.org>
6 *
7 * Some parts of this file were based on source code from tracker,
8 * licensed under the GNU Lesser General Public License Version 2.1
9 * (Copyright 2009, Nokia Corp.)
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 3 of the GNU General Public
13 * License as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>
22 *
23 * Parts of this file based on code from GTK+, licensed as GPL version 2
24 * or later (Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.)
25 */
26
27 #include "frogr-file-loader.h"
28
29 #include "frogr-config.h"
30 #include "frogr-controller.h"
31 #include "frogr-global-defs.h"
32 #include "frogr-location.h"
33 #include "frogr-main-view.h"
34 #include "frogr-picture.h"
35 #include "frogr-util.h"
36
37 #include <config.h>
38 #include <libexif/exif-byte-order.h>
39 #include <libexif/exif-data.h>
40 #include <libexif/exif-entry.h>
41 #include <libexif/exif-format.h>
42 #include <libexif/exif-loader.h>
43 #include <libexif/exif-tag.h>
44 #include <glib/gi18n.h>
45 #include <gio/gio.h>
46
47
48 typedef enum {
49 LOADING_MODE_FROM_URIS,
50 LOADING_MODE_FROM_PICTURES,
51 } LoadingMode;
52
53
54 struct _FrogrFileLoader
55 {
56 GObject parent;
57
58 FrogrController *controller;
59 FrogrMainView *mainview;
60
61 LoadingMode loading_mode;
62
63 GSList *file_uris; /* For URI-based loading */
64 GSList *current_uri;
65
66 GSList *pictures; /* For loading the pixbufs in the pictures */
67 GSList *current_picture;
68
69 guint index;
70 guint n_files;
71
72 gulong max_picture_size;
73 gulong max_video_size;
74 gboolean keep_file_extensions;
75 gboolean import_tags;
76 gboolean public_visibility;
77 gboolean family_visibility;
78 gboolean friend_visibility;
79 gboolean show_in_search;
80 gboolean send_location;
81 gboolean replace_date_posted;
82 FspLicense license;
83 FspSafetyLevel safety_level;
84 FspContentType content_type;
85 };
86
87 G_DEFINE_TYPE (FrogrFileLoader, frogr_file_loader, G_TYPE_OBJECT)
88
89 /* Signals */
90 enum {
91 FILE_LOADED,
92 FILES_LOADED,
93 N_SIGNALS
94 };
95
96 static guint signals[N_SIGNALS] = { 0 };
97
98 /* Prototypes */
99
100 static void _update_status_and_progress (FrogrFileLoader *self);
101 static void _advance_to_next_file (FrogrFileLoader *self);
102 static void _load_current_file (FrogrFileLoader *self);
103 static void _load_current_file_cb (GObject *object,
104 GAsyncResult *res,
105 gpointer data);
106
107 static gboolean _is_video_file (GFile *file);
108 static GdkPixbuf *_try_get_pixbuf_for_image (FrogrFileLoader *self,
109 GFile *file,
110 const gchar *contents,
111 gsize length);
112 static GdkPixbuf *_try_get_pixbuf_for_video (FrogrFileLoader *self,
113 GFile *file,
114 const gchar *contents,
115 gsize length);
116
117 static gboolean get_gps_coordinate (ExifData *exif,
118 ExifTag tag,
119 ExifTag reftag,
120 gdouble *coordinate);
121 static FrogrLocation *get_location_from_exif (ExifData *exif_data);
122 static FrogrPicture* _create_new_picture (FrogrFileLoader *self, GFile *file, GdkPixbuf *pixbuf, gboolean is_video);
123 static void _update_picture_with_exif_data (FrogrFileLoader *self,
124 const gchar *contents,
125 gsize length,
126 FrogrPicture *picture);
127 static gboolean _check_filesize_limits (FrogrFileLoader *self, FrogrPicture *picture);
128
129 static gchar *remove_spaces_from_keyword (const gchar *keyword);
130 static gchar *import_tags_from_xmp_keywords (const char *buffer, size_t len);
131 static void _finish_task_and_self_destruct (FrogrFileLoader *self);
132
133 /* Private API */
134
135 static void
_update_status_and_progress(FrogrFileLoader * self)136 _update_status_and_progress (FrogrFileLoader *self)
137 {
138 g_autofree gchar *status_text = NULL;
139
140 /* Update progress */
141 if (self->current_uri || self->current_picture)
142 status_text = g_strdup_printf (_("Loading files %d / %d"),
143 self->index, self->n_files);
144
145 frogr_main_view_set_status_text (self->mainview, status_text);
146 }
147
148 static void
_advance_to_next_file(FrogrFileLoader * self)149 _advance_to_next_file (FrogrFileLoader *self)
150 {
151 /* update internal status and check the next file */
152 if (self->loading_mode == LOADING_MODE_FROM_PICTURES)
153 self->current_picture = g_slist_next (self->current_picture);
154 else
155 self->current_uri = g_slist_next (self->current_uri);
156
157 self->index++;
158 }
159
160 static void
_load_current_file(FrogrFileLoader * self)161 _load_current_file (FrogrFileLoader *self)
162 {
163 const gchar *file_uri = NULL;
164
165 /* Get the uri for the file first */
166 if (self->loading_mode == LOADING_MODE_FROM_URIS && self->current_uri)
167 file_uri = (const gchar *)self->current_uri->data;
168 else if (self->current_picture)
169 {
170 FrogrPicture *picture = FROGR_PICTURE (self->current_picture->data);
171 file_uri = frogr_picture_get_fileuri (picture);
172 }
173
174 if (file_uri)
175 {
176 GFile *gfile = NULL;
177 g_autoptr(GFileInfo) file_info = NULL;
178 gboolean valid_mime = TRUE;
179
180 /* Get file info (from this point on, use (file_info != NULL) as
181 a reliable way to know whether the file exists or not */
182 gfile = g_file_new_for_uri (file_uri);
183 file_info = g_file_query_info (gfile,
184 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
185 G_FILE_QUERY_INFO_NONE,
186 NULL,
187 NULL);
188 const gchar *mime_type;
189 gint i;
190
191 /* This can be NULL (e.g wrong parameter in the command line) */
192 if (file_info)
193 {
194 /* Check mimetype */
195 mime_type = g_file_info_get_content_type (file_info);
196 valid_mime = FALSE;
197
198 if (mime_type)
199 {
200 const gchar * const *supported_mimetypes = frogr_util_get_supported_mimetypes ();
201 for (i = 0; supported_mimetypes[i]; i++)
202 {
203 if (g_str_equal (supported_mimetypes[i], mime_type))
204 {
205 valid_mime = TRUE;
206 break;
207 }
208 }
209 DEBUG ("Mime detected: %s", mime_type);
210 }
211 }
212
213 /* Asynchronously load the file if mime is valid */
214 if (file_info && valid_mime)
215 {
216 g_file_load_contents_async (gfile,
217 NULL,
218 _load_current_file_cb,
219 self);
220 DEBUG ("Adding file %s", file_uri);
221 }
222 else
223 {
224 _advance_to_next_file (self);
225 _load_current_file (self);
226 }
227 }
228 else
229 {
230 /* Update status and progress and finish */
231 _update_status_and_progress (self);
232 _finish_task_and_self_destruct (self);
233 }
234 }
235
236 static void
_load_current_file_cb(GObject * object,GAsyncResult * res,gpointer data)237 _load_current_file_cb (GObject *object,
238 GAsyncResult *res,
239 gpointer data)
240 {
241 FrogrFileLoader *self = NULL;
242 FrogrPicture *picture = NULL;
243 g_autoptr(GFile) file = NULL;
244 g_autoptr(GError) error = NULL;
245 g_autofree gchar *contents = NULL;
246 gsize length = 0;
247 gboolean keep_going = FALSE;
248
249 self = FROGR_FILE_LOADER (data);
250
251 file = G_FILE (object);
252 if (g_file_load_contents_finish (file, res, &contents, &length, NULL, &error))
253 {
254 g_autoptr(GdkPixbuf) pixbuf = NULL;
255 gboolean is_video = FALSE;
256
257 /* Load the pixbuf for the video or the image */
258 is_video = _is_video_file (file);
259 if (is_video)
260 pixbuf = _try_get_pixbuf_for_video (self, file, contents, length);
261 else
262 pixbuf = _try_get_pixbuf_for_image (self, file, contents, length);
263
264 if (pixbuf)
265 {
266 if (self->loading_mode == LOADING_MODE_FROM_PICTURES)
267 {
268 /* Just update the picture if we are not loading from URIs */
269 picture = FROGR_PICTURE (self->current_picture->data);
270 frogr_picture_set_pixbuf (picture, pixbuf);
271 }
272 else
273 {
274 picture = _create_new_picture (self, file, pixbuf, is_video);
275 _update_picture_with_exif_data (self, contents, length, picture);
276 }
277 }
278 }
279 else
280 {
281 /* Not able to load contents */
282 g_autofree gchar *file_name = g_file_get_basename (file);
283 g_warning ("Not able to read contents from %s: %s",
284 file_name,
285 error->message);
286 }
287
288 /* Update internal status */
289 _advance_to_next_file (self);
290
291 /* Update status and progress */
292 _update_status_and_progress (self);
293
294 /* We might not have a file loaded (e.g. unsupported format) */
295 if (picture)
296 {
297 /* Check if we must interrupt the process */
298 keep_going = _check_filesize_limits (self, picture);
299 if (keep_going)
300 g_signal_emit (self, signals[FILE_LOADED], 0, picture);
301
302 /* We only unref the picture if it was created here */
303 if (self->loading_mode != LOADING_MODE_FROM_PICTURES)
304 g_object_unref (picture);
305 }
306
307 /* Go for the next file, if needed */
308 if (keep_going)
309 _load_current_file (self);
310 else
311 _finish_task_and_self_destruct (self);
312 }
313
314 static gboolean
_is_video_file(GFile * file)315 _is_video_file (GFile *file)
316 {
317 GFileInfo* file_info = NULL;
318 GError *error = NULL;
319 gboolean is_video = FALSE;
320
321 file_info = g_file_query_info (file,
322 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
323 G_FILE_QUERY_INFO_NONE,
324 NULL, &error);
325 if (!error)
326 {
327 const gchar *mime_type = NULL;
328 mime_type = g_file_info_get_content_type (file_info);
329 is_video = !g_str_has_prefix (mime_type, "image");
330 }
331 else
332 {
333 g_warning ("Not able to read file information: %s", error->message);
334 g_error_free (error);
335 }
336
337 return is_video;
338 }
339
340 static GdkPixbuf *
_try_get_pixbuf_for_image(FrogrFileLoader * self,GFile * file,const gchar * contents,gsize length)341 _try_get_pixbuf_for_image (FrogrFileLoader *self,
342 GFile *file,
343 const gchar *contents,
344 gsize length)
345 {
346 GdkPixbuf *pixbuf = NULL;
347 g_autofree gchar *path = NULL;
348 g_autoptr(GError) error = NULL;
349
350 path = g_file_get_path (file);
351 pixbuf = frogr_util_get_pixbuf_from_image_contents ((const guchar *)contents, length,
352 IV_THUMB_WIDTH, IV_THUMB_HEIGHT, path, &error);
353 if (error)
354 {
355 g_autofree gchar *file_name = NULL;
356 g_autofree gchar *msg = NULL;
357
358 file_name = g_file_get_basename (file);
359 msg = g_strdup_printf (_("Unable to load picture %s:\n%s"), file_name, error->message);
360 frogr_util_show_error_dialog (GTK_WINDOW (self->mainview), msg);
361 }
362
363 return pixbuf;
364 }
365
366 static GdkPixbuf *
_try_get_pixbuf_for_video(FrogrFileLoader * self,GFile * file,const gchar * contents,gsize length)367 _try_get_pixbuf_for_video (FrogrFileLoader *self,
368 GFile *file,
369 const gchar *contents,
370 gsize length)
371 {
372 GdkPixbuf *pixbuf = NULL;
373 g_autoptr(GError) error = NULL;
374
375 pixbuf = frogr_util_get_pixbuf_for_video_file (file, IV_THUMB_WIDTH, IV_THUMB_HEIGHT, &error);
376 if (!pixbuf)
377 {
378 g_autofree gchar *file_name = NULL;
379 g_autofree gchar *msg = NULL;
380
381 /* FIXME: We should integrate with gstreamer's codec
382 installer instead of just showing an error message to
383 the user, but this is "good enough" for now. */
384 file_name = g_file_get_basename (file);
385 msg = g_strdup_printf (_("Unable to load video %s\n"
386 "Please check that you have the right codec installed"), file_name);
387 frogr_util_show_error_dialog (GTK_WINDOW (self->mainview), msg);
388 }
389
390 return pixbuf;
391 }
392
393 /* This function was taken from tracker, licensed under the GNU Lesser
394 * General Public License Version 2.1 (Copyright 2009, Nokia Corp.) */
395 static gboolean
get_gps_coordinate(ExifData * exif,ExifTag tag,ExifTag reftag,gdouble * coordinate)396 get_gps_coordinate (ExifData *exif,
397 ExifTag tag,
398 ExifTag reftag,
399 gdouble *coordinate)
400 {
401 ExifEntry *entry = exif_data_get_entry (exif, tag);
402 ExifEntry *refentry = exif_data_get_entry (exif, reftag);
403
404 g_return_val_if_fail (coordinate != NULL, FALSE);
405
406 if (entry && refentry)
407 {
408 ExifByteOrder order;
409 ExifRational c1,c2,c3;
410 gfloat f;
411 gchar ref;
412
413 order = exif_data_get_byte_order (exif);
414 c1 = exif_get_rational (entry->data, order);
415 c2 = exif_get_rational (entry->data+8, order);
416 c3 = exif_get_rational (entry->data+16, order);
417 ref = refentry->data[0];
418
419 /* Avoid ridiculous values */
420 if (c1.denominator == 0 ||
421 c2.denominator == 0 ||
422 c3.denominator == 0)
423 {
424 return FALSE;
425 }
426
427 f = (double)c1.numerator/c1.denominator+
428 (double)c2.numerator/(c2.denominator*60)+
429 (double)c3.numerator/(c3.denominator*60*60);
430
431 if (ref == 'S' || ref == 'W')
432 {
433 f = -1 * f;
434 }
435
436 *coordinate = f;
437 return TRUE;
438 }
439
440 return FALSE;
441 }
442
443 static FrogrLocation *
get_location_from_exif(ExifData * exif_data)444 get_location_from_exif (ExifData *exif_data)
445 {
446 FrogrLocation *location = NULL;
447 gdouble latitude;
448 gdouble longitude;
449 gboolean has_latitude;
450
451 if (exif_data)
452 {
453 has_latitude = get_gps_coordinate (exif_data, EXIF_TAG_GPS_LATITUDE,
454 EXIF_TAG_GPS_LATITUDE_REF, &latitude);
455
456 /* We need both latitude and longitude */
457 if (has_latitude && get_gps_coordinate (exif_data, EXIF_TAG_GPS_LONGITUDE,
458 EXIF_TAG_GPS_LONGITUDE_REF, &longitude))
459 {
460 location = frogr_location_new (latitude, longitude);
461 }
462 }
463
464 return location;
465 }
466
467 static FrogrPicture*
_create_new_picture(FrogrFileLoader * self,GFile * file,GdkPixbuf * pixbuf,gboolean is_video)468 _create_new_picture (FrogrFileLoader *self, GFile *file, GdkPixbuf *pixbuf, gboolean is_video)
469 {
470 FrogrPicture *picture = NULL;
471 g_autoptr(GFileInfo) file_info = NULL;
472 g_autofree gchar *file_name = NULL;
473 g_autofree gchar *file_uri = NULL;
474 guint64 filesize = 0;
475 g_autoptr(GError) error = NULL;
476
477 /* Gather needed information */
478 file_info = g_file_query_info (file,
479 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
480 "," G_FILE_ATTRIBUTE_STANDARD_SIZE,
481 G_FILE_QUERY_INFO_NONE,
482 NULL, &error);
483 if (!error)
484 {
485 file_name = g_strdup (g_file_info_get_display_name (file_info));
486 filesize = g_file_info_get_size (file_info);
487 }
488 else
489 {
490 g_warning ("Not able to read file information: %s", error->message);
491
492 /* Fallback if g_file_query_info() failed */
493 file_name = g_file_get_basename (file);
494 }
495
496 if (!self->keep_file_extensions)
497 {
498 gchar *extension_dot = NULL;
499
500 /* Remove extension if present */
501 extension_dot = g_strrstr (file_name, ".");
502 if (extension_dot)
503 *extension_dot = '\0';
504 }
505
506 /* Build the FrogrPicture */
507 file_uri = g_file_get_uri (file);
508 picture = frogr_picture_new (file_uri,
509 file_name,
510 self->public_visibility,
511 self->family_visibility,
512 self->friend_visibility,
513 is_video);
514
515 frogr_picture_set_show_in_search (picture, self->show_in_search);
516 frogr_picture_set_send_location (picture, self->send_location);
517 frogr_picture_set_replace_date_posted (picture, self->replace_date_posted);
518 frogr_picture_set_license (picture, self->license);
519 frogr_picture_set_content_type (picture, self->content_type);
520 frogr_picture_set_safety_level (picture, self->safety_level);
521 frogr_picture_set_pixbuf (picture, pixbuf);
522
523 /* FrogrPicture stores the size in KB */
524 frogr_picture_set_filesize (picture, filesize / 1024);
525
526 return picture;
527 }
528
529 static void
_update_picture_with_exif_data(FrogrFileLoader * self,const gchar * contents,gsize length,FrogrPicture * picture)530 _update_picture_with_exif_data (FrogrFileLoader *self,
531 const gchar *contents,
532 gsize length,
533 FrogrPicture *picture)
534 {
535 ExifLoader *exif_loader = NULL;
536 ExifData *exif_data = NULL;
537
538 /* Set date and time from exif data, if present */
539 exif_loader = exif_loader_new();
540 exif_loader_write (exif_loader, (unsigned char *) contents, length);
541
542 exif_data = exif_loader_get_data (exif_loader);
543 if (exif_data)
544 {
545 g_autoptr(FrogrLocation) location = NULL;
546 ExifEntry *exif_entry = NULL;
547
548 /* Date and time for picture taken */
549 exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_DATE_TIME_ORIGINAL);
550 if (exif_entry)
551 {
552 if (exif_entry->format == EXIF_FORMAT_ASCII)
553 {
554 g_autofree gchar *value = g_new0 (char, 20);
555 exif_entry_get_value (exif_entry, value, 20);
556
557 frogr_picture_set_datetime (picture, value);
558 }
559 else
560 g_warning ("Found DateTime exif tag of invalid type");
561 }
562
563 /* Import tags from XMP metadata, if required */
564 if (self->import_tags)
565 {
566 g_autofree gchar *imported_tags = NULL;
567
568 imported_tags = import_tags_from_xmp_keywords (contents, length);
569 if (imported_tags)
570 frogr_picture_set_tags (picture, imported_tags);
571 }
572
573 /* GPS coordinates */
574 location = get_location_from_exif (exif_data);
575 if (location != NULL)
576 {
577 /* frogr_picture_set_location takes ownership of location */
578 frogr_picture_set_location (picture, location);
579 }
580 exif_data_unref (exif_data);
581 }
582
583 exif_loader_unref (exif_loader);
584 }
585
586 static gboolean
_check_filesize_limits(FrogrFileLoader * self,FrogrPicture * picture)587 _check_filesize_limits (FrogrFileLoader *self, FrogrPicture *picture)
588 {
589 gulong picture_filesize = 0;
590 gulong max_filesize = 0;
591 gboolean keep_going = TRUE;
592
593 max_filesize = frogr_picture_is_video (picture) ? self->max_video_size : self->max_picture_size;
594 picture_filesize = frogr_picture_get_filesize (picture);
595
596 if (picture_filesize > max_filesize)
597 {
598 g_autofree gchar *msg = NULL;
599
600 /* First %s is the title of the picture (filename of the file by
601 default). Second %s is the max allowed size for a picture to be
602 uploaded to flickr (different for free and PRO accounts). */
603 msg = g_strdup_printf (_("Can't load file %s:\nSize of file is bigger "
604 "than the maximum allowed for this account (%s)"),
605 frogr_picture_get_title (picture),
606 frogr_util_get_datasize_string (max_filesize));
607
608 frogr_util_show_error_dialog (GTK_WINDOW (self->mainview), msg);
609
610 keep_going = FALSE;
611 }
612
613 return keep_going;
614 }
615
616 static gchar *
remove_spaces_from_keyword(const gchar * keyword)617 remove_spaces_from_keyword (const gchar *keyword)
618 {
619 gchar *new_keyword = NULL;
620
621 if (keyword)
622 {
623 int i = 0;
624 int j = 0;
625
626 new_keyword = g_new0 (gchar, strlen(keyword) + 1);
627 for (i = 0; keyword[i] != '\0'; i++)
628 {
629 if (keyword[i] != ' ')
630 new_keyword[j++] = keyword[i];
631 }
632 new_keyword[j] = '\0';
633 }
634
635 return new_keyword;
636 }
637
638 static gchar *
import_tags_from_xmp_keywords(const char * buffer,size_t len)639 import_tags_from_xmp_keywords (const char *buffer, size_t len)
640 {
641 const gchar *keywords_start = NULL;
642 const gchar *keywords_end = NULL;
643 g_autofree gchar *keywords_string = NULL;
644 gchar *start = NULL;
645 gchar *end = NULL;
646 gchar *result = NULL;
647 int i;
648
649 /* Look for the beginning of the XMP data interesting for as if
650 present, that is, the keywords (aka the 'tags') */
651 for (i = 0; i < len && !keywords_start; i++)
652 {
653 if (buffer[i] != '<')
654 continue;
655
656 if (!strncmp (&buffer[i], "<dc:subject", 11))
657 keywords_start = &buffer[i];
658 }
659
660 /* Find the end of the interesting XMP data, if found */
661 if (!keywords_start)
662 return NULL;
663
664 keywords_end = g_strrstr (keywords_start, "</dc:subject>");
665 if (!keywords_end)
666 return NULL;
667
668 keywords_string = g_strndup (keywords_start, keywords_end - keywords_start);
669
670 /* Remove extra not-needed stuff in the string */
671 start = g_strstr_len (keywords_string, -1, "<rdf:li");
672 end = g_strrstr (keywords_string, "</rdf:li>");
673 if (start && end)
674 {
675 g_auto(GStrv) keywords = NULL;
676 gchar *keyword = NULL;
677
678 /* Get an array of strings with all the keywords */
679 end[0] = '\0';
680 keywords = g_regex_split_simple ("<.?rdf:li(!>)*>", start,
681 G_REGEX_DOTALL | G_REGEX_RAW, 0);
682
683 /* Remove spaces to normalize to flickr tags */
684 for (i = 0; keywords[i]; i++)
685 {
686 keyword = keywords[i];
687 keywords[i] = remove_spaces_from_keyword (keyword);
688 g_free (keyword);
689 }
690
691 result = g_strjoinv (" ", keywords);
692 }
693
694 return result;
695 }
696
697 static void
_finish_task_and_self_destruct(FrogrFileLoader * self)698 _finish_task_and_self_destruct (FrogrFileLoader *self)
699 {
700 g_signal_emit (self, signals[FILES_LOADED], 0);
701 g_object_unref (self);
702 }
703
704 static void
_frogr_file_loader_dispose(GObject * object)705 _frogr_file_loader_dispose (GObject* object)
706 {
707 FrogrFileLoader *self = FROGR_FILE_LOADER (object);
708 g_clear_object (&self->mainview);
709 g_clear_object (&self->controller);
710 G_OBJECT_CLASS (frogr_file_loader_parent_class)->dispose(object);
711 }
712
713 static void
_frogr_file_loader_finalize(GObject * object)714 _frogr_file_loader_finalize (GObject* object)
715 {
716 FrogrFileLoader *self = FROGR_FILE_LOADER (object);
717
718 /* Free */
719 g_slist_free_full (self->file_uris, g_free);
720
721 G_OBJECT_CLASS (frogr_file_loader_parent_class)->finalize(object);
722 }
723
724 static void
frogr_file_loader_class_init(FrogrFileLoaderClass * klass)725 frogr_file_loader_class_init(FrogrFileLoaderClass *klass)
726 {
727 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
728
729 obj_class->dispose = _frogr_file_loader_dispose;
730 obj_class->finalize = _frogr_file_loader_finalize;
731
732 signals[FILE_LOADED] =
733 g_signal_new ("file-loaded",
734 G_OBJECT_CLASS_TYPE (klass),
735 G_SIGNAL_RUN_FIRST,
736 0, NULL, NULL,
737 g_cclosure_marshal_VOID__OBJECT,
738 G_TYPE_NONE, 1, FROGR_TYPE_PICTURE);
739
740 signals[FILES_LOADED] =
741 g_signal_new ("files-loaded",
742 G_OBJECT_CLASS_TYPE (klass),
743 G_SIGNAL_RUN_FIRST,
744 0, NULL, NULL,
745 g_cclosure_marshal_VOID__VOID,
746 G_TYPE_NONE, 0);
747 }
748
749 static void
frogr_file_loader_init(FrogrFileLoader * self)750 frogr_file_loader_init (FrogrFileLoader *self)
751 {
752 FrogrConfig *config = frogr_config_get_instance ();
753
754 /* Init private data */
755
756 /* We need the controller to get the main window */
757 self->controller = g_object_ref (frogr_controller_get_instance ());
758 self->mainview = g_object_ref (frogr_controller_get_main_view (self->controller));
759
760 /* Initialize values from frogr configuration */
761 self->max_picture_size = G_MAXULONG;
762 self->max_video_size = G_MAXULONG;
763 self->keep_file_extensions = frogr_config_get_keep_file_extensions (config);
764 self->import_tags = frogr_config_get_import_tags_from_metadata (config);
765 self->public_visibility = frogr_config_get_default_public (config);
766 self->family_visibility = frogr_config_get_default_family (config);
767 self->friend_visibility = frogr_config_get_default_friend (config);
768 self->show_in_search = frogr_config_get_default_show_in_search (config);
769 self->send_location = frogr_config_get_default_send_geolocation_data (config);
770 self->replace_date_posted = frogr_config_get_default_replace_date_posted (config);
771 self->license = frogr_config_get_default_license (config);
772 self->safety_level = frogr_config_get_default_safety_level (config);
773 self->content_type = frogr_config_get_default_content_type (config);
774
775 /* Init the rest of private data */
776 self->file_uris = NULL;
777 self->pictures = NULL;
778 self->current_uri = NULL;
779 self->current_picture = NULL;
780 self->index = -1;
781 self->n_files = 0;
782 }
783
784 /* Public API */
785
786 FrogrFileLoader *
frogr_file_loader_new_from_uris(GSList * file_uris,gulong max_picture_size,gulong max_video_size)787 frogr_file_loader_new_from_uris (GSList *file_uris, gulong max_picture_size, gulong max_video_size)
788 {
789 FrogrFileLoader *self = NULL;
790
791 g_return_val_if_fail (file_uris, NULL);
792
793 self = FROGR_FILE_LOADER (g_object_new(FROGR_TYPE_FILE_LOADER, NULL));
794
795 self->loading_mode = LOADING_MODE_FROM_URIS;
796 self->file_uris = file_uris;
797 self->current_uri = self->file_uris;
798 self->index = 0;
799 self->n_files = g_slist_length (self->file_uris);
800 self->max_picture_size = max_picture_size;
801 self->max_video_size = max_video_size;
802
803 return self;
804 }
805
806 FrogrFileLoader *
frogr_file_loader_new_from_pictures(GSList * pictures)807 frogr_file_loader_new_from_pictures (GSList *pictures)
808 {
809 FrogrFileLoader *self = NULL;
810
811 g_return_val_if_fail (pictures, NULL);
812
813 self = FROGR_FILE_LOADER (g_object_new(FROGR_TYPE_FILE_LOADER, NULL));
814
815 self->loading_mode = LOADING_MODE_FROM_PICTURES;
816 self->pictures = pictures;
817 self->current_picture = pictures;
818 self->index = 0;
819 self->n_files = g_slist_length (self->pictures);
820
821 return self;
822 }
823
824 void
frogr_file_loader_load(FrogrFileLoader * self)825 frogr_file_loader_load (FrogrFileLoader *self)
826 {
827 g_return_if_fail (FROGR_IS_FILE_LOADER (self));
828
829 /* Check first whether there's something to load */
830 if (!self->n_files)
831 return;
832
833 /* Update status and progress */
834 _update_status_and_progress (self);
835
836 /* Trigger the asynchronous process */
837 _load_current_file (self);
838 }
839