[gtkhtml] Add preview in Insert Image dialog.



commit 1ee3e676bb7b342770fd25fbd9ff88856b9b047e
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Jan 28 01:02:48 2011 -0500

    Add preview in Insert Image dialog.
    
    Also restrict the files shown to images only.

 components/editor/Makefile.am                    |    2 +
 components/editor/gtkhtml-editor-actions.c       |   44 ++--
 components/editor/gtkhtml-editor-private.c       |   30 --
 components/editor/gtkhtml-editor-private.h       |    4 +-
 components/editor/gtkhtml-image-chooser-dialog.c |  325 ++++++++++++++++++++++
 components/editor/gtkhtml-image-chooser-dialog.h |   73 +++++
 6 files changed, 427 insertions(+), 51 deletions(-)
---
diff --git a/components/editor/Makefile.am b/components/editor/Makefile.am
index b3e642d..c1b8e42 100644
--- a/components/editor/Makefile.am
+++ b/components/editor/Makefile.am
@@ -51,6 +51,8 @@ libgtkhtml_editor_4_0_la_SOURCES = \
 	gtkhtml-face-chooser-menu.h		\
 	gtkhtml-face-tool-button.c		\
 	gtkhtml-face-tool-button.h		\
+	gtkhtml-image-chooser-dialog.c		\
+	gtkhtml-image-chooser-dialog.h		\
 	gtkhtml-spell-dialog.c			\
 	gtkhtml-spell-dialog.h			\
 	gtkhtml-spell-checker.c			\
diff --git a/components/editor/gtkhtml-editor-actions.c b/components/editor/gtkhtml-editor-actions.c
index bd216c6..7d9921d 100644
--- a/components/editor/gtkhtml-editor-actions.c
+++ b/components/editor/gtkhtml-editor-actions.c
@@ -136,21 +136,6 @@
  *****************************************************************************/
 
 static void
-insert_image_response_cb (GtkFileChooser *file_chooser,
-                          gint response,
-                          GtkhtmlEditor *editor)
-{
-	gchar *uri;
-
-	if (response != GTK_RESPONSE_OK)
-		return;
-
-	uri = gtk_file_chooser_get_uri (file_chooser);
-	gtkhtml_editor_insert_image (editor, uri);
-	g_free (uri);
-}
-
-static void
 insert_html_file_ready_cb (GFile *file,
                            GAsyncResult *result,
                            GtkhtmlEditor *editor)
@@ -631,9 +616,32 @@ static void
 action_insert_image_cb (GtkAction *action,
                         GtkhtmlEditor *editor)
 {
-	gtkhtml_editor_insert_file (
-		editor, _("Insert Image"),
-		G_CALLBACK (insert_image_response_cb));
+	GtkWidget *dialog;
+	GFile *file;
+
+	dialog = gtkhtml_image_chooser_dialog_new (
+		_("Insert Image"), GTK_WINDOW (editor));
+
+	g_object_bind_property (
+		editor, "current-folder",
+		dialog, "current-folder",
+		G_BINDING_BIDIRECTIONAL |
+		G_BINDING_SYNC_CREATE);
+
+	file = gtkhtml_image_chooser_dialog_run (
+		GTKHTML_IMAGE_CHOOSER_DIALOG (dialog));
+
+	if (file != NULL) {
+		gchar *uri;
+
+		uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+		gtkhtml_editor_insert_image (editor, uri);
+		g_free (uri);
+
+		g_object_unref (file);
+	}
+
+	gtk_widget_destroy (dialog);
 }
 
 static void
diff --git a/components/editor/gtkhtml-editor-private.c b/components/editor/gtkhtml-editor-private.c
index 1c420e9..ca59875 100644
--- a/components/editor/gtkhtml-editor-private.c
+++ b/components/editor/gtkhtml-editor-private.c
@@ -482,36 +482,6 @@ gtkhtml_editor_find_data_file (const gchar *basename)
 	return NULL;  /* never gets here */
 }
 
