[solang] Improved thumbnail handling
- From: Debarshi Ray <debarshir src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [solang] Improved thumbnail handling
- Date: Wed, 13 Jan 2010 17:09:23 +0000 (UTC)
commit ee57ba299afef763283cfdde26a0f47d96298974
Author: Debarshi Ray <rishi gnu org>
Date: Wed Dec 30 13:26:10 2009 +0200
Improved thumbnail handling
Do not keep the thumbnail (and other textual data) in
Application::listStore_. Just keep the serial number and PhotoPtr, and
use GtkCellLayoutDataFuncs to set the Gtk::CellRenderers in the
ThumbnailView. New thumbnails are created using
CellRendererThumbnail::create_thumbnail, which is invoked from
CellRendererThumbnail::render_vfunc. This is done to reduce the number
of thumbnails to be created to only those which will actually get
rendered. As a result of this, BrowserRenderer::generate_thumbnails
has been replaced with BrowserRenderer::set_thumbnail_size.
The Thumbnailer is now a singleton and a new signal
Thumbnailer::ready has been added to indicate when it has completed
processing some photos. Application::on_thumbnailer_ready triggers
the "row-changed" signal on those rows of Application::listStore_
which have any of the processed photos.
src/application/application.cpp | 47 +++++++-
src/application/application.h | 3 +
src/application/engine.cpp | 7 -
src/application/engine.h | 6 -
src/common/Makefile.am | 1 +
src/common/singleton.h | 39 ++++++
src/common/thumbnailer.cpp | 17 +++-
src/common/thumbnailer.h | 16 ++-
src/renderer/browser-model-column-record.cpp | 32 +-----
src/renderer/browser-model-column-record.h | 17 ---
src/renderer/browser-renderer.cpp | 168 +++-----------------------
src/renderer/browser-renderer.h | 8 +-
src/renderer/cell-renderer-thumbnail.cpp | 97 +++++++++++++++-
src/renderer/cell-renderer-thumbnail.h | 19 +++
src/renderer/thumbnail-view.cpp | 43 ++++++-
15 files changed, 291 insertions(+), 229 deletions(-)
---
diff --git a/src/application/application.cpp b/src/application/application.cpp
index f3fc401..baf8b55 100644
--- a/src/application/application.cpp
+++ b/src/application/application.cpp
@@ -49,6 +49,7 @@
#include "search-basket.h"
#include "slideshow-renderer.h"
#include "tag-manager.h"
+#include "thumbnailer.h"
namespace Solang
{
@@ -255,6 +256,11 @@ Application::Application(int & argc, char ** & argv) throw() :
&Application::show_progress_dialog));
engine_.photo_import_end().connect(sigc::mem_fun(*this,
&Application::hide_progress_dialog));
+
+ Thumbnailer & thumbnailer = Thumbnailer::instance();
+ thumbnailer.signal_ready().connect(
+ sigc::mem_fun(*this,
+ &Application::on_thumbnailer_ready));
}
Application::~Application() throw()
@@ -420,7 +426,6 @@ Application::add_photo_to_model(const PhotoPtr & photo) throw()
row[model_column_record.get_column_serial()]
= static_cast<guint>(model_path.front());
row[model_column_record.get_column_photo()] = photo;
- row[model_column_record.get_column_pixbuf()] = PixbufPtr(0);
}
void
@@ -499,6 +504,46 @@ Application::on_criteria_changed(PhotoSearchCriteriaList & criteria)
}
void
+Application::on_thumbnailer_ready(PhotoList & photos) const throw()
+{
+ const Gtk::TreeModel::Children children = listStore_->children();
+
+ // Hoping that keeping the bigger loop within the smaller loop
+ // will result in better optimization. In this case,
+ // children.size() is likely to be greater than photos.size().
+
+ for (PhotoList::const_iterator photo_iter = photos.begin();
+ photos.end() != photo_iter;
+ photo_iter++)
+ {
+ for (Gtk::TreeModel::const_iterator model_iter
+ = children.begin();
+ children.end() != model_iter;
+ model_iter++)
+ {
+ Gtk::TreeModel::Row row = *model_iter;
+ BrowserModelColumnRecord model_column_record;
+ const PhotoPtr photo
+ = row[model_column_record.get_column_photo()];
+
+ if (G_UNLIKELY(photo->get_uri()
+ == (*photo_iter)->get_uri()))
+ {
+ listStore_->row_changed(listStore_->get_path(
+ model_iter),
+ model_iter);
+ break;
+ }
+ }
+
+ while (true == Gtk::Main::events_pending())
+ {
+ Gtk::Main::iteration();
+ }
+ }
+}
+
+void
Application::show_progress_dialog() throw()
{
progressDialog_.set_transient_for(mainWindow_);
diff --git a/src/application/application.h b/src/application/application.h
index 1ceaec6..b5ca6b6 100644
--- a/src/application/application.h
+++ b/src/application/application.h
@@ -117,6 +117,9 @@ class Application :
throw();
void
+ on_thumbnailer_ready(PhotoList & photos) const throw();
+
+ void
show_progress_dialog() throw();
Glib::ThreadPool threadPool_;
diff --git a/src/application/engine.cpp b/src/application/engine.cpp
index a988224..35f97c7 100644
--- a/src/application/engine.cpp
+++ b/src/application/engine.cpp
@@ -49,7 +49,6 @@ Engine::Engine(int & argc, char ** & argv,
exportQueue_(),
photos_(),
currentStorageSystems_(),
- thumbnailer_(),
database_(),
criterionRepo_(),
deleteActions_( database_ )
@@ -320,10 +319,4 @@ Engine::get_photos() throw()
return photos_;
}
-Thumbnailer &
-Engine::get_thumbnailer() throw()
-{
- return thumbnailer_;
-}
-
} //namespace Solang
diff --git a/src/application/engine.h b/src/application/engine.h
index 99f29fc..43ba484 100644
--- a/src/application/engine.h
+++ b/src/application/engine.h
@@ -31,7 +31,6 @@
#include "photo.h"
#include "photo-search-criteria.h"
#include "search-criterion-repo.h"
-#include "thumbnailer.h"
#include "types.h"
namespace Solang
@@ -175,9 +174,6 @@ class Engine :
inline DeletionQueue &
get_delete_actions();
- Thumbnailer &
- get_thumbnailer() throw();
-
private:
ProgressObserverPtr observer_;
@@ -209,8 +205,6 @@ class Engine :
StorageMap currentStorageSystems_;
- Thumbnailer thumbnailer_;
-
Database database_;
SearchCriterionRepo criterionRepo_;
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 4285dbd..8d7e75f 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -70,6 +70,7 @@ libcommon_la_SOURCES = \
scale-action.h \
scale-tool-item.cpp \
scale-tool-item.h \
+ singleton.h \
spinner.cpp \
spinner.h \
spinner-dialog.cpp \
diff --git a/src/common/singleton.h b/src/common/singleton.h
new file mode 100644
index 0000000..2ce9236
--- /dev/null
+++ b/src/common/singleton.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
+ *
+ * Solang 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Solang 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SOLANG_SINGLETON_H
+#define SOLANG_SINGLETON_H
+
+namespace Solang
+{
+
+template<typename T>
+class Singleton
+{
+ public:
+ static T &
+ instance() throw()
+ {
+ static T t;
+ return t;
+ }
+};
+
+} // namespace Solang
+
+#endif // SOLANG_SINGLETON_H
diff --git a/src/common/thumbnailer.cpp b/src/common/thumbnailer.cpp
index b407551..1ab03cc 100644
--- a/src/common/thumbnailer.cpp
+++ b/src/common/thumbnailer.cpp
@@ -33,7 +33,8 @@ namespace Solang
Thumbnailer::Thumbnailer() throw() :
map_(),
pendingList_(),
- thumbnailerProxy_()
+ thumbnailerProxy_(),
+ ready_()
{
thumbnailerProxy_.error_connect(
sigc::mem_fun(*this,
@@ -86,6 +87,7 @@ Thumbnailer::on_signal_ready(guint handle, UStringList & uris)
}
std::map<Glib::ustring, PhotoPtr> & m = map_[handle];
+ PhotoList photos;
for (UStringList::const_iterator iter = uris.begin();
uris.end() != iter;
@@ -97,8 +99,13 @@ Thumbnailer::on_signal_ready(guint handle, UStringList & uris)
{
continue;
}
- m[uri]->set_thumbnail_state(Photo::THUMBNAIL_STATE_READY);
+
+ const PhotoPtr photo = m[uri];
+ photo->set_thumbnail_state(Photo::THUMBNAIL_STATE_READY);
+ photos.push_back(photo);
}
+
+ ready_.emit(photos);
}
void
@@ -155,4 +162,10 @@ Thumbnailer::push(const PhotoPtr & photo) throw()
}
}
+sigc::signal<void, PhotoList &> &
+Thumbnailer::signal_ready() throw()
+{
+ return ready_;
+}
+
} // namespace Solang
diff --git a/src/common/thumbnailer.h b/src/common/thumbnailer.h
index 998ef2b..a133fbc 100644
--- a/src/common/thumbnailer.h
+++ b/src/common/thumbnailer.h
@@ -24,23 +24,31 @@
#include <glibmm.h>
#include <sigc++/sigc++.h>
+#include "singleton.h"
#include "thumbnailer-proxy.h"
#include "types.h"
namespace Solang
{
-class Thumbnailer
+class Thumbnailer :
+ public Singleton<Thumbnailer>,
+ public sigc::trackable
{
public:
- Thumbnailer() throw();
-
~Thumbnailer() throw();
void
push(const PhotoPtr & photo) throw();
+ sigc::signal<void, PhotoList &> &
+ signal_ready() throw();
+
private:
+ friend class Singleton<Thumbnailer>;
+
+ Thumbnailer() throw();
+
void
on_async_queue(guint handle, const PhotoList & photos)
throw();
@@ -68,6 +76,8 @@ class Thumbnailer
ThumbnailerProxy thumbnailerProxy_;
sigc::connection signalTimeout_;
+
+ sigc::signal<void, PhotoList &> ready_;
};
} // namespace Solang
diff --git a/src/renderer/browser-model-column-record.cpp b/src/renderer/browser-model-column-record.cpp
index b7b5ca8..afd1aeb 100644
--- a/src/renderer/browser-model-column-record.cpp
+++ b/src/renderer/browser-model-column-record.cpp
@@ -28,22 +28,16 @@ enum
{
COLUMN_SERIAL = 0,
COLUMN_PHOTO,
- COLUMN_PIXBUF,
- COLUMN_TAG_NAME,
COLUMN_COUNT
};
BrowserModelColumnRecord::BrowserModelColumnRecord() throw() :
Gtk::TreeModelColumnRecord(),
columnSerial_(),
- columnPhoto_(),
- columnPixbuf_(),
- columnTagName_()
+ columnPhoto_()
{
add(columnSerial_);
add(columnPhoto_);
- add(columnPixbuf_);
- add(columnTagName_);
}
BrowserModelColumnRecord::~BrowserModelColumnRecord() throw()
@@ -74,28 +68,4 @@ BrowserModelColumnRecord::get_column_photo_num() const throw()
return COLUMN_PHOTO;
}
-const Gtk::TreeModelColumn<PixbufPtr> &
-BrowserModelColumnRecord::get_column_pixbuf() const throw()
-{
- return columnPixbuf_;
-}
-
-gint
-BrowserModelColumnRecord::get_column_pixbuf_num() const throw()
-{
- return COLUMN_PIXBUF;
-}
-
-const Gtk::TreeModelColumn<Glib::ustring> &
-BrowserModelColumnRecord::get_column_tag_name() const throw()
-{
- return columnTagName_;
-}
-
-gint
-BrowserModelColumnRecord::get_column_tag_name_num() const throw()
-{
- return COLUMN_TAG_NAME;
-}
-
} // namespace Solang
diff --git a/src/renderer/browser-model-column-record.h b/src/renderer/browser-model-column-record.h
index 0cd7ff2..f3311f9 100644
--- a/src/renderer/browser-model-column-record.h
+++ b/src/renderer/browser-model-column-record.h
@@ -19,7 +19,6 @@
#ifndef SOLANG_BROWSER_MODEL_COLUMN_RECORD_H
#define SOLANG_BROWSER_MODEL_COLUMN_RECORD_H
-#include <gdkmm.h>
#include <gtkmm.h>
#include "types.h"
@@ -48,27 +47,11 @@ class BrowserModelColumnRecord :
gint
get_column_photo_num() const throw();
- const Gtk::TreeModelColumn<PixbufPtr> &
- get_column_pixbuf() const throw();
-
- gint
- get_column_pixbuf_num() const throw();
-
- const Gtk::TreeModelColumn<Glib::ustring> &
- get_column_tag_name() const throw();
-
- gint
- get_column_tag_name_num() const throw();
-
protected:
Gtk::TreeModelColumn<guint> columnSerial_;
Gtk::TreeModelColumn<PhotoPtr> columnPhoto_;
- Gtk::TreeModelColumn<PixbufPtr> columnPixbuf_;
-
- Gtk::TreeModelColumn<Glib::ustring> columnTagName_;
-
private:
};
diff --git a/src/renderer/browser-renderer.cpp b/src/renderer/browser-renderer.cpp
index 439d831..a2bf331 100644
--- a/src/renderer/browser-renderer.cpp
+++ b/src/renderer/browser-renderer.cpp
@@ -21,8 +21,6 @@
#include "config.h"
#endif // HAVE_CONFIG_H
-#include <iostream>
-#include <sstream>
#include <vector>
#include <glibmm/i18n.h>
@@ -38,8 +36,6 @@
#include "photo.h"
#include "photo-search-criteria.h"
#include "scale-action.h"
-#include "thumbbuf-maker.h"
-#include "thumbnailer.h"
namespace Solang
{
@@ -88,7 +84,6 @@ BrowserRenderer::BrowserRenderer() throw() :
paginationBar_(),
dummyLabel_(),
scrolledWindow_(),
- imageLoading_(0),
treeModelFilter_(),
thumbnailView_(thumbnailRendererWidth, thumbnailRendererHeight),
zoomValue_(initialZoomValue),
@@ -371,13 +366,11 @@ BrowserRenderer::clear_thumbnails() throw()
BrowserModelColumnRecord model_column_record;
Gtk::TreeModel::Row row = *iter;
- row[model_column_record.get_column_pixbuf()] = PixbufPtr(0);
PhotoPtr photo = row[model_column_record.get_column_photo()];
if( !photo->get_has_unsaved_data() )
{
photo->set_thumbnail_buffer( PixbufPtr(0) );
}
- row[model_column_record.get_column_tag_name()] = "";
while (true == Gtk::Main::events_pending())
{
@@ -386,146 +379,6 @@ BrowserRenderer::clear_thumbnails() throw()
}
}
-void
-BrowserRenderer::generate_thumbnails() throw()
-{
- std::ostringstream fsout;
- fsout << paginationBar_.get_lower_limit();
-
- const Gtk::TreeModel::Path first_path(fsout.str());
-
- if (true == first_path.empty())
- {
- return;
- }
-
- const Gtk::TreeModel::iterator first_iter
- = treeModelFilter_->get_model()->get_iter(first_path);
-
- if (false == first_iter)
- {
- return;
- }
-
- std::ostringstream lsout;
- lsout << paginationBar_.get_upper_limit() - 1;
-
- const Gtk::TreeModel::Path last_path(lsout.str());
-
- if (true == last_path.empty())
- {
- return;
- }
-
- const Gtk::TreeModel::iterator last_iter
- = treeModelFilter_->get_model()->get_iter(last_path);
-
- if (false == last_iter)
- {
- return;
- }
-
- const guint thumbnail_width
- = static_cast<guint>(
- ratioWidth
- * static_cast<double>(zoomValue_));
- const guint thumbnail_height
- = static_cast<guint>(
- ratioHeight
- * static_cast<double>(zoomValue_));
-
- thumbnailView_.set_thumbnail_width(thumbnail_width + 12);
- thumbnailView_.set_thumbnail_height(thumbnail_height + 12);
-
- if (0 == imageLoading_)
- {
- const IconThemePtr icon_theme = Gtk::IconTheme::get_default();
- try
- {
- imageLoading_ = icon_theme->load_icon(
- "image-loading",
- thumbnail_height,
- static_cast<Gtk::IconLookupFlags>(0));
- }
- catch (const Glib::Error & e)
- {
- std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
- << e.what() << std::endl;
- }
- }
-
- Gtk::TreeModel::iterator iter;
-
- // operator<= is not defined.
- for (iter = first_iter; ; iter++)
- {
- BrowserModelColumnRecord model_column_record;
- Gtk::TreeModel::Row row = *iter;
-
- const PhotoPtr & photo
- = row[model_column_record.get_column_photo()];
- const Photo::ThumbnailState thumbnail_state
- = photo->get_thumbnail_state();
-
- if (Photo::THUMBNAIL_STATE_NONE == thumbnail_state)
- {
- ThumbbufMaker thumbbuf_maker(thumbnail_width,
- thumbnail_height,
- false);
-
- PixbufPtr pixbuf;
- try
- {
- pixbuf = thumbbuf_maker(photo);
- photo->set_thumbnail_buffer(pixbuf);
- photo->set_thumbnail_state(
- Photo::THUMBNAIL_STATE_READY);
- }
- catch (const Gdk::PixbufError & e)
- {
- Engine & engine = application_->get_engine();
- Thumbnailer & thumbnailer = engine.get_thumbnailer();
- thumbnailer.push(photo);
-
- pixbuf = imageLoading_;
- photo->set_thumbnail_state(
- Photo::THUMBNAIL_STATE_LOADING);
- }
- catch (const Glib::FileError & e)
- {
- Engine & engine = application_->get_engine();
- Thumbnailer & thumbnailer = engine.get_thumbnailer();
- thumbnailer.push(photo);
-
- pixbuf = imageLoading_;
- photo->set_thumbnail_state(
- Photo::THUMBNAIL_STATE_LOADING);
- }
-
- row[model_column_record.get_column_pixbuf()] = pixbuf;
-
-// row[model_column_record.get_column_tag_name()]
-// = photo->get_exif_data().get_picture_taken_time();
- }
- else if (Photo::THUMBNAIL_STATE_LOADING == thumbnail_state)
- {
- row[model_column_record.get_column_pixbuf()]
- = imageLoading_;
- }
- else if (Photo::THUMBNAIL_STATE_READY == thumbnail_state)
- {
- row[model_column_record.get_column_pixbuf()]
- = photo->get_thumbnail_buffer();
- }
-
- // operator<= is not defined.
- if (last_iter == iter)
- {
- break;
- }
- }
-}
-
PhotoList
BrowserRenderer::get_current_selection() throw()
{
@@ -678,7 +531,7 @@ BrowserRenderer::on_item_edit() throw()
void
BrowserRenderer::on_limits_changed() throw()
{
- generate_thumbnails();
+ set_thumbnail_size();
treeModelFilter_->refilter();
}
@@ -715,7 +568,6 @@ BrowserRenderer::on_action_view_zoom_changed(
const ScaleActionPtr & scale_action) throw()
{
zoomValue_ = scale_action->get_value();
- imageLoading_.reset();
static sigc::connection connection;
@@ -830,9 +682,25 @@ BrowserRenderer::on_visible(
void
BrowserRenderer::reload() throw()
{
+ set_thumbnail_size();
clear_thumbnails();
- generate_thumbnails();
treeModelFilter_->refilter();
}
+void
+BrowserRenderer::set_thumbnail_size() throw()
+{
+ const guint thumbnail_width
+ = static_cast<guint>(
+ ratioWidth
+ * static_cast<double>(zoomValue_));
+ const guint thumbnail_height
+ = static_cast<guint>(
+ ratioHeight
+ * static_cast<double>(zoomValue_));
+
+ thumbnailView_.set_thumbnail_width(thumbnail_width + 12);
+ thumbnailView_.set_thumbnail_height(thumbnail_height + 12);
+}
+
} // namespace Solang
diff --git a/src/renderer/browser-renderer.h b/src/renderer/browser-renderer.h
index ad9c778..e185e3b 100644
--- a/src/renderer/browser-renderer.h
+++ b/src/renderer/browser-renderer.h
@@ -81,9 +81,6 @@ class BrowserRenderer :
clear_thumbnails() throw();
void
- generate_thumbnails() throw();
-
- void
on_action_add_to_export_queue() throw();
void
@@ -127,6 +124,9 @@ class BrowserRenderer :
void
reload() throw();
+ void
+ set_thumbnail_size() throw();
+
ApplicationPtr application_;
IconFactoryPtr iconFactory_;
@@ -155,8 +155,6 @@ class BrowserRenderer :
Gtk::ScrolledWindow scrolledWindow_;
- PixbufPtr imageLoading_;
-
TreeModelFilterPtr treeModelFilter_;
ThumbnailView thumbnailView_;
diff --git a/src/renderer/cell-renderer-thumbnail.cpp b/src/renderer/cell-renderer-thumbnail.cpp
index 77fede6..bea44df 100644
--- a/src/renderer/cell-renderer-thumbnail.cpp
+++ b/src/renderer/cell-renderer-thumbnail.cpp
@@ -20,21 +20,34 @@
#include "config.h"
#endif // HAVE_CONFIG_H
+#include <iostream>
#include <cmath>
#include <cairomm/cairomm.h>
#include "cell-renderer-thumbnail.h"
+#include "photo.h"
+#include "thumbbuf-maker.h"
+#include "thumbnailer.h"
namespace Solang
{
CellRendererThumbnail::CellRendererThumbnail() throw() :
Gtk::CellRendererPixbuf(),
- extraHeight_(0)
+ extraHeight_(0),
+ imageLoading_(0),
+ photo_()
{
property_xalign().set_value(0.5);
property_yalign().set_value(0.5);
+
+ const IconThemePtr icon_theme = Gtk::IconTheme::get_default();
+ icon_theme->signal_changed().connect(
+ sigc::mem_fun(*this,
+ &CellRendererThumbnail::on_icon_theme_changed));
+
+ load_icons();
}
CellRendererThumbnail::~CellRendererThumbnail() throw()
@@ -42,6 +55,76 @@ CellRendererThumbnail::~CellRendererThumbnail() throw()
}
void
+CellRendererThumbnail::create_thumbnail(gint thumbnail_height,
+ gint thumbnail_width) throw()
+{
+ if (thumbnail_height < -1 || thumbnail_width < -1)
+ {
+ return;
+ }
+
+ if (Photo::THUMBNAIL_STATE_LOADING
+ == photo_->get_thumbnail_state())
+ {
+ property_pixbuf().set_value(imageLoading_);
+ return;
+ }
+
+ ThumbbufMaker thumbbuf_maker(thumbnail_width,
+ thumbnail_height,
+ false);
+ PixbufPtr pixbuf;
+ try
+ {
+ pixbuf = thumbbuf_maker(photo_);
+ photo_->set_thumbnail_buffer(pixbuf);
+ photo_->set_thumbnail_state(Photo::THUMBNAIL_STATE_READY);
+ }
+ catch (const Gdk::PixbufError & e)
+ {
+ Thumbnailer & thumbnailer = Thumbnailer::instance();
+ thumbnailer.push(photo_);
+
+ pixbuf = imageLoading_;
+ photo_->set_thumbnail_state(Photo::THUMBNAIL_STATE_LOADING);
+ }
+ catch (const Glib::FileError & e)
+ {
+ Thumbnailer & thumbnailer = Thumbnailer::instance();
+ thumbnailer.push(photo_);
+
+ pixbuf = imageLoading_;
+ photo_->set_thumbnail_state(Photo::THUMBNAIL_STATE_LOADING);
+ }
+
+ property_pixbuf().set_value(pixbuf);
+}
+
+void
+CellRendererThumbnail::load_icons() throw()
+{
+ const IconThemePtr icon_theme = Gtk::IconTheme::get_default();
+ try
+ {
+ imageLoading_ = icon_theme->load_icon(
+ "image-loading",
+ 96,
+ static_cast<Gtk::IconLookupFlags>(0));
+ }
+ catch (const Glib::Error & e)
+ {
+ std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+ << e.what() << std::endl;
+ }
+}
+
+void
+CellRendererThumbnail::on_icon_theme_changed() throw()
+{
+ load_icons();
+}
+
+void
CellRendererThumbnail::render_vfunc(
const Glib::RefPtr<Gdk::Drawable> & window,
Gtk::Widget & widget,
@@ -50,6 +133,12 @@ CellRendererThumbnail::render_vfunc(
const Gdk::Rectangle & expose_area,
Gtk::CellRendererState flags)
{
+ if (0 == property_pixbuf().get_value())
+ {
+ create_thumbnail(cell_area.get_height() - 12,
+ cell_area.get_width() - 12);
+ }
+
const gint height = background_area.get_height() + extraHeight_;
const gint width = background_area.get_width();
@@ -128,4 +217,10 @@ CellRendererThumbnail::set_extra_height(guint height) throw()
extraHeight_ = height;
}
+void
+CellRendererThumbnail::set_photo(const PhotoPtr & photo) throw()
+{
+ photo_ = photo;
+}
+
} // namespace Solang
diff --git a/src/renderer/cell-renderer-thumbnail.h b/src/renderer/cell-renderer-thumbnail.h
index d60deb7..173568f 100644
--- a/src/renderer/cell-renderer-thumbnail.h
+++ b/src/renderer/cell-renderer-thumbnail.h
@@ -23,6 +23,8 @@
#include <glibmm.h>
#include <gtkmm.h>
+#include "types.h"
+
namespace Solang
{
@@ -38,6 +40,9 @@ class CellRendererThumbnail :
void
set_extra_height(guint height) throw();
+ void
+ set_photo(const PhotoPtr & photo) throw();
+
protected:
virtual void
render_vfunc(const Glib::RefPtr<Gdk::Drawable> & window,
@@ -47,8 +52,22 @@ class CellRendererThumbnail :
const Gdk::Rectangle & expose_area,
Gtk::CellRendererState flags);
+ void
+ create_thumbnail(gint thumbnail_height,
+ gint thumbnail_width) throw();
+
+ void
+ load_icons() throw();
+
+ void
+ on_icon_theme_changed() throw();
+
guint extraHeight_;
+ PhotoPtr photo_;
+
+ PixbufPtr imageLoading_;
+
private:
};
diff --git a/src/renderer/thumbnail-view.cpp b/src/renderer/thumbnail-view.cpp
index 19dc038..4e80b38 100644
--- a/src/renderer/thumbnail-view.cpp
+++ b/src/renderer/thumbnail-view.cpp
@@ -34,6 +34,37 @@ static const std::string uiFile
= PACKAGE_DATA_DIR"/"PACKAGE_TARNAME"/ui/"
PACKAGE_TARNAME"-thumbnail-popup.ui";
+static void
+thumbnail_view_set_renderer_thumbnail_data(
+ GtkCellLayout * cell_layout,
+ GtkCellRenderer * cell_renderer,
+ GtkTreeModel * tree_model,
+ GtkTreeIter * tree_iter,
+ gpointer user_data)
+{
+ CellRendererThumbnail * const renderer_thumbnail
+ = dynamic_cast<CellRendererThumbnail *>(Glib::wrap(
+ cell_renderer,
+ false));
+ const TreeModelPtr list_store = Glib::wrap(tree_model, true);
+
+ // Can not convert a GtkTreeIter * to a Gtk::TreeModel::iterator *
+ // directly.
+ const Gtk::TreePath tree_path(gtk_tree_model_get_path(tree_model,
+ tree_iter),
+ false);
+ const Gtk::TreeModel::const_iterator iter = list_store->get_iter(
+ tree_path);
+
+ Gtk::TreeModel::Row row = *iter;
+ BrowserModelColumnRecord model_column_record;
+ const PhotoPtr photo = row[model_column_record.get_column_photo()];
+ PixbufPtr pixbuf = photo->get_thumbnail_buffer();
+
+ renderer_thumbnail->property_pixbuf().set_value(pixbuf);
+ renderer_thumbnail->set_photo(photo);
+}
+
ThumbnailView::ThumbnailView(gint thumbnail_renderer_width,
gint thumbnail_renderer_height) throw() :
Gtk::IconView(),
@@ -102,14 +133,14 @@ ThumbnailView::configure(gint thumbnail_renderer_width,
= GTK_CELL_RENDERER(rendererText_.gobj());
gtk_cell_layout_pack_start(self, renderer_thumbnail, FALSE);
- gtk_cell_layout_set_attributes(self, renderer_thumbnail,
- "pixbuf", BrowserModelColumnRecord().get_column_pixbuf_num(),
- NULL);
+ gtk_cell_layout_set_cell_data_func(
+ self,
+ renderer_thumbnail,
+ thumbnail_view_set_renderer_thumbnail_data,
+ 0,
+ 0);
gtk_cell_layout_pack_start(self, renderer_info, FALSE);
- gtk_cell_layout_set_attributes(self, renderer_info,
- "text", BrowserModelColumnRecord().get_column_tag_name_num(),
- NULL);
rendererThumbnail_.property_width().set_value(
thumbnail_renderer_width);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]