[glom] Show a progress bar while loading an image
- From: Armin Burgmeier <arminb src gnome org>
- To: svn-commits-list gnome org
- Subject: [glom] Show a progress bar while loading an image
- Date: Thu, 7 May 2009 14:00:38 -0400 (EDT)
commit e2bca82f6e68c8cf647ac9484dab1f7866eb07ce
Author: Armin Burgmeier <armin arbur net>
Date: Wed May 6 18:00:36 2009 +0200
Show a progress bar while loading an image
* glom/glom.glade:
* glom/utility_widgets/dialog_image_progress.h:
* glom/utility_widgets/dialog_image_progress.cc:
* glom/utility_widgets/Makefile.am: Added a dialog which loads an
image and shows progress of the operation.
* glom/utility_widgets/imageglom.h:
* glom/utility_widgets/imageglom.cc: Use this dialog when the user
selects an image to load, to indicate progress for large images.
---
ChangeLog | 12 ++
glom/glom.glade | 55 ++++++++-
glom/utility_widgets/Makefile.am | 1 +
glom/utility_widgets/dialog_image_progress.cc | 170 +++++++++++++++++++++++++
glom/utility_widgets/dialog_image_progress.h | 67 ++++++++++
glom/utility_widgets/imageglom.cc | 52 ++++----
glom/utility_widgets/imageglom.h | 1 +
7 files changed, 325 insertions(+), 33 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 9fd2d39..f6b0882 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2009-05-07 Armin Burgmeier <armin arbur net>
+
+ * glom/glom.glade:
+ * glom/utility_widgets/dialog_image_progress.h:
+ * glom/utility_widgets/dialog_image_progress.cc:
+ * glom/utility_widgets/Makefile.am: Added a dialog which loads an
+ image and shows progress of the operation.
+
+ * glom/utility_widgets/imageglom.h:
+ * glom/utility_widgets/imageglom.cc: Use this dialog when the user
+ selects an image to load, to indicate progress for large images.
+
2009-05-05 Armin Burgmeier <armin arbur net>
* glom/libglom/sharedptr.h: Added operator!=.
diff --git a/glom/glom.glade b/glom/glom.glade
index e0f3b9d..2453d83 100644
--- a/glom/glom.glade
+++ b/glom/glom.glade
@@ -173,7 +173,6 @@
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="stock">gtk-ok</property>
- <property name="icon-size">4</property>
</object>
<packing>
<property name="expand">False</property>
@@ -661,7 +660,6 @@
<object class="GtkImage" id="image13">
<property name="visible">True</property>
<property name="stock">gtk-ok</property>
- <property name="icon-size">4</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1466,7 +1464,6 @@
<object class="GtkImage" id="image6">
<property name="visible">True</property>
<property name="stock">gtk-convert</property>
- <property name="icon-size">4</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1630,7 +1627,6 @@ The data in the field was not recognized. Please try to correct the data or reve
<object class="GtkImage" id="image5">
<property name="visible">True</property>
<property name="stock">gtk-undo</property>
- <property name="icon-size">4</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1805,4 +1801,55 @@ The data in the field was not recognized. Please try to correct the data or reve
<property name="page_increment">10</property>
</object>
<object class="GtkTextBuffer" id="textbuffer1"/>
+ <object class="GtkDialog" id="dialog_image_progress">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Loading image</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="default_width">640</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox7">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkProgressBar" id="image_loading_progress_bar">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area7">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label" translatable="yes">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">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button1</action-widget>
+ </action-widgets>
+ </object>
</interface>
diff --git a/glom/utility_widgets/Makefile.am b/glom/utility_widgets/Makefile.am
index af55df0..fc3fe14 100644
--- a/glom/utility_widgets/Makefile.am
+++ b/glom/utility_widgets/Makefile.am
@@ -32,6 +32,7 @@ libutility_widgets_a_SOURCES = alignment_justified.cc alignment_justified.h \
labelglom.h labelglom.cc \
dialog_choose_id.cc dialog_choose_id.h \
dialog_choose_date.cc dialog_choose_date.h \
+ dialog_image_progress.cc dialog_image_progress.h \
checkglom.h checkglom.cc \
layoutwidgetutils.h layoutwidgetutils.cc \
dialog_layoutitem_properties.cc dialog_layoutitem_properties.h \
diff --git a/glom/utility_widgets/dialog_image_progress.cc b/glom/utility_widgets/dialog_image_progress.cc
new file mode 100644
index 0000000..3047281
--- /dev/null
+++ b/glom/utility_widgets/dialog_image_progress.cc
@@ -0,0 +1,170 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2004 Murray Cumming
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "dialog_image_progress.h"
+
+#include <gtkmm/messagedialog.h>
+#include <glibmm/i18n.h>
+
+namespace
+{
+
+// Read the file in chunks of this size:
+const unsigned int CHUNK_SIZE = 2048;
+
+} // anonymous namespace
+
+namespace Glom
+{
+
+Dialog_Image_Progress::Dialog_Image_Progress(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
+: Gtk::Dialog(cobject)
+{
+ builder->get_widget("image_loading_progress_bar", m_progress_bar);
+
+ if(!m_progress_bar)
+ throw std::runtime_error("Missing widgets from glade file for Dialog_Image_Progress");
+}
+
+Dialog_Image_Progress::~Dialog_Image_Progress()
+{
+ if(m_data.get())
+ g_free(m_data->data);
+ if(m_loader)
+ {
+ try
+ {
+ m_loader->close();
+ }
+ catch(const Glib::Error& ex)
+ {
+ // Ignore error, it's normal for close() to through when the image has
+ // not yet been loaded completely, for example when cancelling the
+ // dialog.
+ }
+ }
+
+ // TODO: Cancel outstanding async operations in destructor?
+}
+
+void Dialog_Image_Progress::load(const Glib::ustring& uri)
+{
+ // Can only load one file with data
+ g_assert(!m_data.get());
+
+ m_loader = Gdk::PixbufLoader::create();
+ m_data.reset(new GdaBinary);
+ m_data->data = NULL;
+ m_data->binary_length = 0;
+
+ m_file = Gio::File::create_for_uri(uri);
+ m_progress_bar->set_text(Glib::ustring::compose("Loading %1...", m_file->get_parse_name()));
+
+ try
+ {
+ // Open the file for reading:
+ m_file->read_async(sigc::mem_fun(*this, &Dialog_Image_Progress::on_file_read));
+ }
+ catch(const Glib::Error& ex)
+ {
+ error(ex.what());
+ }
+}
+
+void Dialog_Image_Progress::on_file_read(const Glib::RefPtr<Gio::AsyncResult>& result)
+{
+ try
+ {
+ m_stream = m_file->read_finish(result);
+ // Query size of the file, so that we can show progress:
+ m_stream->query_info_async(sigc::mem_fun(*this, &Dialog_Image_Progress::on_query_info), G_FILE_ATTRIBUTE_STANDARD_SIZE);
+ }
+ catch(const Glib::Error& ex)
+ {
+ error(ex.what());
+ }
+}
+
+void Dialog_Image_Progress::on_query_info(const Glib::RefPtr<Gio::AsyncResult>& result)
+{
+ try
+ {
+ Glib::RefPtr<Gio::FileInfo> info = m_stream->query_info_finish(result);
+ m_data->binary_length = info->get_size();
+ // We need to use the glib allocater here:
+ m_data->data = static_cast<guchar*>(g_try_malloc(m_data->binary_length));
+ if(!m_data->data)
+ error(_("Not enough memory available to load the image"));
+
+ // Read the first chunk from the file
+ m_stream->read_async(m_data->data, std::min<gsize>(CHUNK_SIZE, m_data->binary_length), sigc::bind(sigc::mem_fun(*this, &Dialog_Image_Progress::on_stream_read), 0));
+ }
+ catch(const Glib::Error& ex)
+ {
+ error(ex.what());
+ }
+}
+
+void Dialog_Image_Progress::on_stream_read(const Glib::RefPtr<Gio::AsyncResult>& result, unsigned int offset)
+{
+ try
+ {
+ gssize size = m_stream->read_finish(result);
+ g_assert(size >= 0); // Would have thrown an exception otherwise
+ // Cannot read more data than there is available in the file:
+ g_assert(offset + size <= static_cast<gsize>(m_data->binary_length));
+ // Load image
+ m_loader->write(m_data->data + offset, size);
+ // Set progress
+ m_progress_bar->set_fraction(static_cast<double>(offset + size) / m_data->binary_length);
+ // Read next chunk, if any
+ if(offset + size < static_cast<gsize>(m_data->binary_length))
+ // Even if choose a priority lower than GDK_PRIORITY_REDRAW + 10 for the
+ // read_async we don't see the progressbar progressing while the image
+ // is loading. Therefore we put an idle inbetween.
+ Glib::signal_idle().connect(sigc::bind_return(sigc::bind(sigc::mem_fun(*this, &Dialog_Image_Progress::on_read_next), offset + size), false));
+ else
+ // We are done loading the image, close the progress dialog
+ response(Gtk::RESPONSE_ACCEPT);
+ }
+ catch(const Glib::Error& ex)
+ {
+ error(ex.what());
+ }
+}
+
+void Dialog_Image_Progress::on_read_next(unsigned int at)
+{
+ g_assert(at < static_cast<gsize>(m_data->binary_length));
+
+ m_stream->read_async(m_data->data + at, std::min<gsize>(CHUNK_SIZE, m_data->binary_length - at), sigc::bind(sigc::mem_fun(*this, &Dialog_Image_Progress::on_stream_read), at));
+}
+
+void Dialog_Image_Progress::error(const Glib::ustring& error_message)
+{
+ Gtk::MessageDialog dialog(*this, Glib::ustring::compose(_("Error loading %1"), m_file->get_parse_name()), Gtk::MESSAGE_ERROR);
+ dialog.set_title(_("Error loading image"));
+ dialog.set_secondary_text(error_message);
+
+ dialog.run();
+ response(Gtk::RESPONSE_REJECT);
+}
+
+} // namespace Glom
diff --git a/glom/utility_widgets/dialog_image_progress.h b/glom/utility_widgets/dialog_image_progress.h
new file mode 100644
index 0000000..bd8c71e
--- /dev/null
+++ b/glom/utility_widgets/dialog_image_progress.h
@@ -0,0 +1,67 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2004 Murray Cumming
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GLOM_DIALOG_UTILITY_WIDGETSIMPORT_CSV_PROGRESS_H
+#define GLOM_DIALOG_IMPORT_CSV_PROGRESS_H
+
+#include <gtkmm/dialog.h>
+#include <gtkmm/builder.h>
+#include <gtkmm/progressbar.h>
+#include <gdkmm/pixbufloader.h>
+#include <giomm/file.h>
+#include <giomm/fileinputstream.h>
+#include <libgda/libgda.h>
+#include <memory>
+
+namespace Glom
+{
+
+class Dialog_Image_Progress : public Gtk::Dialog
+{
+public:
+ Dialog_Image_Progress(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder);
+ virtual ~Dialog_Image_Progress();
+
+ void load(const Glib::ustring& uri);
+
+ std::auto_ptr<GdaBinary> get_image_data() { return m_data; }
+ Glib::RefPtr<Gdk::Pixbuf> get_pixbuf() { return m_loader->get_pixbuf(); }
+
+private:
+ void error(const Glib::ustring& error_message);
+
+ void on_file_read(const Glib::RefPtr<Gio::AsyncResult>& result);
+ void on_query_info(const Glib::RefPtr<Gio::AsyncResult>& result);
+ void on_stream_read(const Glib::RefPtr<Gio::AsyncResult>& result, unsigned int offset);
+ void on_read_next(unsigned int at);
+
+ Glib::RefPtr<Gdk::PixbufLoader> m_loader;
+ std::auto_ptr<GdaBinary> m_data;
+ Gtk::ProgressBar* m_progress_bar;
+
+ Glib::RefPtr<Gio::File> m_file;
+ Glib::RefPtr<Gio::FileInputStream> m_stream;
+ unsigned int m_stream_size;
+};
+
+} //namespace Glom
+
+#endif //GLOM_DIALOG_IMPORT_CSV_PROGRESS_H
+
diff --git a/glom/utility_widgets/imageglom.cc b/glom/utility_widgets/imageglom.cc
index 384a7f9..13db9da 100644
--- a/glom/utility_widgets/imageglom.cc
+++ b/glom/utility_widgets/imageglom.cc
@@ -22,6 +22,7 @@
#include <glibmm/i18n.h>
#include <glom/application.h>
#include <glom/utils_ui.h>
+#include <glom/glade_utils.h>
#include <libglom/data_structure/glomconversions.h>
//#include <sstream> //For stringstream
@@ -405,44 +406,37 @@ void ImageGlom::on_menupopup_activate_select_file()
if((response != Gtk::RESPONSE_CANCEL) && (response != Gtk::RESPONSE_DELETE_EVENT))
{
- const std::string filepath = dialog.get_filename();
- if(!filepath.empty())
+ const Glib::ustring uri = dialog.get_uri();
+ if(!uri.empty())
{
- // TODO: We might want to show a progress dialog here, and read
- // the data asynchronously
- // We use the C API here to avoid unnecessary copying
- gchar* data;
- gsize length;
- GError* error = NULL;
- if(!g_file_get_contents(filepath.c_str(), &data, &length, &error))
+ Dialog_Image_Progress* dialog;
+ Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom.glade"), "dialog_image_progress");
+ builder->get_widget_derived("dialog_image_progress", dialog);
+ if(dialog)
{
- App_Glom* pApp = get_application();
- if(pApp)
- Frame_Glom::show_ok_dialog(_("Image loading failed"), _("The image file could not be opened:\n") + Glib::ustring(error->message), *pApp, Gtk::MESSAGE_ERROR);
- g_error_free(error);
- }
- else
- {
- GdaBinary* bin = g_new(GdaBinary, 1);
- bin->data = reinterpret_cast<guchar*>(data);
- bin->binary_length = length;
+ // Automatically delete the dialog when we no longer need it:
+ std::auto_ptr<Gtk::Dialog> dialog_keeper(dialog);
- m_original_data = Gnome::Gda::Value();
- m_original_data.Glib::ValueBase::init(GDA_TYPE_BINARY);
- gda_value_take_binary(m_original_data.gobj(), bin);
+ App_Glom* pApp = get_application();
+ dialog->set_transient_for(*pApp);
+ dialog->load(uri);
- m_pixbuf_original = Utils::get_pixbuf_for_gda_value(m_original_data);
- if(m_pixbuf_original)
+ if(dialog->run() == Gtk::RESPONSE_ACCEPT)
{
+ GdaBinary* bin = g_new(GdaBinary, 1);
+ std::auto_ptr<GdaBinary> image_data = dialog->get_image_data();
+ bin->data = image_data->data;
+ bin->binary_length = image_data->binary_length;
+
+ m_original_data = Gnome::Gda::Value();
+ m_original_data.Glib::ValueBase::init(GDA_TYPE_BINARY);
+ gda_value_take_binary(m_original_data.gobj(), bin);
+
+ m_pixbuf_original = dialog->get_pixbuf();
m_image.set(m_pixbuf_original); //Load the image.
scale();
signal_edited().emit();
}
- else
- {
- m_original_data = Gnome::Gda::Value();
- g_warning("ImageGlom::on_menupopup_activate_select_file(): file load failed.");
- }
}
}
}
diff --git a/glom/utility_widgets/imageglom.h b/glom/utility_widgets/imageglom.h
index 3367570..7ac4ebc 100644
--- a/glom/utility_widgets/imageglom.h
+++ b/glom/utility_widgets/imageglom.h
@@ -24,6 +24,7 @@
#include <gtkmm.h>
#include <libglom/data_structure/field.h>
#include "layoutwidgetfield.h"
+#include "dialog_image_progress.h"
#include <gtkmm/builder.h>
namespace Glom
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]