-gint
-gtkhtml_editor_insert_file (GtkhtmlEditor *editor,
-                            const gchar *title,
-                            GCallback response_cb)
-{
-	GtkWidget *dialog;
-	gint response;
-
-	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), GTK_RESPONSE_CANCEL);
-	g_return_val_if_fail (response_cb != NULL, GTK_RESPONSE_CANCEL);
-
-	dialog = gtk_file_chooser_dialog_new (
-		title, GTK_WINDOW (editor),
-		GTK_FILE_CHOOSER_ACTION_OPEN,
-		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-		GTK_STOCK_OPEN, GTK_RESPONSE_OK,
-		NULL);
-
-	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
-	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-
-	g_signal_connect (dialog, "response", response_cb, editor);
-
-	response = gtkhtml_editor_file_chooser_dialog_run (editor, dialog);
-
-	gtk_widget_destroy (dialog);
-
-	return response;
-}
-
 GFile *
 gtkhtml_editor_run_open_dialog (GtkhtmlEditor *editor,
                                 const gchar *title,
diff --git a/components/editor/gtkhtml-editor-private.h b/components/editor/gtkhtml-editor-private.h
index d1212c2..7197915 100644
--- a/components/editor/gtkhtml-editor-private.h
+++ b/components/editor/gtkhtml-editor-private.h
@@ -36,6 +36,7 @@
 #include "gtkhtml-combo-box.h"
 #include "gtkhtml-face-action.h"
 #include "gtkhtml-face-chooser.h"
+#include "gtkhtml-image-chooser-dialog.h"
 #include "gtkhtml-spell-dialog.h"
 
 /* GtkHTML internals */
@@ -203,9 +204,6 @@ void		gtkhtml_editor_private_finalize	(GtkhtmlEditor *editor);
 
 void		gtkhtml_editor_actions_init	(GtkhtmlEditor *editor);
 gchar *		gtkhtml_editor_find_data_file	(const gchar *basename);
-gint		gtkhtml_editor_insert_file	(GtkhtmlEditor *editor,
-						 const gchar *title,
-						 GCallback response_cb);
 GFile *		gtkhtml_editor_run_open_dialog	(GtkhtmlEditor *editor,
 						 const gchar *title,
 						 GtkCallback customize_func,
diff --git a/components/editor/gtkhtml-image-chooser-dialog.c b/components/editor/gtkhtml-image-chooser-dialog.c
new file mode 100644
index 0000000..7fc8b1c
--- /dev/null
+++ b/components/editor/gtkhtml-image-chooser-dialog.c
@@ -0,0 +1,325 @@
+/*
+ * gtkhtml-image-chooser-dialog.c
+ *
+ * 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 "gtkhtml-image-chooser-dialog.h"
+
+#define GTKHTML_IMAGE_CHOOSER_DIALOG_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_IMAGE_CHOOSER_DIALOG, \
+	GtkhtmlImageChooserDialogPrivate))
+
+#define PREVIEW_WIDTH	256
+#define PREVIEW_HEIGHT	256
+
+typedef struct _Context Context;
+
+struct _GtkhtmlImageChooserDialogPrivate {
+	GCancellable *cancellable;
+	gchar *current_folder;
+};
+
+struct _Context {
+	GtkFileChooser *file_chooser;
+	GCancellable *cancellable;
+};
+
+enum {
+	PROP_0,
+	PROP_CURRENT_FOLDER
+};
+
+G_DEFINE_TYPE (
+	GtkhtmlImageChooserDialog,
+	gtkhtml_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)
+{
+	GtkhtmlImageChooserDialogPrivate *priv;
+	GtkWidget *preview_widget;
+	GFile *preview_file;
+	Context *context;
+
+	priv = GTKHTML_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_set_property (GObject *object,
+                                   guint property_id,
+                                   const GValue *value,
+                                   GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_CURRENT_FOLDER:
+			gtkhtml_image_chooser_dialog_set_current_folder (
+				GTKHTML_IMAGE_CHOOSER_DIALOG (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+image_chooser_dialog_get_property (GObject *object,
+                                   guint property_id,
+                                   GValue *value,
+                                   GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_CURRENT_FOLDER:
+			g_value_set_string (
+				value,
+				gtkhtml_image_chooser_dialog_get_current_folder (
+				GTKHTML_IMAGE_CHOOSER_DIALOG (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+image_chooser_dialog_dispose (GObject *object)
+{
+	GtkhtmlImageChooserDialogPrivate *priv;
+
+	priv = GTKHTML_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 (gtkhtml_image_chooser_dialog_parent_class)->
+		dispose (object);
+}
+
+static void
+image_chooser_dialog_finalize (GObject *object)
+{
+	GtkhtmlImageChooserDialogPrivate *priv;
+
+	priv = GTKHTML_IMAGE_CHOOSER_DIALOG_GET_PRIVATE (object);
+
+	g_free (priv->current_folder);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (gtkhtml_image_chooser_dialog_parent_class)->
+		finalize (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
+gtkhtml_image_chooser_dialog_class_init (GtkhtmlImageChooserDialogClass *class)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (
+		class, sizeof (GtkhtmlImageChooserDialogPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = image_chooser_dialog_set_property;
+	object_class->get_property = image_chooser_dialog_get_property;
+	object_class->dispose = image_chooser_dialog_dispose;
+	object_class->finalize = image_chooser_dialog_finalize;
+	object_class->constructed = image_chooser_dialog_constructed;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CURRENT_FOLDER,
+		g_param_spec_string (
+			"current-folder",
+			"Current Folder",
+			"The initial folder for file chooser dialogs",
+			g_get_home_dir (),
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+}
+
+static void
+gtkhtml_image_chooser_dialog_init (GtkhtmlImageChooserDialog *dialog)
+{
+	dialog->priv = GTKHTML_IMAGE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
+
+	g_signal_connect (
+		dialog, "update-preview",
+		G_CALLBACK (image_chooser_dialog_update_preview), NULL);
+}
+
+GtkWidget *
+gtkhtml_image_chooser_dialog_new (const gchar *title,
+                                  GtkWindow *parent)
+{
+	return g_object_new (
+		GTKHTML_TYPE_IMAGE_CHOOSER_DIALOG,
+		"action", GTK_FILE_CHOOSER_ACTION_OPEN,
+		"title", title,
+		"transient-for", parent, NULL);
+}
+
+GFile *
+gtkhtml_image_chooser_dialog_run (GtkhtmlImageChooserDialog *dialog)
+{
+	GtkFileChooser *file_chooser;
+	gchar *uri;
+
+	g_return_val_if_fail (GTKHTML_IS_IMAGE_CHOOSER_DIALOG (dialog), NULL);
+
+	file_chooser = GTK_FILE_CHOOSER (dialog);
+
+	uri = (gchar *)
+		gtkhtml_image_chooser_dialog_get_current_folder (dialog);
+	if (uri != NULL)
+		gtk_file_chooser_set_current_folder_uri (file_chooser, uri);
+
+	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
+		return NULL;
+
+	uri = gtk_file_chooser_get_current_folder_uri (file_chooser);
+	gtkhtml_image_chooser_dialog_set_current_folder (dialog, uri);
+	g_free (uri);
+
+	return gtk_file_chooser_get_file (file_chooser);
+}
+
+const gchar *
+gtkhtml_image_chooser_dialog_get_current_folder (GtkhtmlImageChooserDialog *dialog)
+{
+	g_return_val_if_fail (GTKHTML_IS_IMAGE_CHOOSER_DIALOG (dialog), NULL);
+
+	return dialog->priv->current_folder;
+}
+
+void
+gtkhtml_image_chooser_dialog_set_current_folder (GtkhtmlImageChooserDialog *dialog,
+                                                 const gchar *current_folder)
+{
+	g_return_if_fail (GTKHTML_IS_IMAGE_CHOOSER_DIALOG (dialog));
+
+	if (current_folder == NULL)
+		current_folder = g_get_home_dir ();
+
+	g_free (dialog->priv->current_folder);
+	dialog->priv->current_folder = g_strdup (current_folder);
+
+	g_object_notify (G_OBJECT (dialog), "current-folder");
+}
diff --git a/components/editor/gtkhtml-image-chooser-dialog.h b/components/editor/gtkhtml-image-chooser-dialog.h
new file mode 100644
index 0000000..4f2e077
--- /dev/null
+++ b/components/editor/gtkhtml-image-chooser-dialog.h
@@ -0,0 +1,73 @@
+/*
+ * gtkhtml-image-chooser-dialog.h
+ *
+ * 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.
+ */
+
+#ifndef GTKHTML_IMAGE_CHOOSER_DIALOG_H
+#define GTKHTML_IMAGE_CHOOSER_DIALOG_H
+
+#include "gtkhtml-editor-common.h"
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_IMAGE_CHOOSER_DIALOG \
+	(gtkhtml_image_chooser_dialog_get_type ())
+#define GTKHTML_IMAGE_CHOOSER_DIALOG(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_IMAGE_CHOOSER_DIALOG, GtkhtmlImageChooserDialog))
+#define GTKHTML_IMAGE_CHOOSER_DIALOG_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_IMAGE_CHOOSER_DIALOG, GtkhtmlImageChooserDialogClass))
+#define GTKHTML_IS_IMAGE_CHOOSER_DIALOG(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_IMAGE_CHOOSER_DIALOG))
+#define GTKHTML_IS_IMAGE_CHOOSER_DIALOG_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_IMAGE_CHOOSER_DIALOG))
+#define GTKHTML_IMAGE_CHOOSER_DIALOG_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_IMAGE_CHOOSER_DIALOG, GtkhtmlImageChooserDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlImageChooserDialog GtkhtmlImageChooserDialog;
+typedef struct _GtkhtmlImageChooserDialogClass GtkhtmlImageChooserDialogClass;
+typedef struct _GtkhtmlImageChooserDialogPrivate GtkhtmlImageChooserDialogPrivate;
+
+struct _GtkhtmlImageChooserDialog {
+	GtkFileChooserDialog parent;
+	GtkhtmlImageChooserDialogPrivate *priv;
+};
+
+struct _GtkhtmlImageChooserDialogClass {
+	GtkFileChooserDialogClass parent_class;
+};
+
+GType		gtkhtml_image_chooser_dialog_get_type
+					(void) G_GNUC_CONST;
+GtkWidget *	gtkhtml_image_chooser_dialog_new
+					(const gchar *title,
+					 GtkWindow *parent);
+GFile *		gtkhtml_image_chooser_dialog_run
+					(GtkhtmlImageChooserDialog *dialog);
+const gchar *	gtkhtml_image_chooser_dialog_get_current_folder
+					(GtkhtmlImageChooserDialog *dialog);
+void		gtkhtml_image_chooser_dialog_set_current_folder
+					(GtkhtmlImageChooserDialog *dialog,
+					 const gchar *current_folder);
+
+G_END_DECLS
+
+#endif /* GTKHTML_IMAGE_CHOOSER_DIALOG_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]