/*
* e-image-chooser-dialog.c
*
* Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* 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 Lesser General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "e-image-chooser-dialog.h"
#define E_IMAGE_CHOOSER_DIALOG_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_IMAGE_CHOOSER_DIALOG, EImageChooserDialogPrivate))
#define PREVIEW_WIDTH 256
#define PREVIEW_HEIGHT 256
typedef struct _Context Context;
struct _EImageChooserDialogPrivate {
GCancellable *cancellable;
};
struct _Context {
GtkFileChooser *file_chooser;
GCancellable *cancellable;
};
G_DEFINE_TYPE (
EImageChooserDialog,
e_image_chooser_dialog,
GTK_TYPE_FILE_CHOOSER_DIALOG)
static void
context_free (Context *context)
{
g_object_unref (context->file_chooser);
g_object_unref (context->cancellable);
g_slice_free (Context, context);
}
static void
image_chooser_dialog_read_cb (GFile *preview_file,
GAsyncResult *result,
Context *context)
{
GdkPixbuf *pixbuf;
GtkWidget *preview_widget;
GFileInputStream *input_stream;
input_stream = g_file_read_finish (preview_file, result, NULL);
/* FIXME Handle errors better, but remember
* to ignore G_IO_ERROR_CANCELLED. */
if (input_stream == NULL)
goto exit;
/* XXX This blocks, but GDK-PixBuf offers no asynchronous
* alternative and I don't want to deal with making GDK
* calls from threads and all the crap that goes with it. */
pixbuf = gdk_pixbuf_new_from_stream_at_scale (
G_INPUT_STREAM (input_stream),
PREVIEW_WIDTH, PREVIEW_HEIGHT, TRUE,
context->cancellable, NULL);
preview_widget = gtk_file_chooser_get_preview_widget (
context->file_chooser);
gtk_file_chooser_set_preview_widget_active (
context->file_chooser, pixbuf != NULL);
gtk_image_set_from_pixbuf (GTK_IMAGE (preview_widget), pixbuf);
if (pixbuf != NULL)
g_object_unref (pixbuf);
g_object_unref (input_stream);
exit:
context_free (context);
}
static void
image_chooser_dialog_update_preview (GtkFileChooser *file_chooser)
{
EImageChooserDialogPrivate *priv;
GtkWidget *preview_widget;
GFile *preview_file;
Context *context;
priv = E_IMAGE_CHOOSER_DIALOG_GET_PRIVATE (file_chooser);
preview_file = gtk_file_chooser_get_preview_file (file_chooser);
preview_widget = gtk_file_chooser_get_preview_widget (file_chooser);
if (priv->cancellable != NULL) {
g_cancellable_cancel (priv->cancellable);
g_object_unref (priv->cancellable);
priv->cancellable = NULL;
}
gtk_image_clear (GTK_IMAGE (preview_widget));
gtk_file_chooser_set_preview_widget_active (file_chooser, FALSE);
if (preview_file == NULL)
return;
priv->cancellable = g_cancellable_new ();
context = g_slice_new0 (Context);
context->file_chooser = g_object_ref (file_chooser);
context->cancellable = g_object_ref (priv->cancellable);
g_file_read_async (
preview_file, G_PRIORITY_LOW,
priv->cancellable, (GAsyncReadyCallback)
image_chooser_dialog_read_cb, context);
g_object_unref (preview_file);
}
static void
image_chooser_dialog_dispose (GObject *object)
{
EImageChooserDialogPrivate *priv;
priv = E_IMAGE_CHOOSER_DIALOG_GET_PRIVATE (object);
if (priv->cancellable != NULL) {
g_cancellable_cancel (priv->cancellable);
g_object_unref (priv->cancellable);
priv->cancellable = NULL;
}
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_image_chooser_dialog_parent_class)->dispose (object);
}
static void
image_chooser_dialog_constructed (GObject *object)
{
GtkFileChooser *file_chooser;
GtkFileFilter *file_filter;
file_chooser = GTK_FILE_CHOOSER (object);
gtk_file_chooser_set_local_only (file_chooser, FALSE);
gtk_dialog_add_button (
GTK_DIALOG (file_chooser),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
gtk_dialog_add_button (
GTK_DIALOG (file_chooser),
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT);
gtk_dialog_set_default_response (
GTK_DIALOG (file_chooser), GTK_RESPONSE_ACCEPT);
file_filter = gtk_file_filter_new ();
gtk_file_filter_add_pixbuf_formats (file_filter);
gtk_file_chooser_set_filter (file_chooser, file_filter);
gtk_file_chooser_set_preview_widget (file_chooser, gtk_image_new ());
}
static void
e_image_chooser_dialog_class_init (EImageChooserDialogClass *class)
{
GObjectClass *object_class;
g_type_class_add_private (
class, sizeof (EImageChooserDialogPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->dispose = image_chooser_dialog_dispose;
object_class->constructed = image_chooser_dialog_constructed;
}
static void
e_image_chooser_dialog_init (EImageChooserDialog *dialog)
{
dialog->priv = E_IMAGE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
g_signal_connect (
dialog, "update-preview",
G_CALLBACK (image_chooser_dialog_update_preview), NULL);
}
GtkWidget *
e_image_chooser_dialog_new (const gchar *title,
GtkWindow *parent)
{
return g_object_new (
E_TYPE_IMAGE_CHOOSER_DIALOG,
"action", GTK_FILE_CHOOSER_ACTION_OPEN,
"title", title,
"transient-for", parent, NULL);
}
GFile *
e_image_chooser_dialog_run (EImageChooserDialog *dialog)
{
GtkFileChooser *file_chooser;
g_return_val_if_fail (E_IS_IMAGE_CHOOSER_DIALOG (dialog), NULL);
file_chooser = GTK_FILE_CHOOSER (dialog);
if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
return NULL;
return gtk_file_chooser_get_file (file_chooser);
}