/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * 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 . */ #include #include #include #include "dlg-export-to-flickr.h" #include "flickr-account.h" #include "flickr-photoset.h" #include "flickr-service.h" #include "preferences.h" #define GET_WIDGET(x) (_gtk_builder_get_widget (data->builder, (x))) #define _OPEN_IN_BROWSER_RESPONSE 1 enum { ACCOUNT_DATA_COLUMN, ACCOUNT_NAME_COLUMN }; enum { PHOTOSET_DATA_COLUMN, PHOTOSET_ICON_COLUMN, PHOTOSET_TITLE_COLUMN, PHOTOSET_N_PHOTOS_COLUMN }; typedef struct { FlickrServer *server; GthBrowser *browser; GSettings *settings; GthFileData *location; GList *file_list; GtkBuilder *builder; GtkWidget *dialog; GtkWidget *list_view; GtkWidget *progress_dialog; GtkWidget *photoset_combobox; FlickrService *service; GList *photosets; FlickrPhotoset *photoset; GList *photos_ids; GCancellable *cancellable; } DialogData; static void destroy_dialog (DialogData *data) { if (data->dialog != NULL) gtk_widget_destroy (data->dialog); if (data->service != NULL) gth_task_completed (GTH_TASK (data->service), NULL); _g_object_unref (data->cancellable); _g_string_list_free (data->photos_ids); _g_object_unref (data->photoset); _g_object_list_unref (data->photosets); _g_object_unref (data->service); gtk_widget_destroy (data->progress_dialog); _g_object_unref (data->builder); _g_object_list_unref (data->file_list); _g_object_unref (data->location); g_object_unref (data->settings); g_free (data); } static void completed_messagedialog_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_CLOSE: gtk_widget_destroy (GTK_WIDGET (dialog)); gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_DELETE_EVENT); break; case _OPEN_IN_BROWSER_RESPONSE: { OAuthAccount *account; char *url = NULL; GError *error = NULL; gtk_widget_destroy (GTK_WIDGET (dialog)); account = web_service_get_current_account (WEB_SERVICE (data->service)); if (data->photoset == NULL) { GString *ids; GList *scan; ids = g_string_new (""); for (scan = data->photos_ids; scan; scan = scan->next) { if (scan != data->photos_ids) g_string_append (ids, ","); g_string_append (ids, (char *) scan->data); } url = g_strconcat (data->server->url, "/photos/upload/edit/?ids=", ids->str, NULL); g_string_free (ids, TRUE); } else if (data->photoset->url != NULL) url = g_strdup (data->photoset->url); else if (data->photoset->id != NULL) url = g_strconcat (data->server->url, "/photos/", account->id, "/sets/", data->photoset->id, NULL); if ((url != NULL) && ! gtk_show_uri_on_window (GTK_WINDOW (data->browser), url, GDK_CURRENT_TIME, &error)) { 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_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_DELETE_EVENT); g_free (url); } break; default: break; } } static void export_completed_with_success (DialogData *data) { GtkWidget *dialog; gth_task_dialog (GTH_TASK (data->service), TRUE, NULL); dialog = _gtk_message_dialog_new (GTK_WINDOW (data->browser), GTK_DIALOG_MODAL, NULL, _("Files successfully uploaded to the server."), NULL, _GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE, _("_Open in the Browser"), _OPEN_IN_BROWSER_RESPONSE, NULL); g_signal_connect (dialog, "delete-event", G_CALLBACK (gtk_true), NULL); g_signal_connect (dialog, "response", G_CALLBACK (completed_messagedialog_response_cb), data); gtk_window_present (GTK_WINDOW (dialog)); } static void add_photos_to_photoset_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { DialogData *data = user_data; GError *error = NULL; if (! flickr_service_add_photos_to_set_finish (FLICKR_SERVICE (source_object), result, &error)) { _gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not create the album"), error); g_clear_error (&error); gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_DELETE_EVENT); return; } export_completed_with_success (data); } static void add_photos_to_photoset (DialogData *data) { flickr_service_add_photos_to_set (data->service, data->photoset, data->photos_ids, data->cancellable, add_photos_to_photoset_ready_cb, data); } static void create_photoset_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { DialogData *data = user_data; GError *error = NULL; char *primary; primary = g_strdup (data->photoset->primary); g_object_unref (data->photoset); data->photoset = flickr_service_create_photoset_finish (FLICKR_SERVICE (source_object), result, &error); if (error != NULL) { _gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not create the album"), error); g_clear_error (&error); gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_DELETE_EVENT); } else { flickr_photoset_set_primary (data->photoset, primary); add_photos_to_photoset (data); } g_free (primary); } static void post_photos_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { DialogData *data = user_data; GError *error = NULL; data->photos_ids = flickr_service_post_photos_finish (FLICKR_SERVICE (source_object), result, &error); if (error != NULL) { _gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not upload the files"), error); g_clear_error (&error); gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_DELETE_EVENT); return; } if (data->photoset == NULL) { export_completed_with_success (data); return; } /* create the photoset if it doesn't exists */ if (data->photoset->id == NULL) { char *first_id; first_id = data->photos_ids->data; flickr_photoset_set_primary (data->photoset, first_id); flickr_service_create_photoset (data->service, data->photoset, data->cancellable, create_photoset_ready_cb, data); } else add_photos_to_photoset (data); } static int find_photoset_by_title (FlickrPhotoset *photoset, const char *name) { return g_strcmp0 (photoset->title, name); } static void export_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->list_view), (DataFunc) destroy_dialog, data); break; case GTK_RESPONSE_OK: { const char *photoset_title; GList *file_list; int max_width; int max_height; gtk_widget_hide (data->dialog); gth_task_dialog (GTH_TASK (data->service), FALSE, NULL); data->photoset = NULL; photoset_title = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (data->photoset_combobox)))); if ((photoset_title != NULL) && (g_strcmp0 (photoset_title, "") != 0)) { GList *link; link = g_list_find_custom (data->photosets, photoset_title, (GCompareFunc) find_photoset_by_title); if (link != NULL) data->photoset = g_object_ref (link->data); if (data->photoset == NULL) { data->photoset = flickr_photoset_new (); flickr_photoset_set_title (data->photoset, photoset_title); } } file_list = gth_file_data_list_to_file_list (data->file_list); max_width = -1; max_height = -1; if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("resize_checkbutton")))) { int idx = gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("resize_combobox"))); max_width = ImageSizeValues[idx].width; max_height = ImageSizeValues[idx].height; } g_settings_set_int (data->settings, PREF_FLICKR_RESIZE_WIDTH, max_width); g_settings_set_int (data->settings, PREF_FLICKR_RESIZE_HEIGHT, max_height); flickr_service_post_photos (data->service, gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("privacy_combobox"))), gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("safety_combobox"))), gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("hidden_checkbutton"))), max_width, max_height, file_list, data->cancellable, post_photos_ready_cb, data); _g_object_list_unref (file_list); } break; default: break; } } static void update_account_list (DialogData *data) { int current_account_idx; OAuthAccount *current_account; int idx; GList *scan; GtkTreeIter iter; char *free_space; 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); free_space = g_format_size (FLICKR_ACCOUNT (current_account)->max_bandwidth - FLICKR_ACCOUNT (current_account)->used_bandwidth); gtk_label_set_text (GTK_LABEL (GET_WIDGET ("free_space_label")), free_space); g_free (free_space); } static void authentication_accounts_changed_cb (WebService *service, gpointer user_data) { update_account_list ((DialogData *) user_data); } static void photoset_list_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { DialogData *data = user_data; GError *error = NULL; GList *scan; _g_object_list_unref (data->photosets); data->photosets = flickr_service_list_photosets_finish (FLICKR_SERVICE (source_object), 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_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_DELETE_EVENT); return; } gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("photoset_liststore"))); for (scan = data->photosets; scan; scan = scan->next) { FlickrPhotoset *photoset = scan->data; char *n_photos; GtkTreeIter iter; n_photos = g_strdup_printf ("(%d)", photoset->n_photos); gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("photoset_liststore")), &iter); gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("photoset_liststore")), &iter, PHOTOSET_DATA_COLUMN, photoset, PHOTOSET_ICON_COLUMN, "file-catalog-symbolic", PHOTOSET_TITLE_COLUMN, photoset->title, PHOTOSET_N_PHOTOS_COLUMN, n_photos, -1); g_free (n_photos); } gtk_dialog_set_response_sensitive (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK, TRUE); 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); flickr_service_list_photosets (data->service, data->cancellable, photoset_list_ready_cb, 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), OAUTH_ACCOUNT (account)); g_object_unref (account); } static void update_sensitivity (DialogData *data) { gtk_widget_set_sensitive (GET_WIDGET ("resize_combobox"), gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("resize_checkbutton")))); } static void resize_checkbutton_toggled_cb (GtkToggleButton *button, gpointer user_data) { update_sensitivity (user_data); } void dlg_export_to_flickr (FlickrServer *server, GthBrowser *browser, GList *file_list) { DialogData *data; GList *scan; int n_total; goffset total_size; char *total_size_formatted; char *text; char *title; data = g_new0 (DialogData, 1); data->server = server; data->browser = browser; data->settings = g_settings_new (PIX_FLICKR_SCHEMA); data->location = gth_file_data_dup (gth_browser_get_location_data (browser)); data->builder = _gtk_builder_new_from_file ("export-to-flickr.ui", "flicker_utils"); data->cancellable = g_cancellable_new (); data->dialog = g_object_new (GTK_TYPE_DIALOG, "transient-for", GTK_WINDOW (browser), "modal", FALSE, "destroy-with-parent", FALSE, "use-header-bar", _gtk_settings_get_dialogs_use_header (), NULL); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (data->dialog))), _gtk_builder_get_widget (data->builder, "dialog_content")); gtk_dialog_add_buttons (GTK_DIALOG (data->dialog), _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL, _GTK_LABEL_UPLOAD, GTK_RESPONSE_OK, NULL); _gtk_dialog_add_class_to_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK, GTK_STYLE_CLASS_SUGGESTED_ACTION); { GtkCellLayout *cell_layout; GtkCellRenderer *renderer; data->photoset_combobox = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL (GET_WIDGET ("photoset_liststore"))); gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (data->photoset_combobox), PHOTOSET_TITLE_COLUMN); gtk_widget_show (data->photoset_combobox); gtk_container_add (GTK_CONTAINER (GET_WIDGET ("photoset_combobox_container")), data->photoset_combobox); cell_layout = GTK_CELL_LAYOUT (data->photoset_combobox); gtk_cell_layout_clear (cell_layout); 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", PHOTOSET_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", PHOTOSET_TITLE_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", PHOTOSET_N_PHOTOS_COLUMN, NULL); } data->file_list = NULL; n_total = 0; total_size = 0; for (scan = file_list; scan; scan = scan->next) { GthFileData *file_data = scan->data; const char *mime_type; mime_type = gth_file_data_get_mime_type (file_data); if (g_content_type_equals (mime_type, "image/bmp") || g_content_type_equals (mime_type, "image/gif") || g_content_type_equals (mime_type, "image/jpeg") || g_content_type_equals (mime_type, "image/png")) { total_size += g_file_info_get_size (file_data->info); n_total++; data->file_list = g_list_prepend (data->file_list, g_object_ref (file_data)); } } data->file_list = g_list_reverse (data->file_list); if (data->file_list == NULL) { GError *error; error = g_error_new_literal (GTH_ERROR, GTH_ERROR_GENERIC, _("No valid file selected.")); _gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not export the files"), error); g_clear_error (&error); gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_DELETE_EVENT); return; } total_size_formatted = g_format_size (total_size); text = g_strdup_printf (g_dngettext (NULL, "%d file (%s)", "%d files (%s)", n_total), n_total, total_size_formatted); gtk_label_set_text (GTK_LABEL (GET_WIDGET ("images_info_label")), text); g_free (text); g_free (total_size_formatted); _gtk_window_resize_to_fit_screen_height (data->dialog, 500); /* Set the widget data */ data->list_view = gth_file_list_new (gth_grid_view_new (), GTH_FILE_LIST_MODE_NO_SELECTION, FALSE); gth_file_list_set_thumb_size (GTH_FILE_LIST (data->list_view), 112); gth_file_list_enable_thumbs (GTH_FILE_LIST (data->list_view), TRUE); gth_file_list_set_ignore_hidden (GTH_FILE_LIST (data->list_view), TRUE); gth_file_list_set_caption (GTH_FILE_LIST (data->list_view), "none"); gth_file_list_set_sort_func (GTH_FILE_LIST (data->list_view), gth_main_get_sort_type ("file::name")->cmp_func, FALSE); gtk_widget_show (data->list_view); gtk_box_pack_start (GTK_BOX (GET_WIDGET ("images_box")), data->list_view, TRUE, TRUE, 0); gth_file_list_set_files (GTH_FILE_LIST (data->list_view), data->file_list); gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (data->photoset_combobox))), _g_file_info_get_edit_name (data->location->info)); gtk_dialog_set_response_sensitive (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK, FALSE); title = g_strdup_printf (_("Export to %s"), data->server->name); gtk_window_set_title (GTK_WINDOW (data->dialog), title); g_free (title); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("resize_checkbutton")), g_settings_get_int (data->settings, PREF_FLICKR_RESIZE_WIDTH) != -1); _gtk_combo_box_add_image_sizes (GTK_COMBO_BOX (GET_WIDGET ("resize_combobox")), g_settings_get_int (data->settings, PREF_FLICKR_RESIZE_WIDTH), g_settings_get_int (data->settings, PREF_FLICKR_RESIZE_HEIGHT)); /* Set the signals handlers. */ g_signal_connect (data->dialog, "delete-event", G_CALLBACK (gtk_true), NULL); g_signal_connect (data->dialog, "response", G_CALLBACK (export_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 ("resize_checkbutton"), "toggled", G_CALLBACK (resize_checkbutton_toggled_cb), data); update_sensitivity (data); data->service = flickr_service_new (server, 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), GTH_TASK_FLAGS_DEFAULT); web_service_autoconnect (WEB_SERVICE (data->service)); }