[glom] Show a progress bar while loading an image



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]