[gthumb] facebook: added ability to import photos
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] facebook: added ability to import photos
- Date: Sun, 23 Dec 2012 20:42:57 +0000 (UTC)
commit b6b75dbb075e423c787d3db343480340090310f2
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun Dec 23 21:33:00 2012 +0100
facebook: added ability to import photos
[new feature]
extensions/facebook/Makefile.am | 4 +-
extensions/facebook/actions.c | 9 +
extensions/facebook/actions.h | 1 +
extensions/facebook/callbacks.c | 10 +
extensions/facebook/data/ui/Makefile.am | 3 +-
.../facebook/data/ui/import-from-facebook.ui | 300 ++++++++++
extensions/facebook/dlg-import-from-facebook.c | 607 ++++++++++++++++++++
extensions/facebook/dlg-import-from-facebook.h | 29 +
extensions/facebook/facebook-photo.c | 473 ++++++++++++----
extensions/facebook/facebook-photo.h | 58 +--
extensions/facebook/facebook-service.c | 123 ++---
extensions/facebook/facebook-service.h | 5 +-
extensions/facebook/facebook.extension.in.in | 2 +-
gthumb/gth-time.c | 61 ++-
gthumb/gth-time.h | 13 +-
15 files changed, 1435 insertions(+), 263 deletions(-)
---
diff --git a/extensions/facebook/Makefile.am b/extensions/facebook/Makefile.am
index 3fb505a..9bb8e58 100644
--- a/extensions/facebook/Makefile.am
+++ b/extensions/facebook/Makefile.am
@@ -12,6 +12,8 @@ libfacebook_la_SOURCES = \
callbacks.h \
dlg-export-to-facebook.c \
dlg-export-to-facebook.h \
+ dlg-import-from-facebook.c \
+ dlg-import-from-facebook.h \
facebook-album.c \
facebook-album.h \
facebook-album-properties-dialog.c \
@@ -26,7 +28,7 @@ libfacebook_la_SOURCES = \
libfacebook_la_CFLAGS = $(GTHUMB_CFLAGS) $(LIBSOUP_CFLAGS) $(LIBSECRET_CFLAGS) $(WEBKIT2_CFLAGS) $(JSON_GLIB_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb
libfacebook_la_LDFLAGS = $(EXTENSION_LIBTOOL_FLAGS)
-libfacebook_la_LIBADD = $(GTHUMB_LIBS) $(LIBSOUP_LIBS) $(LIBSECRET_LIBS) $(WEBKIT2_LIBS) $(JSON_GLIB_LIBS) ../export_tools/libexport_tools.la ../oauth/liboauth.la
+libfacebook_la_LIBADD = $(GTHUMB_LIBS) $(LIBSOUP_LIBS) $(LIBSECRET_LIBS) $(WEBKIT2_LIBS) $(JSON_GLIB_LIBS) ../export_tools/libexport_tools.la ../oauth/liboauth.la ../importer/libimporter.la
libfacebook_la_DEPENDENCIES = $(top_builddir)/gthumb/gthumb$(EXEEXT)
extensioninidir = $(extensiondir)
diff --git a/extensions/facebook/actions.c b/extensions/facebook/actions.c
index 69939f4..d3162e6 100644
--- a/extensions/facebook/actions.c
+++ b/extensions/facebook/actions.c
@@ -24,6 +24,7 @@
#include <glib/gi18n.h>
#include <gthumb.h>
#include "dlg-export-to-facebook.h"
+#include "dlg-import-from-facebook.h"
void
@@ -42,3 +43,11 @@ gth_browser_activate_action_export_facebook (GtkAction *action,
_g_object_list_unref (file_list);
_gtk_tree_path_list_free (items);
}
+
+
+void
+gth_browser_activate_action_import_facebook (GtkAction *action,
+ GthBrowser *browser)
+{
+ dlg_import_from_facebook (browser);
+}
diff --git a/extensions/facebook/actions.h b/extensions/facebook/actions.h
index f708c85..c184b9a 100644
--- a/extensions/facebook/actions.h
+++ b/extensions/facebook/actions.h
@@ -27,5 +27,6 @@
#define DEFINE_ACTION(x) void x (GtkAction *action, gpointer data);
DEFINE_ACTION(gth_browser_activate_action_export_facebook)
+DEFINE_ACTION(gth_browser_activate_action_import_facebook)
#endif /* ACTIONS_H */
diff --git a/extensions/facebook/callbacks.c b/extensions/facebook/callbacks.c
index bed6103..1c8b087 100644
--- a/extensions/facebook/callbacks.c
+++ b/extensions/facebook/callbacks.c
@@ -34,6 +34,11 @@ static const char *ui_info =
"<ui>"
" <menubar name='MenuBar'>"
" <menu name='File' action='FileMenu'>"
+" <menu name='Import' action='ImportMenu'>"
+" <placeholder name='Web_Services'>"
+" <menuitem action='File_Import_Facebook'/>"
+" </placeholder>"
+" </menu>"
" <menu name='Export' action='ExportMenu'>"
" <placeholder name='Web_Services'>"
" <menuitem action='File_Export_Facebook'/>"
@@ -50,6 +55,11 @@ static const char *ui_info =
static GthActionEntryExt action_entries[] = {
+ { "File_Import_Facebook", "site-facebook",
+ N_("Face_book..."), NULL,
+ N_("Download photos from Facebook"),
+ GTH_ACTION_FLAG_ALWAYS_SHOW_IMAGE,
+ G_CALLBACK (gth_browser_activate_action_import_facebook) },
{ "File_Export_Facebook", "site-facebook",
N_("Face_book..."), NULL,
N_("Upload photos to Facebook"),
diff --git a/extensions/facebook/data/ui/Makefile.am b/extensions/facebook/data/ui/Makefile.am
index c288b4b..da02cb0 100644
--- a/extensions/facebook/data/ui/Makefile.am
+++ b/extensions/facebook/data/ui/Makefile.am
@@ -2,7 +2,8 @@ uidir = $(pkgdatadir)/ui
ui_DATA = \
export-to-facebook.ui \
facebook-album-properties.ui \
- facebook-export-completed.ui
+ facebook-export-completed.ui \
+ import-from-facebook.ui
EXTRA_DIST = $(ui_DATA)
diff --git a/extensions/facebook/data/ui/import-from-facebook.ui b/extensions/facebook/data/ui/import-from-facebook.ui
new file mode 100644
index 0000000..82617d7
--- /dev/null
+++ b/extensions/facebook/data/ui/import-from-facebook.ui
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkListStore" id="account_liststore">
+ <columns>
+ <!-- column-name account -->
+ <column type="GObject"/>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkListStore" id="album_liststore">
+ <columns>
+ <!-- column-name data -->
+ <column type="GObject"/>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ <!-- column-name icon -->
+ <column type="gchararray"/>
+ <!-- column-name size -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkImage" id="download_image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-goto-bottom</property>
+ </object>
+ <object class="GtkDialog" id="import_dialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Import from Picasa Web Album</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">5</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="close_button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="download_button">
+ <property name="label" translatable="yes">_Import</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">download_image</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">5</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="account_combobox">
+ <property name="width_request">300</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">account_liststore</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="edit_accounts_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Edit accounts</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">view-list-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">A_ccount:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Album:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="album_combobox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">album_liststore</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="images_box">
+ <property name="width_request">460</property>
+ <property name="height_request">250</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="images_info_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Destination:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="destination_button_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">close_button</action-widget>
+ <action-widget response="-5">download_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/extensions/facebook/dlg-import-from-facebook.c b/extensions/facebook/dlg-import-from-facebook.c
new file mode 100644
index 0000000..7197bfd
--- /dev/null
+++ b/extensions/facebook/dlg-import-from-facebook.c
@@ -0,0 +1,607 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2010 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#define GDK_PIXBUF_ENABLE_BACKEND
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include <extensions/importer/importer.h>
+#include <extensions/oauth/oauth.h>
+#include "dlg-import-from-facebook.h"
+#include "facebook-album.h"
+#include "facebook-photo.h"
+#include "facebook-service.h"
+
+
+#define GET_WIDGET(x) (_gtk_builder_get_widget (data->builder, (x)))
+#define FAKE_SIZE 100000
+#define THUMBNAIL_SIZE 110
+
+
+enum {
+ ACCOUNT_DATA_COLUMN,
+ ACCOUNT_NAME_COLUMN
+};
+
+
+enum {
+ ALBUM_DATA_COLUMN,
+ ALBUM_NAME_COLUMN,
+ ALBUM_ICON_COLUMN,
+ ALBUM_SIZE_COLUMN
+};
+
+
+typedef struct {
+ GthBrowser *browser;
+ GthFileData *location;
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ GtkWidget *preferences_dialog;
+ GtkWidget *progress_dialog;
+ FacebookService *service;
+ GtkWidget *file_list;
+ GList *albums;
+ FacebookAlbum *album;
+ GList *photos;
+ GCancellable *cancellable;
+} DialogData;
+
+
+static void
+import_dialog_destroy_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ if (data->service != NULL)
+ gth_task_completed (GTH_TASK (data->service), NULL);
+ _g_object_unref (data->cancellable);
+ _g_object_unref (data->service);
+ _g_object_list_unref (data->albums);
+ _g_object_unref (data->album);
+ _g_object_list_unref (data->photos);
+ gtk_widget_destroy (data->progress_dialog);
+ _g_object_unref (data->builder);
+ _g_object_unref (data->location);
+ g_free (data);
+}
+
+
+static GList *
+get_files_to_download (DialogData *data)
+{
+ GthFileView *file_view;
+ GList *selected;
+ GList *file_list;
+
+ file_view = (GthFileView *) gth_file_list_get_view (GTH_FILE_LIST (data->file_list));
+ selected = gth_file_selection_get_selected (GTH_FILE_SELECTION (file_view));
+ if (selected != NULL)
+ file_list = gth_file_list_get_files (GTH_FILE_LIST (data->file_list), selected);
+ else
+ file_list = gth_file_store_get_visibles (GTH_FILE_STORE (gth_file_view_get_model (file_view)));
+
+ _gtk_tree_path_list_free (selected);
+
+ return file_list;
+}
+
+
+static void
+import_dialog_response_cb (GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+
+ switch (response_id) {
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CANCEL:
+ gth_file_list_cancel (GTH_FILE_LIST (data->file_list), (DataFunc) gtk_widget_destroy, data->dialog);
+ break;
+
+ case GTK_RESPONSE_OK:
+ {
+ GtkTreeIter iter;
+ FacebookAlbum *album;
+ GList *file_list;
+
+ if (! gtk_combo_box_get_active_iter (GTK_COMBO_BOX (GET_WIDGET ("album_combobox")), &iter)) {
+ gtk_widget_set_sensitive (GET_WIDGET ("download_button"), FALSE);
+ return;
+ }
+
+ gtk_tree_model_get (GTK_TREE_MODEL (GET_WIDGET ("album_liststore")), &iter,
+ ALBUM_DATA_COLUMN, &album,
+ -1);
+
+ file_list = get_files_to_download (data);
+ if (file_list != NULL) {
+ GSettings *settings;
+ GFile *destination;
+ gboolean single_subfolder;
+ GthSubfolderType subfolder_type;
+ GthSubfolderFormat subfolder_format;
+ char *custom_format;
+ GthTask *task;
+
+ settings = g_settings_new (GTHUMB_IMPORTER_SCHEMA);
+ destination = gth_import_preferences_get_destination ();
+ subfolder_type = g_settings_get_enum (settings, PREF_IMPORTER_SUBFOLDER_TYPE);
+ subfolder_format = g_settings_get_enum (settings, PREF_IMPORTER_SUBFOLDER_FORMAT);
+ single_subfolder = g_settings_get_boolean (settings, PREF_IMPORTER_SUBFOLDER_SINGLE);
+ custom_format = g_settings_get_string (settings, PREF_IMPORTER_SUBFOLDER_CUSTOM_FORMAT);
+
+ task = gth_import_task_new (data->browser,
+ file_list,
+ destination,
+ subfolder_type,
+ subfolder_format,
+ single_subfolder,
+ custom_format,
+ (album->name != NULL ? album->name : ""),
+ NULL,
+ FALSE,
+ FALSE,
+ FALSE);
+ gth_browser_exec_task (data->browser, task, FALSE);
+ gtk_widget_destroy (data->dialog);
+
+ g_object_unref (task);
+ _g_object_unref (destination);
+ g_object_unref (settings);
+ }
+
+ _g_object_list_unref (file_list);
+ g_object_unref (album);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static void
+update_account_list (DialogData *data)
+{
+ int current_account_idx;
+ OAuthAccount *current_account;
+ int idx;
+ GList *scan;
+ GtkTreeIter iter;
+
+ gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("account_liststore")));
+
+ current_account_idx = 0;
+ current_account = web_service_get_current_account (WEB_SERVICE (data->service));
+ for (scan = web_service_get_accounts (WEB_SERVICE (data->service)), idx = 0; scan; scan = scan->next, idx++) {
+ OAuthAccount *account = scan->data;
+
+ if (oauth_account_cmp (current_account, account) == 0)
+ current_account_idx = idx;
+
+ gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("account_liststore")), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("account_liststore")), &iter,
+ ACCOUNT_DATA_COLUMN, account,
+ ACCOUNT_NAME_COLUMN, account->name,
+ -1);
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("account_combobox")), current_account_idx);
+}
+
+
+static void
+get_albums_ready_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ GError *error = NULL;
+ GList *scan;
+
+ _g_object_list_unref (data->albums);
+ data->albums = facebook_service_get_albums_finish (data->service, res, &error);
+ if (error != NULL) {
+ if (data->service != NULL)
+ gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
+ _gtk_error_dialog_from_gerror_run (GTK_WINDOW (data->browser), _("Could not connect to the server"), error);
+ g_clear_error (&error);
+ gtk_widget_destroy (data->dialog);
+ return;
+ }
+
+ gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("album_liststore")));
+ for (scan = data->albums; scan; scan = scan->next) {
+ FacebookAlbum *album = scan->data;
+ char *n_photos;
+ GtkTreeIter iter;
+
+ n_photos = g_strdup_printf ("(%d)", album->count);
+
+ gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("album_liststore")), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("album_liststore")), &iter,
+ ALBUM_DATA_COLUMN, album,
+ ALBUM_ICON_COLUMN, "file-catalog",
+ ALBUM_NAME_COLUMN, album->name,
+ ALBUM_SIZE_COLUMN, n_photos,
+ -1);
+
+ g_free (n_photos);
+ }
+
+ gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
+
+ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (data->browser));
+ gtk_window_set_modal (GTK_WINDOW (data->dialog), FALSE);
+ gtk_window_present (GTK_WINDOW (data->dialog));
+}
+
+
+static void
+authentication_ready_cb (WebService *service,
+ DialogData *data)
+{
+ update_account_list (data);
+ facebook_service_get_albums (data->service,
+ data->cancellable,
+ get_albums_ready_cb,
+ data);
+}
+
+
+static void
+authentication_accounts_changed_cb (WebService *service,
+ DialogData *data)
+{
+ update_account_list (data);
+}
+
+
+static void
+edit_accounts_button_clicked_cb (GtkButton *button,
+ DialogData *data)
+{
+ web_service_edit_accounts (WEB_SERVICE (data->service), GTK_WINDOW (data->dialog));
+}
+
+
+static void
+account_combobox_changed_cb (GtkComboBox *widget,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ GtkTreeIter iter;
+ OAuthAccount *account;
+
+ if (! gtk_combo_box_get_active_iter (widget, &iter))
+ return;
+
+ gtk_tree_model_get (gtk_combo_box_get_model (widget),
+ &iter,
+ ACCOUNT_DATA_COLUMN, &account,
+ -1);
+
+ if (oauth_account_cmp (account, web_service_get_current_account (WEB_SERVICE (data->service))) != 0)
+ web_service_connect (WEB_SERVICE (data->service), account);
+
+ g_object_unref (account);
+}
+
+
+static void
+update_selection_status (DialogData *data)
+{
+ GList *file_list;
+ int n_selected;
+ char *text_selected;
+
+ file_list = get_files_to_download (data);
+ n_selected = g_list_length (file_list);
+ text_selected = g_strdup_printf (g_dngettext (NULL, "%d file", "%d files", n_selected), n_selected);
+ gtk_label_set_text (GTK_LABEL (GET_WIDGET ("images_info_label")), text_selected);
+
+ g_free (text_selected);
+ _g_object_list_unref (file_list);
+}
+
+
+static void
+list_photos_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ GError *error = NULL;
+ GList *list;
+ GList *scan;
+
+ gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
+
+ _g_object_list_unref (data->photos);
+ data->photos = facebook_service_list_photos_finish (data->service, result, &error);
+ if (error != NULL) {
+ if (data->service != NULL)
+ gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
+ _gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not get the photo list"), error);
+ g_clear_error (&error);
+ gtk_widget_destroy (data->dialog);
+ return;
+ }
+
+ list = NULL;
+ for (scan = data->photos; scan; scan = scan->next) {
+ FacebookPhoto *photo = scan->data;
+ GthFileData *file_data;
+
+ file_data = gth_file_data_new_for_uri (facebook_photo_get_original_url (photo), "image/jpeg");
+ g_file_info_set_file_type (file_data->info, G_FILE_TYPE_REGULAR);
+ g_file_info_set_size (file_data->info, FAKE_SIZE); /* set a fake size to make the progress dialog work correctly */
+ g_file_info_set_attribute_object (file_data->info, "facebook::object", G_OBJECT (photo));
+
+ list = g_list_prepend (list, file_data);
+ }
+ gth_file_list_set_files (GTH_FILE_LIST (data->file_list), list);
+ update_selection_status (data);
+ gtk_widget_set_sensitive (GET_WIDGET ("download_button"), list != NULL);
+
+ _g_object_list_unref (list);
+}
+
+
+static void
+album_combobox_changed_cb (GtkComboBox *widget,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+ GtkTreeIter iter;
+
+ if (! gtk_combo_box_get_active_iter (widget, &iter)) {
+ gth_file_list_clear (GTH_FILE_LIST (data->file_list), _("No album selected"));
+ return;
+ }
+
+ _g_object_unref (data->album);
+ gtk_tree_model_get (gtk_combo_box_get_model (widget),
+ &iter,
+ ALBUM_DATA_COLUMN, &data->album,
+ -1);
+
+ gth_import_preferences_dialog_set_event (GTH_IMPORT_PREFERENCES_DIALOG (data->preferences_dialog), data->album->name);
+
+ gth_task_dialog (GTH_TASK (data->service), FALSE, NULL);
+ facebook_service_list_photos (data->service,
+ data->album,
+ -1,
+ NULL,
+ data->cancellable,
+ list_photos_ready_cb,
+ data);
+}
+
+
+static GthImage *
+facebook_thumbnail_loader (GInputStream *istream,
+ GthFileData *file_data,
+ int requested_size,
+ int *original_width,
+ int *original_height,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GthImage *image = NULL;
+ FacebookPhoto *photo;
+ const char *uri;
+
+ photo = (FacebookPhoto *) g_file_info_get_attribute_object (file_data->info, "facebook::object");
+
+ uri = facebook_photo_get_thumbnail_url (photo, requested_size);
+ if (uri == NULL)
+ uri = facebook_photo_get_original_url (photo);
+
+ if (uri != NULL) {
+ GFile *file;
+ void *buffer;
+ gsize size;
+
+ file = g_file_new_for_uri (uri);
+ if (_g_file_load_in_buffer (file, &buffer, &size, cancellable, error)) {
+ GInputStream *stream;
+ GdkPixbuf *pixbuf;
+
+ stream = g_memory_input_stream_new_from_data (buffer, size, g_free);
+ pixbuf = gdk_pixbuf_new_from_stream (stream, cancellable, error);
+ if (pixbuf != NULL) {
+ GdkPixbuf *rotated;
+
+ rotated = gdk_pixbuf_apply_embedded_orientation (pixbuf);
+ g_object_unref (pixbuf);
+ pixbuf = rotated;
+
+ image = gth_image_new_for_pixbuf (pixbuf);
+ }
+
+ g_object_unref (pixbuf);
+ g_object_unref (stream);
+ }
+
+ g_object_unref (file);
+ }
+ else
+ *error = g_error_new_literal (GTH_ERROR, 0, "cannot generate the thumbnail");
+
+ return image;
+}
+
+
+static int
+facebook_photo_position_func (GthFileData *a,
+ GthFileData *b)
+{
+ FacebookPhoto *photo_a;
+ FacebookPhoto *photo_b;
+
+ photo_a = (FacebookPhoto *) g_file_info_get_attribute_object (a->info, "facebook::object");
+ photo_b = (FacebookPhoto *) g_file_info_get_attribute_object (b->info, "facebook::object");
+
+ if (photo_a->position == photo_b->position)
+ return strcmp (photo_a->id, photo_b->id);
+ else if (photo_a->position > photo_b->position)
+ return 1;
+ else
+ return -1;
+}
+
+
+static void
+file_list_selection_changed_cb (GthFileView *file_view,
+ gpointer user_data)
+{
+ update_selection_status ((DialogData *) user_data);
+}
+
+
+void
+dlg_import_from_facebook (GthBrowser *browser)
+{
+ DialogData *data;
+ GthThumbLoader *thumb_loader;
+ char *title;
+
+ data = g_new0 (DialogData, 1);
+ data->browser = browser;
+ data->location = gth_file_data_dup (gth_browser_get_location_data (browser));
+ data->builder = _gtk_builder_new_from_file ("import-from-facebook.ui", "facebook");
+ data->dialog = _gtk_builder_get_widget (data->builder, "import_dialog");
+ data->cancellable = g_cancellable_new ();
+
+ {
+ GtkCellLayout *cell_layout;
+ GtkCellRenderer *renderer;
+
+ cell_layout = GTK_CELL_LAYOUT (GET_WIDGET ("album_combobox"));
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (cell_layout, renderer, FALSE);
+ gtk_cell_layout_set_attributes (cell_layout, renderer,
+ "icon-name", ALBUM_ICON_COLUMN,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (cell_layout, renderer, TRUE);
+ gtk_cell_layout_set_attributes (cell_layout, renderer,
+ "text", ALBUM_NAME_COLUMN,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (cell_layout, renderer, FALSE);
+ gtk_cell_layout_set_attributes (cell_layout, renderer,
+ "text", ALBUM_SIZE_COLUMN,
+ NULL);
+ }
+
+ /* Set the widget data */
+
+ data->file_list = gth_file_list_new (gth_grid_view_new (), GTH_FILE_LIST_MODE_NORMAL, FALSE);
+ thumb_loader = gth_file_list_get_thumb_loader (GTH_FILE_LIST (data->file_list));
+ gth_thumb_loader_set_use_cache (thumb_loader, FALSE);
+ gth_thumb_loader_set_loader_func (thumb_loader, facebook_thumbnail_loader);
+ gth_file_list_set_thumb_size (GTH_FILE_LIST (data->file_list), THUMBNAIL_SIZE);
+ gth_file_list_enable_thumbs (GTH_FILE_LIST (data->file_list), TRUE);
+ gth_file_list_set_ignore_hidden (GTH_FILE_LIST (data->file_list), TRUE);
+ gth_file_list_set_caption (GTH_FILE_LIST (data->file_list), "none");
+ gth_file_list_set_sort_func (GTH_FILE_LIST (data->file_list), facebook_photo_position_func, FALSE);
+ gth_file_list_clear (GTH_FILE_LIST (data->file_list), _("No album selected"));
+ gtk_widget_show (data->file_list);
+ gtk_box_pack_start (GTK_BOX (GET_WIDGET ("images_box")), data->file_list, TRUE, TRUE, 0);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GET_WIDGET ("album_liststore")), ALBUM_NAME_COLUMN, GTK_SORT_ASCENDING);
+
+ gtk_widget_set_sensitive (GET_WIDGET ("download_button"), FALSE);
+
+ data->preferences_dialog = gth_import_preferences_dialog_new ();
+ gtk_window_set_transient_for (GTK_WINDOW (data->preferences_dialog), GTK_WINDOW (data->dialog));
+
+ gtk_box_pack_start (GTK_BOX (GET_WIDGET ("destination_button_box")),
+ gth_import_destination_button_new (GTH_IMPORT_PREFERENCES_DIALOG (data->preferences_dialog)),
+ TRUE,
+ TRUE,
+ 0);
+ gtk_widget_show_all (GET_WIDGET ("destination_button_box"));
+
+ title = g_strdup_printf (_("Import from %s"), _("Facebook"));
+ gtk_window_set_title (GTK_WINDOW (data->dialog), title);
+ g_free (title);
+
+ _gtk_window_resize_to_fit_screen_height (data->dialog, 500);
+
+ /* Set the signals handlers. */
+
+ g_signal_connect (data->dialog,
+ "destroy",
+ G_CALLBACK (import_dialog_destroy_cb),
+ data);
+ g_signal_connect (data->dialog,
+ "delete-event",
+ G_CALLBACK (gtk_true),
+ NULL);
+ g_signal_connect (data->dialog,
+ "response",
+ G_CALLBACK (import_dialog_response_cb),
+ data);
+ g_signal_connect (GET_WIDGET ("edit_accounts_button"),
+ "clicked",
+ G_CALLBACK (edit_accounts_button_clicked_cb),
+ data);
+ g_signal_connect (GET_WIDGET ("account_combobox"),
+ "changed",
+ G_CALLBACK (account_combobox_changed_cb),
+ data);
+ g_signal_connect (GET_WIDGET ("album_combobox"),
+ "changed",
+ G_CALLBACK (album_combobox_changed_cb),
+ data);
+ g_signal_connect (gth_file_list_get_view (GTH_FILE_LIST (data->file_list)),
+ "file-selection-changed",
+ G_CALLBACK (file_list_selection_changed_cb),
+ data);
+
+ update_selection_status (data);
+ gth_import_preferences_dialog_set_event (GTH_IMPORT_PREFERENCES_DIALOG (data->preferences_dialog), "");
+
+ data->service = facebook_service_new (data->cancellable,
+ GTK_WIDGET (data->browser),
+ data->dialog);
+ g_signal_connect (data->service,
+ "account-ready",
+ G_CALLBACK (authentication_ready_cb),
+ data);
+ g_signal_connect (data->service,
+ "accounts-changed",
+ G_CALLBACK (authentication_accounts_changed_cb),
+ data);
+
+ data->progress_dialog = gth_progress_dialog_new (GTK_WINDOW (data->browser));
+ gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (data->progress_dialog), GTH_TASK (data->service));
+
+ web_service_autoconnect (WEB_SERVICE (data->service));
+}
diff --git a/extensions/facebook/dlg-import-from-facebook.h b/extensions/facebook/dlg-import-from-facebook.h
new file mode 100644
index 0000000..fc0a97d
--- /dev/null
+++ b/extensions/facebook/dlg-import-from-facebook.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2010 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DLG_IMPORT_FROM_FACEBOOK_H
+#define DLG_IMPORT_FROM_FACEBOOK_H
+
+#include <gthumb.h>
+
+void dlg_import_from_facebook (GthBrowser *browser);
+
+#endif /* DLG_IMPORT_FROM_FACEBOOK_H */
diff --git a/extensions/facebook/facebook-photo.c b/extensions/facebook/facebook-photo.c
index 052739d..4f75b7a 100644
--- a/extensions/facebook/facebook-photo.c
+++ b/extensions/facebook/facebook-photo.c
@@ -3,7 +3,7 @@
/*
* GThumb
*
- * Copyright (C) 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2010-2012 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,202 +22,435 @@
#include <config.h>
#include <stdlib.h>
#include <string.h>
+#include <json-glib/json-glib.h>
#include <gthumb.h>
#include "facebook-photo.h"
-static void facebook_photo_dom_domizable_interface_init (DomDomizableInterface *iface);
+static void facebook_photo_json_serializable_interface_init (JsonSerializableIface *iface);
G_DEFINE_TYPE_WITH_CODE (FacebookPhoto,
facebook_photo,
G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (DOM_TYPE_DOMIZABLE,
- facebook_photo_dom_domizable_interface_init))
+ G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE,
+ facebook_photo_json_serializable_interface_init))
-static void
-facebook_photo_finalize (GObject *obj)
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_PICTURE,
+ PROP_SOURCE,
+ PROP_WIDTH,
+ PROP_HEIGHT,
+ PROP_LINK,
+ PROP_CREATED_TIME,
+ PROP_UPDATED_TIME,
+ PROP_IMAGES
+};
+
+
+/* -- facebook_image -- */
+
+
+static FacebookImage *
+facebook_image_new (void)
{
- FacebookPhoto *self;
+ FacebookImage *image;
- self = FACEBOOK_PHOTO (obj);
+ image = g_new (FacebookImage, 1);
+ image->source = NULL;
+ image->width = 0;
+ image->height = 0;
- g_free (self->id);
- g_free (self->secret);
- g_free (self->server);
- g_free (self->title);
+ return image;
+}
- G_OBJECT_CLASS (facebook_photo_parent_class)->finalize (obj);
+
+static FacebookImage *
+facebook_image_copy (FacebookImage *source)
+{
+ FacebookImage *dest;
+
+ dest = facebook_image_new ();
+ _g_strset (&dest->source, source->source);
+ dest->width = source->width;
+ dest->height = source->height;
+
+ return dest;
}
static void
-facebook_photo_class_init (FacebookPhotoClass *klass)
+facebook_image_free (FacebookImage *image)
{
- G_OBJECT_CLASS (klass)->finalize = facebook_photo_finalize;
+ g_free (image->source);
+ g_free (image);
}
-static DomElement*
-facebook_photo_create_element (DomDomizable *base,
- DomDocument *doc)
+/* -- facebook_image_list -- */
+
+
+#define FACEBOOK_TYPE_IMAGE_LIST (facebook_image_list_get_type ())
+
+
+static GList *
+facebook_image_list_copy (GList *source)
{
- FacebookPhoto *self;
- DomElement *element;
-
- self = FACEBOOK_PHOTO (base);
-
- element = dom_document_create_element (doc, "photo", NULL);
- if (self->id != NULL)
- dom_element_set_attribute (element, "id", self->id);
- if (self->secret != NULL)
- dom_element_set_attribute (element, "secret", self->secret);
- if (self->server != NULL)
- dom_element_set_attribute (element, "server", self->server);
- if (self->title != NULL)
- dom_element_set_attribute (element, "title", self->title);
- if (self->is_primary)
- dom_element_set_attribute (element, "isprimary", "1");
-
- return element;
+ return g_list_copy_deep (source, (GCopyFunc) facebook_image_copy, NULL);
}
static void
-facebook_photo_load_from_element (DomDomizable *base,
- DomElement *element)
+facebook_image_list_free (GList *images)
{
- FacebookPhoto *self;
-
- if ((element == NULL) || (g_strcmp0 (element->tag_name, "photo") != 0))
- return;
-
- self = FACEBOOK_PHOTO (base);
-
- facebook_photo_set_id (self, dom_element_get_attribute (element, "id"));
- facebook_photo_set_secret (self, dom_element_get_attribute (element, "secret"));
- facebook_photo_set_server (self, dom_element_get_attribute (element, "server"));
- facebook_photo_set_title (self, dom_element_get_attribute (element, "title"));
- facebook_photo_set_is_primary (self, dom_element_get_attribute (element, "isprimary"));
- facebook_photo_set_url_sq (self, dom_element_get_attribute (element, "url_sq"));
- facebook_photo_set_url_t (self, dom_element_get_attribute (element, "url_t"));
- facebook_photo_set_url_s (self, dom_element_get_attribute (element, "url_s"));
- facebook_photo_set_url_m (self, dom_element_get_attribute (element, "url_m"));
- facebook_photo_set_url_o (self, dom_element_get_attribute (element, "url_o"));
+ g_list_foreach (images, (GFunc) facebook_image_free, NULL);
+ g_list_free (images);
}
+G_DEFINE_BOXED_TYPE (GList, facebook_image_list, facebook_image_list_copy, facebook_image_list_free)
+
+
+/* -- facebook_photo -- */
+
+
static void
-facebook_photo_dom_domizable_interface_init (DomDomizableInterface *iface)
+facebook_photo_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- iface->create_element = facebook_photo_create_element;
- iface->load_from_element = facebook_photo_load_from_element;
+ FacebookPhoto *self;
+
+ self = FACEBOOK_PHOTO (object);
+
+ switch (property_id) {
+ case PROP_ID:
+ _g_strset (&self->id, g_value_get_string (value));
+ break;
+ case PROP_PICTURE:
+ _g_strset (&self->picture, g_value_get_string (value));
+ break;
+ case PROP_SOURCE:
+ _g_strset (&self->source, g_value_get_string (value));
+ break;
+ case PROP_WIDTH:
+ self->width = g_value_get_int (value);
+ break;
+ case PROP_HEIGHT:
+ self->height = g_value_get_int (value);
+ break;
+ case PROP_LINK:
+ _g_strset (&self->link, g_value_get_string (value));
+ break;
+ case PROP_CREATED_TIME:
+ gth_datetime_free (self->created_time);
+ self->created_time = g_value_dup_boxed (value);
+ break;
+ case PROP_UPDATED_TIME:
+ gth_datetime_free (self->updated_time);
+ self->updated_time = g_value_dup_boxed (value);
+ break;
+ case PROP_IMAGES:
+ facebook_image_list_free (self->images);
+ self->images = g_value_dup_boxed (value);
+ break;
+ default:
+ break;
+ }
}
static void
-facebook_photo_init (FacebookPhoto *self)
+facebook_photo_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- /* void */
+ FacebookPhoto *self;
+
+ self = FACEBOOK_PHOTO (object);
+
+ switch (property_id) {
+ case PROP_ID:
+ g_value_set_string (value, self->id);
+ break;
+ case PROP_PICTURE:
+ g_value_set_string (value, self->picture);
+ break;
+ case PROP_SOURCE:
+ g_value_set_string (value, self->source);
+ break;
+ case PROP_WIDTH:
+ g_value_set_int (value, self->width);
+ break;
+ case PROP_HEIGHT:
+ g_value_set_int (value, self->height);
+ break;
+ case PROP_LINK:
+ g_value_set_string (value, self->link);
+ break;
+ case PROP_CREATED_TIME:
+ g_value_set_boxed (value, self->created_time);
+ break;
+ case PROP_UPDATED_TIME:
+ g_value_set_boxed (value, self->updated_time);
+ break;
+ case PROP_IMAGES:
+ g_value_set_boxed (value, self->images);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
}
-FacebookPhoto *
-facebook_photo_new (void)
+static void
+facebook_photo_finalize (GObject *obj)
{
- return g_object_new (FACEBOOK_TYPE_PHOTO, NULL);
-}
+ FacebookPhoto *self;
+ self = FACEBOOK_PHOTO (obj);
-void
-facebook_photo_set_id (FacebookPhoto *self,
- const char *value)
-{
- _g_strset (&self->id, value);
+ g_free (self->id);
+ g_free (self->picture);
+ g_free (self->source);
+ g_free (self->link);
+ gth_datetime_free (self->created_time);
+ gth_datetime_free (self->updated_time);
+ facebook_image_list_free (self->images);
+
+ G_OBJECT_CLASS (facebook_photo_parent_class)->finalize (obj);
}
-void
-facebook_photo_set_secret (FacebookPhoto *self,
- const char *value)
+static void
+facebook_photo_class_init (FacebookPhotoClass *klass)
{
- _g_strset (&self->secret, value);
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = facebook_photo_finalize;
+ object_class->set_property = facebook_photo_set_property;
+ object_class->get_property = facebook_photo_get_property;
+
+ /* properties */
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_string ("id",
+ "ID",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_PICTURE,
+ g_param_spec_string ("picture",
+ "Picture",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SOURCE,
+ g_param_spec_string ("source",
+ "Source",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_WIDTH,
+ g_param_spec_int ("width",
+ "Width",
+ "",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_HEIGHT,
+ g_param_spec_int ("height",
+ "Height",
+ "",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_LINK,
+ g_param_spec_string ("link",
+ "Link",
+ "",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_CREATED_TIME,
+ g_param_spec_boxed ("created-time",
+ "Created time",
+ "",
+ GTH_TYPE_DATETIME,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_UPDATED_TIME,
+ g_param_spec_boxed ("updated-time",
+ "Updated time",
+ "",
+ GTH_TYPE_DATETIME,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_IMAGES,
+ g_param_spec_boxed ("images",
+ "Images",
+ "",
+ FACEBOOK_TYPE_IMAGE_LIST,
+ G_PARAM_READWRITE));
}
-void
-facebook_photo_set_server (FacebookPhoto *self,
- const char *value)
+static gboolean
+facebook_photo_deserialize_property (JsonSerializable *serializable,
+ const gchar *property_name,
+ GValue *value,
+ GParamSpec *pspec,
+ JsonNode *property_node)
{
- _g_strset (&self->server, value);
-}
+ FacebookPhoto *self = FACEBOOK_PHOTO (serializable);
+ if (pspec->value_type == GTH_TYPE_DATETIME) {
+ GTimeVal timeval;
-void
-facebook_photo_set_title (FacebookPhoto *self,
- const char *value)
-{
- _g_strset (&self->title, value);
-}
+ if (g_time_val_from_iso8601 (json_node_get_string (property_node), &timeval)) {
+ GthDateTime *datetime;
+ datetime = gth_datetime_new ();
+ gth_datetime_from_timeval (datetime, &timeval);
+ g_object_set (self, property_name, datetime, NULL);
-void
-facebook_photo_set_is_primary (FacebookPhoto *self,
- const char *value)
-{
- self->is_primary = (g_strcmp0 (value, "1") == 0);
-}
+ gth_datetime_free (datetime);
+ return TRUE;
+ }
-void
-facebook_photo_set_url_sq (FacebookPhoto *self,
- const char *value)
-{
- _g_strset (&self->url_sq, value);
+ return FALSE;
+ }
+
+ if (pspec->value_type == FACEBOOK_TYPE_IMAGE_LIST) {
+ GList *images = NULL;
+ JsonArray *array;
+ int i;
+
+ array = json_node_get_array (property_node);
+ for (i = 0; i < json_array_get_length (array); i++) {
+ JsonObject *image_obj;
+
+ image_obj = json_array_get_object_element (array, i);
+ if (image_obj != NULL) {
+ FacebookImage *image;
+
+ image = facebook_image_new ();
+ _g_strset (&image->source, json_object_get_string_member (image_obj, "source"));
+ image->width = json_object_get_int_member (image_obj, "width");
+ image->height = json_object_get_int_member (image_obj, "height");
+
+ images = g_list_prepend (images, image);
+ }
+ }
+
+ images = g_list_reverse (images);
+ g_object_set (self, property_name, images, NULL);
+
+ facebook_image_list_free (images);
+
+ return TRUE;
+ }
+
+ return json_serializable_default_deserialize_property (serializable,
+ property_name,
+ value,
+ pspec,
+ property_node);
}
-void
-facebook_photo_set_url_t (FacebookPhoto *self,
- const char *value)
+static void
+facebook_photo_json_serializable_interface_init (JsonSerializableIface *iface)
{
- _g_strset (&self->url_t, value);
+ iface->deserialize_property = facebook_photo_deserialize_property;
}
-void
-facebook_photo_set_url_s (FacebookPhoto *self,
- const char *value)
+static void
+facebook_photo_init (FacebookPhoto *self)
{
- _g_strset (&self->url_s, value);
+ self->id = NULL;
+ self->picture = NULL;
+ self->source = NULL;
+ self->width = 0;
+ self->height = 0;
+ self->link = NULL;
+ self->created_time = NULL;
+ self->updated_time = NULL;
+ self->images = NULL;
}
-void
-facebook_photo_set_url_m (FacebookPhoto *self,
- const char *value)
+FacebookPhoto *
+facebook_photo_new (void)
{
- _g_strset (&self->url_m, value);
+ return g_object_new (FACEBOOK_TYPE_PHOTO, NULL);
}
-void
-facebook_photo_set_url_o (FacebookPhoto *self,
- const char *value)
+const char *
+facebook_photo_get_original_url (FacebookPhoto *photo)
{
- _g_strset (&self->url_o, value);
+ char *url;
+ GList *scan;
+ glong max_size;
+
+ url = photo->source;
+ max_size = photo->width * photo->height;
+
+ for (scan = photo->images; scan; scan = scan->next) {
+ FacebookImage *image = scan->data;
+ glong image_size;
+
+ image_size = image->width * image->height;
+ if (image_size > max_size) {
+ max_size = image_size;
+ url = image->source;
+ }
+ }
+
+ return url;
}
-void
-facebook_photo_set_original_format (FacebookPhoto *self,
- const char *value)
+const char *
+facebook_photo_get_thumbnail_url (FacebookPhoto *photo,
+ int requested_size)
{
- _g_strset (&self->original_format, value);
-
- g_free (self->mime_type);
- self->mime_type = NULL;
- if (self->original_format != NULL)
- self->mime_type = g_strconcat ("image/", self->original_format, NULL);
+ char *url;
+ GList *scan;
+ glong min_delta;
+
+ url = photo->picture;
+ requested_size = requested_size * requested_size;
+ min_delta = 0;
+
+ for (scan = photo->images; scan; scan = scan->next) {
+ FacebookImage *image = scan->data;
+ glong image_delta;
+
+ image_delta = labs ((image->width * image->height) - requested_size);
+ if ((scan == photo->images) || (image_delta < min_delta)) {
+ min_delta = image_delta;
+ url = image->source;
+ }
+ }
+
+ return url;
}
diff --git a/extensions/facebook/facebook-photo.h b/extensions/facebook/facebook-photo.h
index fdf6e04..89d0dc1 100644
--- a/extensions/facebook/facebook-photo.h
+++ b/extensions/facebook/facebook-photo.h
@@ -38,53 +38,37 @@ typedef struct _FacebookPhoto FacebookPhoto;
typedef struct _FacebookPhotoClass FacebookPhotoClass;
typedef struct _FacebookPhotoPrivate FacebookPhotoPrivate;
+typedef struct {
+ char *source;
+ int width;
+ int height;
+} FacebookImage;
+
struct _FacebookPhoto {
GObject parent_instance;
FacebookPhotoPrivate *priv;
- char *id;
- char *secret;
- char *server;
- char *title;
- gboolean is_primary;
- char *url_sq;
- char *url_t;
- char *url_s;
- char *url_m;
- char *url_o;
- char *original_format;
- char *mime_type;
- int position;
+ char *id;
+ char *picture;
+ char *source;
+ int width;
+ int height;
+ char *link;
+ GthDateTime *created_time;
+ GthDateTime *updated_time;
+ GList *images; /* FacebookImage list */
+ int position;
};
struct _FacebookPhotoClass {
GObjectClass parent_class;
};
-GType facebook_photo_get_type (void);
-FacebookPhoto * facebook_photo_new (void);
-void facebook_photo_set_id (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_secret (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_server (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_title (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_is_primary (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_url_sq (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_url_t (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_url_s (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_url_m (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_url_o (FacebookPhoto *self,
- const char *value);
-void facebook_photo_set_original_format (FacebookPhoto *self,
- const char *value);
+GType facebook_photo_get_type (void);
+FacebookPhoto * facebook_photo_new (void);
+const char * facebook_photo_get_original_url (FacebookPhoto *photo);
+const char * facebook_photo_get_thumbnail_url (FacebookPhoto *photo,
+ int requested_size);
G_END_DECLS
diff --git a/extensions/facebook/facebook-service.c b/extensions/facebook/facebook-service.c
index d73cee6..ca2ddb1 100644
--- a/extensions/facebook/facebook-service.c
+++ b/extensions/facebook/facebook-service.c
@@ -955,119 +955,97 @@ facebook_service_upload_photos_finish (FacebookService *self,
}
-#if 0
-
/* -- facebook_service_list_photos -- */
static void
-list_photos_ready_cb (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
+facebook_service_list_photos_ready_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
{
- FacebookService *self = user_data;
+ FacebookService *self = user_data;
GSimpleAsyncResult *result;
- SoupBuffer *body;
- DomDocument *doc = NULL;
+ JsonNode *node;
GError *error = NULL;
result = _web_service_get_result (WEB_SERVICE (self));
- if (msg->status_code != 200) {
- g_simple_async_result_set_error (result,
- SOUP_HTTP_ERROR,
- msg->status_code,
- "%s",
- soup_status_get_phrase (msg->status_code));
- g_simple_async_result_complete_in_idle (result);
- return;
- }
-
- body = soup_message_body_flatten (msg->response_body);
- if (facebook_utils_parse_response (body, &doc, &error)) {
- DomElement *response;
- DomElement *node;
+ if (facebook_utils_parse_response (msg, &node, &error)) {
GList *photos = NULL;
+ JsonObject *obj;
+ JsonObject *obj_photos;
+ JsonArray *data;
+ int i;
- response = DOM_ELEMENT (doc)->first_child;
- for (node = response->first_child; node; node = node->next_sibling) {
- if (g_strcmp0 (node->tag_name, "photoset") == 0) {
- DomElement *child;
- int position;
-
- position = 0;
- for (child = node->first_child; child; child = child->next_sibling) {
- if (g_strcmp0 (child->tag_name, "photo") == 0) {
- FacebookPhoto *photo;
-
- photo = facebook_photo_new ();
- dom_domizable_load_from_element (DOM_DOMIZABLE (photo), child);
- photo->position = position++;
- photos = g_list_prepend (photos, photo);
- }
- }
- }
+ obj = json_node_get_object (node);
+ obj_photos = json_object_get_object_member (obj, "photos");
+ data = json_object_get_array_member (obj_photos, "data");
+ for (i = 0; i < json_array_get_length (data); i++) {
+ JsonNode *photo_node;
+ FacebookPhoto *photo;
+
+ photo_node = json_array_get_element (data, i);
+ photo = (FacebookPhoto *) json_gobject_deserialize (FACEBOOK_TYPE_PHOTO, photo_node);
+ photo->position = i;
+ photos = g_list_prepend (photos, photo);
}
photos = g_list_reverse (photos);
g_simple_async_result_set_op_res_gpointer (result, photos, (GDestroyNotify) _g_object_list_unref);
- g_object_unref (doc);
+ json_node_free (node);
}
else
g_simple_async_result_set_from_error (result, error);
g_simple_async_result_complete_in_idle (result);
-
- soup_buffer_free (body);
}
void
-facebook_service_list_photos (FacebookService *self,
- FacebookPhotoset *photoset,
- const char *extras,
- int per_page,
- int page,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+facebook_service_list_photos (FacebookService *self,
+ FacebookAlbum *album,
+ int limit,
+ const char *after,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ char *uri;
GHashTable *data_set;
- char *s;
SoupMessage *msg;
- g_return_if_fail (photoset != NULL);
+ g_return_if_fail (album != NULL);
- gth_task_progress (GTH_TASK (self->priv->conn), _("Getting the photo list"), NULL, TRUE, 0.0);
+ gth_task_progress (GTH_TASK (self),
+ _("Getting the photo list"),
+ NULL,
+ TRUE,
+ 0.0);
+ uri = g_strdup_printf ("https://graph.facebook.com/%s", album->id);
data_set = g_hash_table_new (g_str_hash, g_str_equal);
- g_hash_table_insert (data_set, "method", "facebook.photosets.getPhotos");
- g_hash_table_insert (data_set, "photoset_id", photoset->id);
- if (extras != NULL)
- g_hash_table_insert (data_set, "extras", (char *) extras);
- if (per_page > 0) {
- s = g_strdup_printf ("%d", per_page);
- g_hash_table_insert (data_set, "per_page", s);
- g_free (s);
+ g_hash_table_insert (data_set, "fields", "photos");
+ if (limit > 0) {
+ char *s_limit = g_strdup_printf ("%d", limit);
+ g_hash_table_insert (data_set, "limit", s_limit);
+ g_free (s_limit);
}
- if (page > 0) {
- s = g_strdup_printf ("%d", page);
- g_hash_table_insert (data_set, "page", s);
- g_free (s);
- }
- facebook_connection_add_api_sig (self->priv->conn, data_set);
- msg = soup_form_request_new_from_hash ("GET", "http://api.facebook.com/services/rest", data_set);
- _web_service_send_message (self,
+ if (after != NULL)
+ g_hash_table_insert (data_set, "after", (gpointer) after);
+ _facebook_service_add_access_token (self, data_set);
+ msg = soup_form_request_new_from_hash ("GET", uri, data_set);
+ _web_service_send_message (WEB_SERVICE (self),
msg,
cancellable,
callback,
user_data,
facebook_service_list_photos,
- list_photos_ready_cb,
+ facebook_service_list_photos_ready_cb,
self);
g_hash_table_destroy (data_set);
+ g_free (uri);
}
@@ -1081,6 +1059,3 @@ facebook_service_list_photos_finish (FacebookService *self,
else
return _g_object_list_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
}
-
-#endif
-
diff --git a/extensions/facebook/facebook-service.h b/extensions/facebook/facebook-service.h
index 800bf84..efe8e28 100644
--- a/extensions/facebook/facebook-service.h
+++ b/extensions/facebook/facebook-service.h
@@ -79,14 +79,15 @@ void facebook_service_upload_photos (FacebookService
GList * facebook_service_upload_photos_finish (FacebookService *self,
GAsyncResult *result,
GError **error);
-#if 0
void facebook_service_list_photos (FacebookService *self,
FacebookAlbum *album,
+ int limit,
+ const char *after,
+ GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GList * facebook_service_list_photos_finish (FacebookService *self,
GAsyncResult *result,
GError **error);
-#endif
#endif /* FACEBOOK_SERVICE_H */
diff --git a/extensions/facebook/facebook.extension.in.in b/extensions/facebook/facebook.extension.in.in
index 4d77d95..afdadc9 100644
--- a/extensions/facebook/facebook.extension.in.in
+++ b/extensions/facebook/facebook.extension.in.in
@@ -11,4 +11,4 @@ Category=Exporter
Type=module
File=%LIBRARY%
API=%GTHUMB_API_VERSION%
-Requires=export_tools;oauth
+Requires=importer;export_tools;oauth
diff --git a/gthumb/gth-time.c b/gthumb/gth-time.c
index a68da94..d76ee11 100644
--- a/gthumb/gth-time.c
+++ b/gthumb/gth-time.c
@@ -18,7 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#include <config.h>
#include <stdlib.h>
#include "glib-utils.h"
@@ -31,14 +31,29 @@
#define INVALID_USEC (1000000)
-GthTime *
+static GthDateTime *
+gth_datetime_copy_for_boxed (GthDateTime *source)
+{
+ GthDateTime *dest;
+
+ dest = gth_datetime_new ();
+ gth_datetime_copy (source, dest);
+
+ return dest;
+}
+
+
+G_DEFINE_BOXED_TYPE (GthDateTime, gth_datetime, gth_datetime_copy_for_boxed, gth_datetime_free)
+
+
+GthTime *
gth_time_new (void)
{
GthTime *time;
-
+
time = g_new (GthTime, 1);
gth_time_clear (time);
-
+
return time;
}
@@ -60,17 +75,17 @@ gth_time_clear (GthTime *time)
}
-gboolean
+gboolean
gth_time_valid (GthTime *time)
-{
+{
return (time->hour < INVALID_HOUR) && (time->min < INVALID_MIN) && (time->sec < INVALID_SEC) && (time->usec < INVALID_USEC);
}
void
-gth_time_set_hms (GthTime *time,
- guint8 hour,
- guint8 min,
+gth_time_set_hms (GthTime *time,
+ guint8 hour,
+ guint8 min,
guint8 sec,
guint usec)
{
@@ -183,46 +198,46 @@ gth_datetime_from_exif_date (GthDateTime *dt,
val = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
year = val;
-
+
if (*exif_date != ':')
return FALSE;
-
+
/* MM */
-
+
exif_date++;
month = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
-
+
if (*exif_date != ':')
return FALSE;
/* DD */
-
+
exif_date++;
day = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
-
+
if (*exif_date != ' ')
return FALSE;
-
+
g_date_set_dmy (dt->date, day, month, year);
/* hh */
-
+
val = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
dt->time->hour = val;
-
+
if (*exif_date != ':')
return FALSE;
-
+
/* mm */
-
+
exif_date++;
dt->time->min = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
-
+
if (*exif_date != ':')
return FALSE;
-
+
/* ss */
-
+
exif_date++;
dt->time->sec = strtoul (exif_date, (char **)&exif_date, 10);
diff --git a/gthumb/gth-time.h b/gthumb/gth-time.h
index 310aa96..c509654 100644
--- a/gthumb/gth-time.h
+++ b/gthumb/gth-time.h
@@ -18,7 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+
#ifndef GTH_TIME_H
#define GTH_TIME_H
@@ -26,6 +26,10 @@
G_BEGIN_DECLS
+
+#define GTH_TYPE_DATETIME (gth_datetime_get_type ())
+
+
typedef struct {
guint8 hour;
guint8 min;
@@ -39,13 +43,14 @@ typedef struct {
} GthDateTime;
+GType gth_datetime_get_type (void);
GthTime * gth_time_new (void);
void gth_time_free (GthTime *time);
void gth_time_clear (GthTime *time);
gboolean gth_time_valid (GthTime *time);
-void gth_time_set_hms (GthTime *time,
- guint8 hour,
- guint8 min,
+void gth_time_set_hms (GthTime *time,
+ guint8 hour,
+ guint8 min,
guint8 sec,
guint usec);
GthDateTime * gth_datetime_new (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]