[solang] Introduced Tracker and the thumbnail management specification



commit f30c478c8459b212f58ea773d7208e57c415a26c
Author: Debarshi Ray <rishi gnu org>
Date:   Fri Dec 25 16:58:47 2009 +0200

    Introduced Tracker and the thumbnail management specification
    
    This is a pretty big change affecting the entire meta-data storage
    and thumbnailing code. Instead of using our own SQLite database for
    keeping our meta-data we now use Tracker [1] so that the meta-data
    (eg., tags) is no longer locked in Solang but can be accessed across
    the desktop. SparQL is used to talk to Tracker over DBus. For
    thumbnailing we use the the DBus Specification for Thumbnail
    Management [2]. Any thumbnailer service which provides the standard
    org.freedesktop.thumbnails.xxx API can be used. Tumbler [3] is one
    such implementation.
    
    One of the major fallouts of this change has been that most of the
    blocking interfaces have now been replaced by their asynchronous
    cousins. Those that are left either need to be replaced or should not
    be used. This is mainly to avoid blocking DBus calls [4].
    
    Since it is possible to query Tracker to return all photos known to
    it, there is no need to manually import photos. The only scenario
    where this will not work is if Tracker's indexer has been switched
    off. In that case one would have to explicitly inform Tracker about
    them. Even then, something like Conduit [5] might be a good option.
    Therefore the Importer and all implementations of IPhotoSource have
    been disabled.
    
    The storage subsystem has been removed. Due to the above changes it
    was no longer needed to have one and henceforth we will rely on Gvfs
    for our needs. All implementations of IStorage have been removed.
    
    ExifData fields are now populated from the information provided by
    Tracker according to the Nepomuk Multimedia (NMM) ontology.
    
    Since we are using the Thumbnail Management Specification, thumbnails
    are no longer separately created and stored in
    $XDG_DATA_HOME/solang/thumbnails. Instead we follow the Thumbnail
    Managing Standard [6].
    
    Some files have been moved from src/attribute and src/database to
    src/common to satisfy the linker.
    
    Dependencies:
    
    Exiv2 and libgdamm have been dropped. Tracker-client and dbus-glib
    are the new compile time dependencies. The presence of the
    org.freedesktop.Tracker1 and org.freedesktop.thumbnails.xxx DBus
    services are the new runtime requirements.
    
    Regressions:
    
    The editor is broken.
    
    The DateManager has been disabled until the queries are ported to
    work with Tracker.
    
    Tags only have a name and can not be removed from photos.
    
    [1] http://tracker-project.org/
    [2] http://live.gnome.org/ThumbnailerSpec
    [3] http://git.xfce.org/apps/tumbler/
    [4] http://smcv.pseudorandom.co.uk/2008/11/nonblocking/
    [5] http://live.gnome.org/Conduit
    [6] http://jens.triq.net/thumbnail-spec/

 .gitignore                                         |    4 +
 README                                             |    5 +-
 configure.ac                                       |   18 +-
 po/POTFILES.in                                     |   12 +-
 src/Makefile.am                                    |    3 -
 src/application/Makefile.am                        |   17 +-
 src/application/application.cpp                    |   89 ++--
 src/application/application.h                      |    6 +-
 src/application/engine.cpp                         |  238 ++--------
 src/application/engine.h                           |   73 +---
 src/application/main.cpp                           |    2 -
 src/attribute/Makefile.am                          |   12 +-
 src/attribute/basic-exif-view.cpp                  |  143 ++++---
 src/attribute/exif-data.cpp                        |  282 -----------
 src/attribute/modification-date.cpp                |   70 +---
 src/attribute/modification-date.h                  |   16 +-
 src/attribute/photo-tag.cpp                        |  100 +---
 src/attribute/photo-tag.h                          |   62 +--
 src/attribute/property-manager.cpp                 |   17 +-
 src/attribute/property-manager.h                   |    3 +
 src/attribute/search-basket.cpp                    |    2 +-
 src/attribute/tag-manager.cpp                      |  101 +++--
 src/attribute/tag-manager.h                        |    6 +
 src/attribute/tag-new-dialog.cpp                   |   42 +-
 src/attribute/tag-view.cpp                         |    6 +-
 src/attribute/tag.cpp                              |  172 +++-----
 src/attribute/tag.h                                |   66 ++--
 src/attribute/thumbnail.cpp                        |  332 -------------
 src/attribute/thumbnail.h                          |  193 --------
 src/common/Makefile.am                             |   73 +++-
 src/common/database.cpp                            |  353 ++++++++++++++
 src/{database => common}/database.h                |   90 ++--
 .../db-table-visitor.h => common/db-object.cpp}    |   39 +-
 src/common/db-object.h                             |   79 ++++
 src/{database => common}/delete-action.cpp         |    7 +-
 src/{database => common}/delete-action.h           |    0
 src/{attribute => common}/exif-data-key.cpp        |    4 +-
 src/{attribute => common}/exif-data-key.h          |    2 +-
 src/common/exif-data.cpp                           |  226 +++++++++
 src/{attribute => common}/exif-data.h              |  105 +++--
 src/common/i-photo-destination.h                   |    2 -
 ...rg-freedesktop-thumbnails-thumbnailer1-dbus.xml |   55 +++
 src/common/photo.cpp                               |  210 +++------
 src/common/photo.h                                 |  142 ++----
 src/common/pixbuf-maker.cpp                        |    8 +-
 src/common/solang-marshal.list                     |    1 +
 src/common/thumbbuf-maker.cpp                      |  128 +-----
 src/common/thumbbuf-maker.h                        |    9 +-
 src/common/thumbnailer-proxy.cpp                   |  441 +++++++++++++++++
 src/common/thumbnailer-proxy.h                     |  102 ++++
 src/common/thumbnailer.cpp                         |  158 +++++++
 src/common/thumbnailer.h                           |   75 +++
 src/common/tracker-client.cpp                      |  204 ++++++++
 src/common/tracker-client.h                        |   69 +++
 src/common/types.h                                 |   15 +-
 src/database/Makefile.am                           |   46 --
 src/database/database.cpp                          |  494 --------------------
 src/database/db-object.cpp                         |  146 ------
 src/database/db-object.h                           |  128 -----
 src/database/db-table-factory.cpp                  |   51 --
 src/database/db-table-factory.h                    |   37 --
 src/database/db-table-visitor.cpp                  |   32 --
 src/database/db-table.cpp                          |  134 ------
 src/database/db-table.h                            |   79 ----
 src/database/exifs-table.cpp                       |   85 ----
 src/database/exifs-table.h                         |   53 ---
 src/database/photo-tags-table.cpp                  |   98 ----
 src/database/photo-tags-table.h                    |   54 ---
 src/database/photos-table.cpp                      |   97 ----
 src/database/photos-table.h                        |   56 ---
 src/database/tags-table.cpp                        |  105 -----
 src/database/tags-table.h                          |   54 ---
 src/database/thumbnails-table.cpp                  |   79 ----
 src/database/thumbnails-table.h                    |   54 ---
 src/edit-engine/Makefile.am                        |    6 +-
 src/editor/Makefile.am                             |    6 +-
 src/editor/desaturate.cpp                          |    2 -
 src/editor/editable-photo.cpp                      |   48 +-
 src/editor/editable-photo.h                        |   38 +-
 src/editor/flip.cpp                                |    4 +-
 src/editor/rotate.cpp                              |   32 +-
 src/editor/save-photos-window.cpp                  |    5 +-
 src/editor/scale.cpp                               |    2 -
 src/exporter/Makefile.am                           |    6 +-
 src/exporter/directory-destination.cpp             |   20 +-
 src/exporter/directory-destination.h               |    2 -
 src/exporter/exporter.cpp                          |   10 +-
 src/importer/Makefile.am                           |    4 +-
 src/renderer/Makefile.am                           |    6 +-
 src/renderer/browser-renderer.cpp                  |   80 +++-
 src/renderer/browser-renderer.h                    |    2 +
 src/renderer/console-renderer.cpp                  |    2 -
 src/renderer/enlarged-renderer.cpp                 |    5 -
 src/renderer/pagination-bar.cpp                    |    8 +-
 src/renderer/slideshow-renderer.cpp                |    7 +-
 src/renderer/thumbnail-view.cpp                    |   16 +-
 src/storage/Makefile.am                            |   31 --
 src/storage/directory-storage.cpp                  |  320 -------------
 src/storage/directory-storage.h                    |   88 ----
 src/storage/storage.cpp                            |   40 --
 src/storage/storage.h                              |   57 ---
 src/storage/thumbnail-store.cpp                    |   36 --
 src/storage/thumbnail-store.h                      |   51 --
 src/storage/token-replacer.h                       |   92 ----
 104 files changed, 2708 insertions(+), 4889 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index c74812d..0ae7375 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,9 +13,13 @@ libtool
 ltmain.sh
 missing
 mkinstalldirs
+org-freedesktop-thumbnails-thumbnailer1-dbus-bindings.h
 solang
+solang-marshal.c
+solang-marshal.h
 stamp-h1
 stamp-it
+stamp-solang-marshal.h
 .deps
 .intltool-merge-cache
 .libs
diff --git a/README b/README
index 5385880..8be1c03 100644
--- a/README
+++ b/README
@@ -52,16 +52,15 @@ Features:
 Dependencies:
 -------------
  - babl
- - exiv2 >= 0.18
+ - dbus-glib-1
  - flickcurl
- - libgdamm-3.0 <= 3.0.1
- - libgda-sqlite-3.0
  - gdl-1.0
  - gegl
  - libgphoto2
  - gtkimageview
  - gtkmm-2.4 >= 2.8
  - libsoup-2.4
+ - tracker-client-0.7
  - webkit-1.0
 
 Packages are available for Debian, Fedora and Ubuntu.
diff --git a/configure.ac b/configure.ac
index 11e4dbe..2fc2851 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,17 +22,24 @@ AM_GLIB_GNU_GETTEXT
 AM_PROG_LIBTOOL
 
 
+AC_ARG_VAR(
+    [DBUS_BINDING_TOOL],
+    [Tool to generate C bindings from XML D-Bus interface definitions])
+AC_PATH_PROG([DBUS_BINDING_TOOL], [dbus-binding-tool], [no])
+if test x"$DBUS_BINDING_TOOL" = x"no"; then
+    AC_MSG_ERROR([could not find dbus-binding-tool in \$PATH.])
+fi
+
 PKG_CHECK_MODULES(BABL, [babl])
-PKG_CHECK_MODULES(EXIV2, [exiv2 >= 0.18])
-PKG_CHECK_MODULES(FLICKCURL, [flickcurl])
-PKG_CHECK_MODULES(GDAMM, [libgdamm-4.0])
-PKG_CHECK_MODULES(GDA_SQLITE, [libgda-sqlite-4.0])
+PKG_CHECK_MODULES(DBUS, [dbus-glib-1])
+PKG_CHECK_MODULES(FLICKCURL, [flickcurl libxml-2.0])
 PKG_CHECK_MODULES(GDL, [gdl-1.0])
 PKG_CHECK_MODULES(GEGL, [gegl])
 PKG_CHECK_MODULES(GPHOTO2, [libgphoto2])
 PKG_CHECK_MODULES(GTKIMAGEVIEW, [gtkimageview])
 PKG_CHECK_MODULES(GTKMM, [gtkmm-2.4 >= 2.8])
 PKG_CHECK_MODULES(SOUP, [libsoup-2.4])
+PKG_CHECK_MODULES(TRACKER, [tracker-client-0.7])
 PKG_CHECK_MODULES(WEBKIT, [webkit-1.0])
 
 
@@ -53,12 +60,9 @@ src/Makefile
 src/application/Makefile
 src/attribute/Makefile
 src/common/Makefile
-src/database/Makefile
 src/edit-engine/Makefile
 src/editor/Makefile
 src/exporter/Makefile
-src/importer/Makefile
 src/renderer/Makefile
-src/storage/Makefile
 po/Makefile.in
 ])
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 98a4e57..b4dea3a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -3,14 +3,15 @@
 data/solang.desktop.in.in
 src/application/engine.cpp
 src/application/main-window.cpp
+src/attribute/basic-exif-view.cpp
 src/attribute/date-manager.cpp
 src/attribute/property-manager.cpp
 src/attribute/search-basket.cpp
 src/attribute/tag-manager.cpp
 src/attribute/tag-new-dialog.cpp
+src/common/exif-data.cpp
 src/common/histogram-viewer.cpp
 src/common/progress-dialog.cpp
-src/database/database.cpp
 src/edit-engine/brightness-operation.cpp
 src/edit-engine/buffer.cpp
 src/edit-engine/contrast-operation.cpp
@@ -27,15 +28,6 @@ src/editor/save-photos-window.cpp
 src/editor/scale-widget.cpp
 src/exporter/directory-destination.cpp
 src/exporter/exporter-dialog.cpp
-src/importer/camera-import-widget.cpp
-src/importer/camera-source.cpp
-src/importer/directory-source.cpp
-src/importer/flickr-auth-dialog.cpp
-src/importer/flickr-chooser-button.cpp
-src/importer/flickr-chooser-dialog.cpp
-src/importer/flickr-source.cpp
-src/importer/importer.cpp
-src/importer/importer-dialog.cpp
 src/renderer/browser-renderer.cpp
 src/renderer/editor-renderer.cpp
 src/renderer/enlarged-renderer.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index e2e380b..c144724 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,11 +1,8 @@
 SUBDIRS = \
 	attribute \
 	common \
-	database \
 	edit-engine \
 	editor \
 	exporter \
-	importer \
 	renderer \
-	storage \
 	application
diff --git a/src/application/Makefile.am b/src/application/Makefile.am
index 606789d..22b2d06 100644
--- a/src/application/Makefile.am
+++ b/src/application/Makefile.am
@@ -17,25 +17,22 @@ solang_LDFLAGS =
 
 solang_LDADD = \
 	$(top_builddir)/src/exporter/libexporter.la \
-	$(top_builddir)/src/importer/libimporter.la \
 	$(top_builddir)/src/renderer/librenderer.la \
-	$(top_builddir)/src/storage/libstorage.la \
 	$(top_builddir)/src/attribute/libattribute.la \
-	$(top_builddir)/src/database/libdatabase.la \
 	$(top_builddir)/src/editor/libeditor.la \
 	$(top_builddir)/src/edit-engine/libeditengine.la \
 	$(top_builddir)/src/common/libcommon.la \
-	$(EXIV2_LIBS) \
+	$(DBUS_LIBS) \
 	$(FLICKCURL_LIBS) \
 	$(GPHOTO2_LIBS) \
 	$(GTKIMAGEVIEW_LIBS) \
 	$(WEBKIT_LIBS) \
 	$(GTKMM_LIBS) \
-	$(GDAMM_LIBS) \
 	$(SOUP_LIBS) \
 	$(GDL_LIBS) \
 	$(BABL_LIBS) \
-	$(GEGL_LIBS)
+	$(GEGL_LIBS) \
+	$(TRACKER_LIBS)
 
 AM_CPPFLAGS = \
 	-DPACKAGE_LOCALE_DIR=\""${datadir}/locale"\" \
@@ -49,18 +46,16 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/database \
 	-I$(top_srcdir)/src/editor \
 	-I$(top_srcdir)/src/exporter \
-	-I$(top_srcdir)/src/importer \
 	-I$(top_srcdir)/src/renderer \
-	-I$(top_srcdir)/src/storage \
 	$(SOLANG_CFLAGS) \
-	$(EXIV2_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(FLICKCURL_CFLAGS) \
 	$(GPHOTO2_CFLAGS) \
 	$(GTKIMAGEVIEW_CFLAGS) \
 	$(GTKMM_CFLAGS) \
-	$(GDAMM_CFLAGS) \
 	$(GDL_CFLAGS) \
-	$(GEGL_CFLAGS)
+	$(GEGL_CFLAGS) \
+	$(TRACKER_CFLAGS)
 
 AM_CXXFLAGS = \
 	 -Wall
diff --git a/src/application/application.cpp b/src/application/application.cpp
index 13413e6..f3fc401 100644
--- a/src/application/application.cpp
+++ b/src/application/application.cpp
@@ -30,27 +30,25 @@
 #include "application.h"
 #include "browser-model-column-record.h"
 #include "browser-renderer.h"
-#include "camera-source.h"
-#include "console-renderer.h"
+//#include "camera-source.h"
+//#include "console-renderer.h"
 #include "content-type-repo.h"
-#include "date-manager.h"
+//#include "date-manager.h"
 #include "directory-destination.h"
-#include "directory-source.h"
-#include "directory-storage.h"
+//#include "directory-source.h"
 #include "editor-renderer.h"
 #include "enlarged-renderer.h"
 #include "exporter.h"
-#include "flickr-source.h"
-#include "i-photo-source.h"
+//#include "flickr-source.h"
+//#include "i-photo-source.h"
 #include "i-plugin.h"
-#include "importer.h"
+//#include "importer.h"
 #include "photo.h"
 #include "progress-observer.h"
 #include "property-manager.h"
 #include "search-basket.h"
 #include "slideshow-renderer.h"
 #include "tag-manager.h"
-#include "thumbnail-store.h"
 
 namespace Solang
 {
@@ -244,31 +242,11 @@ Application::Application(int & argc, char ** & argv) throw() :
         }
     }
 
-    std::string thumbnail_store_path = Glib::get_user_data_dir() + "/";
-    thumbnail_store_path += Glib::get_prgname();
-    thumbnail_store_path += "/thumbnails/";
-
-    std::string photo_store_path = Glib::get_user_special_dir(
-                                       G_USER_DIRECTORY_PICTURES);
-
-    if( photo_store_path.empty() )
-    {
-        photo_store_path = Glib::get_home_dir();
-        photo_store_path += "/Pictures";
-    }
-    photo_store_path += "/";
-    photo_store_path += Glib::get_application_name();
-
-    ThumbnailStore thumbnail_store(thumbnail_store_path);
-    IStoragePtr directory_storage(new DirectoryStorage(
-                                          thumbnail_store,
-                                          engine_.get_db(),
-                                          photo_store_path));
-    engine_.add_current_storage_system(
-        directory_storage->get_storage_uri_prefix(), directory_storage);
-
     add_icons();
 
+    engine_.signal_criteria_changed().connect(
+        sigc::mem_fun(*this,
+                      &Application::on_criteria_changed));
     engine_.photo_export_begin().connect(sigc::mem_fun(*this,
         &Application::show_progress_dialog));
     engine_.photo_export_end().connect(sigc::mem_fun(*this,
@@ -277,8 +255,6 @@ Application::Application(int & argc, char ** & argv) throw() :
         &Application::show_progress_dialog));
     engine_.photo_import_end().connect(sigc::mem_fun(*this,
         &Application::hide_progress_dialog));
-    engine_.photo_render_begin().connect(sigc::mem_fun(*this,
-        &Application::on_photo_render_begin));
 }
 
 Application::~Application() throw()
@@ -290,12 +266,16 @@ void
 Application::init() throw()
 {
     engine_.init("");
+    engine_.search_async(
+        PhotoSearchCriteriaList(),
+        sigc::mem_fun(*this,
+                      &Application::on_async_search));
 
     // Plugins.
 
-    IPluginPtr date_manager(new DateManager());
-    plugins_.insert(std::make_pair("date-manager",
-                                   date_manager));
+//    IPluginPtr date_manager(new DateManager());
+//    plugins_.insert(std::make_pair("date-manager",
+//                                   date_manager));
 
     IPluginPtr property_manager(new PropertyManager());
     plugins_.insert(std::make_pair("property-manager",
@@ -314,18 +294,18 @@ Application::init() throw()
     plugins_.insert(std::make_pair("directory-exporter",
                                    directory_exporter));
 
-    IPhotoSourcePtr directory_source(new DirectorySource());
-    IPluginPtr directory_importer(new Importer(directory_source, true));
-    plugins_.insert(std::make_pair("directory-importer",
-                                   directory_importer));
+//    IPhotoSourcePtr directory_source(new DirectorySource());
+//    IPluginPtr directory_importer(new Importer(directory_source, true));
+//    plugins_.insert(std::make_pair("directory-importer",
+//                                   directory_importer));
 
-    IPhotoSourcePtr camera_source(new CameraSource());
-    IPluginPtr camera_importer(new Importer(camera_source, false));
-    plugins_.insert(std::make_pair("camera-importer", camera_importer));
+//    IPhotoSourcePtr camera_source(new CameraSource());
+//    IPluginPtr camera_importer(new Importer(camera_source, false));
+//    plugins_.insert(std::make_pair("camera-importer", camera_importer));
 
-    IPhotoSourcePtr flickr_source(new FlickrSource());
-    IPluginPtr flickr_importer(new Importer(flickr_source, false));
-    plugins_.insert(std::make_pair("flickr-importer", flickr_importer));
+//    IPhotoSourcePtr flickr_source(new FlickrSource());
+//    IPluginPtr flickr_importer(new Importer(flickr_source, false));
+//    plugins_.insert(std::make_pair("flickr-importer", flickr_importer));
 
     std::for_each(plugins_.begin(), plugins_.end(),
                   Initializer<IPluginPtr>(this));
@@ -501,17 +481,24 @@ Application::list_store_change_end() throw()
 }
 
 void
-Application::on_photo_render_begin() throw()
+Application::on_async_search(PhotoList & photos) throw()
 {
     mainWindow_.set_busy(true);
-
-    PhotoList photos = engine_.get_photos();
     add_photos_to_model(photos);
-
     mainWindow_.set_busy(false);
 }
 
 void
+Application::on_criteria_changed(PhotoSearchCriteriaList & criteria)
+                                 throw()
+{
+    engine_.search_async(
+        criteria,
+        sigc::mem_fun(*this,
+                      &Application::on_async_search));
+}
+
+void
 Application::show_progress_dialog() throw()
 {
     progressDialog_.set_transient_for(mainWindow_);
diff --git a/src/application/application.h b/src/application/application.h
index 999dc68..1ceaec6 100644
--- a/src/application/application.h
+++ b/src/application/application.h
@@ -110,7 +110,11 @@ class Application :
         hide_progress_dialog() throw();
 
         void
-        on_photo_render_begin() throw();
+        on_async_search(PhotoList & photos) throw();
+
+        void
+        on_criteria_changed(PhotoSearchCriteriaList & criteria)
+                            throw();
 
         void
         show_progress_dialog() throw();
diff --git a/src/application/engine.cpp b/src/application/engine.cpp
index e24f789..a988224 100644
--- a/src/application/engine.cpp
+++ b/src/application/engine.cpp
@@ -41,29 +41,19 @@ Engine::Engine(int & argc, char ** & argv,
     photoExportEnd_(),
     photoImportBegin_(),
     photoImportEnd_(),
-    photoRenderBegin_(),
-    photoRenderEnd_(),
     tagAddBegin_(),
     tagAddEnd_(),
-    criterionChanged_(),
+    criteriaChanged_(),
     selectionChanged_(),
     mutex_(),
     exportQueue_(),
     photos_(),
     currentStorageSystems_(),
-    database_(""),
+    thumbnailer_(),
+    database_(),
     criterionRepo_(),
     deleteActions_( database_ )
 {
-    //TBD::CREATE
-    {
-        Glib::ustring dbPath = Glib::get_user_data_dir() + "/";
-        dbPath += Glib::get_prgname();
-        dbPath += "/";
-        database_.set_path( dbPath );
-    }
-    criterionChanged_.connect(
-                sigc::mem_fun( *this, &Engine::on_criterion_changed));
 }
 
 Engine::~Engine() throw()
@@ -73,7 +63,6 @@ Engine::~Engine() throw()
 void
 Engine::init(Glib::ustring str)
 {
-    database_.open();
 }
 
 void
@@ -83,6 +72,14 @@ Engine::final()
 }
 
 void
+Engine::criteria_changed() throw()
+{
+    criterionRepo_.update();
+    PhotoSearchCriteriaList criteria = criterionRepo_.get_criterion();
+    criteriaChanged_.emit(criteria);
+}
+
+void
 Engine::import(const PhotoPtr & photo,
                const IPhotoSourcePtr & source,
                const IStoragePtr & selected_storage,
@@ -117,7 +114,6 @@ Engine::import(const PhotoPtr & photo,
         Glib::Mutex::Lock lock(mutex_);
         photos_ = imp_photos;
     }
-    photoRenderBegin_.emit();
 
     return;
 }
@@ -155,7 +151,6 @@ Engine::import(const PhotoList & photos,
         Glib::Mutex::Lock lock(mutex_);
         photos_ = imp_photos;
     }
-    photoRenderBegin_.emit();
 
     return;
 }
@@ -191,66 +186,32 @@ Engine::import(const IPhotoSourcePtr & source,
         Glib::Mutex::Lock lock(mutex_);
         photos_ = imp_photos;
     }
-    photoRenderBegin_.emit();
 
     return;
 }
 
-PhotoList
-Engine::search(const PhotoSearchCriteriaList & criterion,
-               const ProgressObserverPtr & observer) throw()
-{
-    ProgressObserverPtr obs = (observer) ? observer : observer_;
-    return database_.search(criterion, obs);
-}
-
-void
-Engine::on_criterion_changed()
-{
-    criterionRepo_.update();
-    const PhotoSearchCriteriaList & criterion
-                        = criterionRepo_.get_criterion();
-    show( criterion, observer_ );
-}
-
 void
-Engine::show(const PhotoSearchCriteriaList & criterion) throw()
+Engine::search_async(const PhotoSearchCriteriaList & criteria,
+                     const Database::SlotAsyncPhotos & slot) const
+                     throw()
 {
-    return show( criterion, observer_);
+    database_.search_async(criteria, slot);
 }
 
 void
-Engine::show(const PhotoSearchCriteriaList & criterion,
-             const ProgressObserverPtr & observer) throw()
+Engine::export_photos(const IPhotoDestinationPtr & destination)
+                      throw()
 {
-    PhotoList photos = create_renderable_list_from_photos(
-                           search(criterion, observer_), observer_);
-
-    {
-        Glib::Mutex::Lock lock(mutex_);
-        photos_ = photos;
-    }
-    photoRenderBegin_.emit();
-
+    export_photos(destination, observer_);
     return;
 }
 
 void
 Engine::export_photos(const IPhotoDestinationPtr & destination,
-                      const IStoragePtr & selected_storage) throw()
-{
-    export_photos(destination, selected_storage, observer_);
-    return;
-}
-
-void
-Engine::export_photos(const IPhotoDestinationPtr & destination,
-                      const IStoragePtr & selected_storage,
                       const ProgressObserverPtr & observer) throw()
 {
     photoExportBegin_.emit();
-    destination->export_photos(exportQueue_, selected_storage,
-                               observer);
+    destination->export_photos(exportQueue_, observer);
     photoExportEnd_.emit();
 
     return;
@@ -269,117 +230,14 @@ Engine::erase(const PhotoList & photos,
         obs->set_event_description("Removing Selected Photos");
     }
 
-    DBTablePtr photosTable = database_.getTable( "photos" );
-    DBTablePtr photoTagsTable = database_.getTable( "photo_tags" );
-
-    for( PhotoList::const_iterator photo = photos.begin();
-         photo != photos.end(); photo++ )
-    {
-        const Glib::ustring &uri = (*photo)->get_uri();
-        Glib::ustring storagePrefix
-                            = uri.substr(0, uri.find( ":" ) );
-        StorageMap::iterator storage
-                        = currentStorageSystems_.find( storagePrefix );
-        if( storage != currentStorageSystems_.end() )
-        {
-            ((*storage).second)->remove( (*photo) );
-            photosTable->remove( *(*photo) );
-            photoTagsTable->remove( *(*photo) );
-            if( obs )
-                obs->receive_event_notifiation();
-        }    
-        else
-        {
-            //TBD::Error 
-        }
-    }
-        
     return;
 }
 
 void
-Engine::save(const PhotoPtr & photo)
-{
-    const Glib::ustring & uri = photo->get_uri();
-    Glib::ustring storagePrefix
-                        = uri.substr(0, uri.find( ":" ) );
-    StorageMap::iterator storage
-                    = currentStorageSystems_.find( storagePrefix );
-    if( storage != currentStorageSystems_.end() )
-    {
-        (*storage).second->save( photo, false );
-    }
-    photo->set_has_unsaved_data( false );
-}
-
-PhotoList
-Engine::create_renderable_list_from_photos(
-    const PhotoList & photos,
-    const ProgressObserverPtr & observer)
-{
-    ProgressObserverPtr obs = (observer) ? observer : observer_;
-
-    if( obs )
-    {
-        observer->set_event_description(_("Updating path information"));
-        observer->set_num_events(photos.size());
-        observer->set_current_events(0);
-    }
-
-    for( PhotoList::const_iterator photo = photos.begin();
-         photo != photos.end(); photo++ )
-    {
-        const Glib::ustring &uri = (*photo)->get_uri();
-        Glib::ustring storagePrefix
-                            = uri.substr(0, uri.find( ":" ) );
-        StorageMap::iterator storage
-                        = currentStorageSystems_.find( storagePrefix );
-        if( storage != currentStorageSystems_.end() )
-        {
-            (*photo)->set_disk_file_path(
-                        ((*storage).second)->retrieve( *(*photo) ) );
-            if( obs )
-                obs->receive_event_notifiation();
-        }
-    }
-
-    if (0 != obs)
-    {
-        obs->reset();
-    }
-
-    return photos;
-}
-
-TagList
-Engine::get_tags() const throw()
-{
-    DBTablePtr tagsTable = database_.getTable("tags");
-    DataModelPtr model = tagsTable->get_model();
-    TagList tags;
-
-    for (gint32 i = 0; i < model->get_n_rows(); i++)
-    {
-        TagPtr tag(new Tag());
-        tag->create(model, i);
-        tag->set_table( tagsTable );
-        tags.push_back(tag);
-    }
-
-    return tags;
-}
-
-void
-Engine::apply_tag_to_photos( PhotoList &photos, const TagPtr &tag )
+Engine::get_tags_async(const Database::SlotAsyncTags & slot) const
+                       throw()
 {
-    for( PhotoList::iterator photo = photos.begin();
-         photo != photos.end(); photo++)
-    {
-        PhotoTag pt(
-                (*photo)->get_photo_id(), tag->get_tag_id());
-        pt.save( *get_db() );
-    }
-    return;
+    database_.get_tags_async(slot);
 }
 
 DatePhotoInfoList
@@ -426,18 +284,6 @@ Engine::photo_import_end() throw()
 }
 
 Glib::Dispatcher &
-Engine::photo_render_begin() throw()
-{
-    return photoRenderBegin_;
-}
-
-Glib::Dispatcher &
-Engine::photo_render_end() throw()
-{
-    return photoRenderEnd_;
-}
-
-Glib::Dispatcher &
 Engine::tag_add_begin() throw()
 {
     return tagAddBegin_;
@@ -449,44 +295,16 @@ Engine::tag_add_end() throw()
     return tagAddEnd_;
 }
 
-Glib::Dispatcher &
-Engine::criterion_changed() throw()
-{
-    return criterionChanged_;
-}
-
 sigc::signal<void> &
 Engine::selection_changed() throw()
 {
     return selectionChanged_;
 }
 
-void
-Engine::set_current_storage_systems(const Engine::StorageMap & storages)
-{
-    currentStorageSystems_ = storages;
-}
-
-void
-Engine::add_current_storage_system(const Glib::ustring & prefix,
-                                   const IStoragePtr & storage)
+sigc::signal<void, PhotoSearchCriteriaList &> &
+Engine::signal_criteria_changed() throw()
 {
-    currentStorageSystems_.insert(std::make_pair(prefix, storage));
-}
-
-IStoragePtr
-Engine::get_current_storage_system(const Glib::ustring & prefix) const
-                                   throw()
-{
-    const StorageMap::const_iterator it
-        = currentStorageSystems_.find(prefix);
-
-    if (currentStorageSystems_.end() == it)
-    {
-        return IStoragePtr();
-    }
-
-    return it->second;
+    return criteriaChanged_;
 }
 
 PhotoList &
@@ -502,4 +320,10 @@ 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 cfbd306..99f29fc 100644
--- a/src/application/engine.h
+++ b/src/application/engine.h
@@ -31,6 +31,7 @@
 #include "photo.h"
 #include "photo-search-criteria.h"
 #include "search-criterion-repo.h"
+#include "thumbnailer.h"
 #include "types.h"
 
 namespace Solang
@@ -56,6 +57,9 @@ class Engine :
         final();
 
         void
+        criteria_changed() throw();
+
+        void
         import(const PhotoPtr & photo,
                const IPhotoSourcePtr & source,
                const IStoragePtr & selected_storage,
@@ -92,28 +96,17 @@ class Engine :
                const TagList & tags,
                const ProgressObserverPtr & observer) throw();
 
-        PhotoList
-        search(const PhotoSearchCriteriaList & criterion,
-               const ProgressObserverPtr & observer
-                   = ProgressObserverPtr()) throw();
-
-        void
-        on_criterion_changed();
-
         void
-        show(const PhotoSearchCriteriaList & criterion) throw();
+        search_async(const PhotoSearchCriteriaList & criteria,
+                     const Database::SlotAsyncPhotos & slot) const
+                     throw();
 
         void
-        show(const PhotoSearchCriteriaList & criterion,
-             const ProgressObserverPtr & observer) throw();
+        export_photos(const IPhotoDestinationPtr & destination)
+                      throw();
 
         void
         export_photos(const IPhotoDestinationPtr & destination,
-                      const IStoragePtr & selected_storage) throw();
-
-        void
-        export_photos(const IPhotoDestinationPtr & destination,
-                      const IStoragePtr & selected_storage,
                       const ProgressObserverPtr & observer) throw();
 
         void
@@ -122,13 +115,8 @@ class Engine :
                   = ProgressObserverPtr());
 
         void
-        save(const PhotoPtr &photo);
-
-        TagList
-        get_tags() const throw();
-
-        void
-        apply_tag_to_photos( PhotoList &photos, const TagPtr &tag );
+        get_tags_async(const Database::SlotAsyncTags & slot) const
+                       throw();
 
         //Group by year
         DatePhotoInfoList
@@ -154,11 +142,8 @@ class Engine :
         Glib::Dispatcher &
         photo_import_end() throw();
 
-        Glib::Dispatcher &
-        photo_render_begin() throw();
-
-        Glib::Dispatcher &
-        photo_render_end() throw();
+        sigc::signal<void, PhotoSearchCriteriaList &> &
+        signal_criteria_changed() throw();
 
         Glib::Dispatcher &
         tag_add_begin() throw();
@@ -166,9 +151,6 @@ class Engine :
         Glib::Dispatcher &
         tag_add_end() throw();
 
-        Glib::Dispatcher &
-        criterion_changed() throw();
-
         sigc::signal<void> &
         selection_changed() throw();
 
@@ -178,17 +160,6 @@ class Engine :
             return DatabasePtr(&database_);
         }
 
-        void
-        set_current_storage_systems(const StorageMap & storages);
-
-        void
-        add_current_storage_system(const Glib::ustring & prefix,
-                                   const IStoragePtr & storage);
-
-        IStoragePtr
-        get_current_storage_system(const Glib::ustring & prefix)
-                                   const throw();
-
         PhotoList &
         get_export_queue() throw();
 
@@ -204,13 +175,10 @@ class Engine :
         inline DeletionQueue &
         get_delete_actions();
 
-    private:
-        PhotoList
-        create_renderable_list_from_photos(
-            const PhotoList & photos,
-            const ProgressObserverPtr & observer
-                = ProgressObserverPtr());
+        Thumbnailer &
+        get_thumbnailer() throw();
 
+    private:
         ProgressObserverPtr observer_;
 
         Glib::Dispatcher photoExportBegin_;
@@ -221,15 +189,12 @@ class Engine :
 
         Glib::Dispatcher photoImportEnd_;
 
-        Glib::Dispatcher photoRenderBegin_;
-
-        Glib::Dispatcher photoRenderEnd_;
-        
         Glib::Dispatcher tagAddBegin_;
 
         Glib::Dispatcher tagAddEnd_;
 
-        Glib::Dispatcher criterionChanged_;
+        sigc::signal<void, PhotoSearchCriteriaList &>
+            criteriaChanged_;
 
         sigc::signal<void> selectionChanged_;
 
@@ -244,6 +209,8 @@ class Engine :
 
         StorageMap currentStorageSystems_;
 
+        Thumbnailer thumbnailer_;
+
         Database database_;
 
         SearchCriterionRepo criterionRepo_;
diff --git a/src/application/main.cpp b/src/application/main.cpp
index 44f4b45..3190aa7 100644
--- a/src/application/main.cpp
+++ b/src/application/main.cpp
@@ -29,7 +29,6 @@
 #include <glibmm.h>
 #include <glibmm/i18n.h>
 #include <gtkmm.h>
-#include <libgdamm.h>
 
 #ifdef ENABLE_NLS
 #include <libintl.h>
@@ -46,7 +45,6 @@ main(int argc, char *argv[])
 
     Glib::thread_init();
     Gio::init();
-    Gnome::Gda::init();
     gegl_init( &argc, &argv );
 
     if (0 != flickcurl_init())
diff --git a/src/attribute/Makefile.am b/src/attribute/Makefile.am
index 569bbc3..4106346 100644
--- a/src/attribute/Makefile.am
+++ b/src/attribute/Makefile.am
@@ -13,10 +13,6 @@ libattribute_la_SOURCES = \
 	date-view-model-column-record.h \
 	date-view.cpp \
 	date-view.h \
-	exif-data-key.cpp \
-	exif-data-key.h \
-	exif-data.cpp \
-	exif-data.h \
 	modification-date.cpp \
 	modification-date.h \
 	photo-tag.cpp \
@@ -40,9 +36,7 @@ libattribute_la_SOURCES = \
 	tag-view.h \
 	tag-view.cpp \
 	tag-view-model-column-record.h \
-	tag-view-model-column-record.cpp \
-	thumbnail.cpp \
-	thumbnail.h	
+	tag-view-model-column-record.cpp
 
 AM_CPPFLAGS = \
 	-DPACKAGE_LOCALE_DIR=\""${datadir}/locale"\" \
@@ -58,10 +52,10 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/renderer \
 	-I$(top_srcdir)/src/storage \
 	$(SOLANG_CFLAGS) \
-	$(EXIV2_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(GTKMM_CFLAGS) \
-	$(GDAMM_CFLAGS) \
 	$(GDL_CFLAGS) \
+	$(TRACKER_CFLAGS) \
 	$(LIBXML_CFLAGS)
 
 AM_CXXFLAGS = \
diff --git a/src/attribute/basic-exif-view.cpp b/src/attribute/basic-exif-view.cpp
index 0f2be05..fd170f7 100644
--- a/src/attribute/basic-exif-view.cpp
+++ b/src/attribute/basic-exif-view.cpp
@@ -1,5 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
  * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
  *
  * Solang is free software: you can redistribute it and/or modify it
@@ -22,6 +23,8 @@
 
 #include <iostream>
 
+#include <glibmm/i18n.h>
+
 #include "application.h"
 #include "basic-exif-view.h"
 #include "exif-data.h"
@@ -83,109 +86,141 @@ BasicExifView::populate(const ExifData& data) throw()
 {
     listStore_->clear();
 
+    const Glib::ustring & camera_data = data.get_camera();
+
+    if (false == camera_data.empty())
     {
+        const Glib::ustring camera_desc = _("Camera");
+        const ExifDataKeyPtr key(new ExifDataKey(camera_desc,
+                                                 "nmm:camera",
+                                                 camera_data));
+
         Gtk::TreeModel::iterator model_iter = listStore_->append();
         Gtk::TreeModel::Row row = *model_iter;
-        const ExifDataKeyPtr key(
-                    new ExifDataKey("Aperture",
-                                    "aperture", data.get_aperture()));
 
         row[modelColumnRecord_.get_column_key()] = key;
-        row[modelColumnRecord_.get_column_description()] = "Aperture";
-        row[modelColumnRecord_.get_column_value()] = data.get_aperture();
+        row[modelColumnRecord_.get_column_description()]
+                                   = camera_desc;
+        row[modelColumnRecord_.get_column_value()] = camera_data;
     }
 
-    {
-        Gtk::TreeModel::iterator model_iter = listStore_->append();
-        Gtk::TreeModel::Row row = *model_iter;
-        const ExifDataKeyPtr key(
-                new ExifDataKey("Shutter Speed",
-                                "shutter_speed",
-                                data.get_shutter_speed()));
-        row[modelColumnRecord_.get_column_key()] = key;
-        row[modelColumnRecord_.get_column_description()] = "Shutter Speed";
-        row[modelColumnRecord_.get_column_value()] = data.get_shutter_speed();
-    }
+    const Glib::ustring & exposure_time_data
+                              = data.get_exposure_time();
 
+    if (false == exposure_time_data.empty())
     {
+        const Glib::ustring exposure_time_desc = _("Exposure time");
+        const ExifDataKeyPtr key(new ExifDataKey(
+                                         exposure_time_desc,
+                                         "nmm:exposureTime",
+                                         data.get_exposure_time()));
+
         Gtk::TreeModel::iterator model_iter = listStore_->append();
         Gtk::TreeModel::Row row = *model_iter;
-        const ExifDataKeyPtr key(
-                new ExifDataKey("Exposure Program",
-                                "exposure_program" ,
-                                data.get_exposure_program()));
+
         row[modelColumnRecord_.get_column_key()] = key;
-        row[modelColumnRecord_.get_column_description()] = "Exposure Program";
-        row[modelColumnRecord_.get_column_value()] = data.get_exposure_program();
+        row[modelColumnRecord_.get_column_description()]
+                                   = exposure_time_desc;
+        row[modelColumnRecord_.get_column_value()]
+                                   = exposure_time_data;
     }
 
+    const Glib::ustring & fnumber_data = data.get_fnumber();
+
+    if (false == fnumber_data.empty())
     {
+        const Glib::ustring fnumber_desc = _("F-number");
+        const ExifDataKeyPtr key(new ExifDataKey(fnumber_desc,
+                                                 "nmm:fnumber",
+                                                 fnumber_data));
+
         Gtk::TreeModel::iterator model_iter = listStore_->append();
         Gtk::TreeModel::Row row = *model_iter;
-        std::ostringstream sout;
-        sout<<data.get_iso_speed();
-        const ExifDataKeyPtr key(
-                new ExifDataKey("ISO Rating",
-                                "iso_speed", sout.str() ) );
+
         row[modelColumnRecord_.get_column_key()] = key;
-        row[modelColumnRecord_.get_column_description()] = "ISO Rating";
-        row[modelColumnRecord_.get_column_value()] = sout.str();
+        row[modelColumnRecord_.get_column_description()]
+                                   = fnumber_desc;
+        row[modelColumnRecord_.get_column_value()]
+                                   = data.get_fnumber();
     }
 
+    const Glib::ustring & iso_speed_data = data.get_iso_speed();
+
+    if (false == iso_speed_data.empty())
     {
+        const Glib::ustring iso_speed_desc = _("ISO speed");
+        const ExifDataKeyPtr key(new ExifDataKey(iso_speed_desc,
+                                                 "nmm:isoSpeed",
+                                                 iso_speed_data));
+
         Gtk::TreeModel::iterator model_iter = listStore_->append();
         Gtk::TreeModel::Row row = *model_iter;
-        const ExifDataKeyPtr key(
-                new ExifDataKey("Exposure Metering Mode",
-                                "metering_mode" ,
-                                data.get_exposure_metering_mode()));
+
         row[modelColumnRecord_.get_column_key()] = key;
         row[modelColumnRecord_.get_column_description()]
-                                = "Exposure Metering Mode";
-        row[modelColumnRecord_.get_column_value()]
-                                = data.get_exposure_metering_mode();
+                                   = iso_speed_desc;
+        row[modelColumnRecord_.get_column_value()] = iso_speed_data;
     }
 
+    const Glib::ustring & metering_mode_data
+                              = data.get_metering_mode();
+
+    if (false == metering_mode_data.empty())
     {
+        const Glib::ustring metering_mode_desc = _("Metering mode");
+        const ExifDataKeyPtr key(new ExifDataKey(
+                                     metering_mode_desc,
+                                     "nmm:meteringMode",
+                                     data.get_metering_mode_enum()));
+
         Gtk::TreeModel::iterator model_iter = listStore_->append();
         Gtk::TreeModel::Row row = *model_iter;
-        const ExifDataKeyPtr key(
-                new ExifDataKey("Actual Focal Length",
-                                "focal_length" ,
-                                data.get_focal_length()));
+
         row[modelColumnRecord_.get_column_key()] = key;
         row[modelColumnRecord_.get_column_description()]
-                                = "Actual Focal Length";
+                                   = metering_mode_desc;
         row[modelColumnRecord_.get_column_value()]
-                                = data.get_focal_length();
+                                   = metering_mode_data;
     }
 
+    const Glib::ustring & focal_length_data = data.get_focal_length();
+
+    if (false == focal_length_data.empty())
     {
+        const Glib::ustring focal_length_desc = _("Focal length");
+        const ExifDataKeyPtr key(new ExifDataKey(focal_length_desc,
+                                                 "nmm:focalLength",
+                                                 focal_length_data));
+
         Gtk::TreeModel::iterator model_iter = listStore_->append();
         Gtk::TreeModel::Row row = *model_iter;
-        const ExifDataKeyPtr key(
-                new ExifDataKey("White Balance",
-                                "white_balance" ,
-                                data.get_white_balance()));
+
         row[modelColumnRecord_.get_column_key()] = key;
         row[modelColumnRecord_.get_column_description()]
-                                = "White Balance";
+                                   = focal_length_desc;
         row[modelColumnRecord_.get_column_value()]
-                                = data.get_white_balance();
+                                   = focal_length_data;
     }
 
+    const Glib::ustring & white_balance_data
+                              = data.get_white_balance();
+
+    if (false == white_balance_data.empty())
     {
+        const Glib::ustring white_balance_desc = _("White balance");
+        const ExifDataKeyPtr key(new ExifDataKey(
+                                     white_balance_desc,
+                                     "nmm:whiteBalance",
+                                     data.get_white_balance_enum()));
+
         Gtk::TreeModel::iterator model_iter = listStore_->append();
         Gtk::TreeModel::Row row = *model_iter;
-        const ExifDataKeyPtr key(
-                new ExifDataKey("35mm Camera Focal Length",
-                                "focal_length_in_film" ,
-                                data.get_focal_length_film()));
+
         row[modelColumnRecord_.get_column_key()] = key;
         row[modelColumnRecord_.get_column_description()]
-                                = "35mm Camera Focal Length";
+                                   = white_balance_desc;
         row[modelColumnRecord_.get_column_value()]
-                                = data.get_focal_length_film();
+                                   = white_balance_data;
     }
 }
 
diff --git a/src/attribute/modification-date.cpp b/src/attribute/modification-date.cpp
index 5a4a95b..c4e101f 100644
--- a/src/attribute/modification-date.cpp
+++ b/src/attribute/modification-date.cpp
@@ -1,5 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
  * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
  *
  * Solang is free software: you can redistribute it and/or modify it
@@ -29,28 +30,10 @@
 namespace Solang
 {
 
-const gint32 ModificationDate::MOD_DAY_COL   = 3;
-const gint32 ModificationDate::MOD_MONTH_COL = 4;
-const gint32 ModificationDate::MOD_YEAR_COL  = 5;
-
 Glib::ustring
 ModificationDate::get_query_criteria() const throw()
 {
-    std::ostringstream sout;
-    if( get_year() > 0 )
-    {
-        sout<<" ( mod_year="<<get_year();
-        if( get_month() > 0 )
-        {
-            sout<<" and mod_month="<<get_month();
-            if( get_day() > 0 )
-            {
-                sout<<" and mod_day="<<get_day();
-            }
-        }
-        sout<<" )";
-    }
-    return sout.str();
+    return Glib::ustring();
 }
 
 PhotoSearchCriteria::ClubbingOperationType
@@ -97,53 +80,4 @@ ModificationDate::get_criteria_icon_path() const throw()
     return PACKAGE_DATA_DIR"/"PACKAGE_TARNAME"/pixmaps/tag-16.png";
 }
 
-void
-ModificationDate::insert(std::vector<Gnome::Gda::Value> &values)
-{
-    values.push_back( Gnome::Gda::Value( get_day() ) ); 
-    values.push_back( Gnome::Gda::Value( get_month() ) ); 
-    values.push_back( Gnome::Gda::Value( get_year() ) ); 
-}
-
-void
-ModificationDate::update(
-                DataModelPtr & model, gint32 row) throw(Glib::Error)
-{
-    if( get_day() != model->get_value_at(
-                                MOD_DAY_COL, row ).get_int())
-    {
-        model->set_value_at(
-                MOD_DAY_COL, row, 
-                            Gnome::Gda::Value( get_day() ) );
-    }
-    
-    if( get_month() != model->get_value_at(
-                                MOD_MONTH_COL, row ).get_int())
-    {
-        model->set_value_at(
-                MOD_MONTH_COL, row, 
-                            Gnome::Gda::Value( get_month() ) );
-    }
-
-    if( get_year() != model->get_value_at(
-                                MOD_YEAR_COL, row ).get_int())
-    {
-        model->set_value_at(
-                MOD_YEAR_COL, row, 
-                            Gnome::Gda::Value( get_year() ) );
-    }
-
-}
-
-void
-ModificationDate::create(const DataModelPtr & data_model, gint32 row)
-{
-    set_day(
-        data_model->get_value_at( MOD_DAY_COL, row ).get_int());    
-    set_month(
-        data_model->get_value_at( MOD_MONTH_COL, row ).get_int());    
-    set_year(
-        data_model->get_value_at( MOD_YEAR_COL, row ).get_int());    
-}
-
 } // namespace Solang
diff --git a/src/attribute/modification-date.h b/src/attribute/modification-date.h
index 569115c..3b371be 100644
--- a/src/attribute/modification-date.h
+++ b/src/attribute/modification-date.h
@@ -1,5 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
  * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
  *
  * Solang is free software: you can redistribute it and/or modify it
@@ -28,11 +29,6 @@ class ModificationDate
     : public PhotoSearchCriteria
 {
     private:
-
-        static const gint32 MOD_DAY_COL;
-        static const gint32 MOD_MONTH_COL;
-        static const gint32 MOD_YEAR_COL;
-
         gint32 day_;
         gint32 month_;
         gint32 year_;    
@@ -160,16 +156,6 @@ class ModificationDate
 
         virtual Glib::ustring
         get_criteria_icon_path() const throw();
-
-        void
-        insert(std::vector<Gnome::Gda::Value> &values);
-
-        void
-        update(DataModelPtr & model, gint32 row) throw(Glib::Error);
-
-        void
-        create(const DataModelPtr & data_model, gint32 row);
-
 };    
 
 } // namespace Solang
diff --git a/src/attribute/photo-tag.cpp b/src/attribute/photo-tag.cpp
index 014678e..4a822ed 100644
--- a/src/attribute/photo-tag.cpp
+++ b/src/attribute/photo-tag.cpp
@@ -1,5 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
  * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
  *
  * Solang is free software: you can redistribute it and/or modify it
@@ -16,25 +17,19 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <iostream>
-#include <sstream>
-
+#include "database.h"
+#include "photo.h"
 #include "photo-tag.h"
+#include "tag.h"
 
 namespace Solang
 {
 
-const gint32 PhotoTag::PHOTOID_COL = 0;
-const gint32 PhotoTag::TAGID_COL = 1;
-
-PhotoTag::PhotoTag()
-    :DBObject()
-{
-}
-
-PhotoTag::PhotoTag( gint32 photoId, gint32 tagId )
-    :photoId_(photoId),
-    tagId_(tagId)
+PhotoTag::PhotoTag(const PhotoPtr & photo, const TagPtr & tag)
+                   throw() :
+    DBObject(),
+    photo_(photo),
+    tag_(tag)
 {
 }
 
@@ -43,84 +38,41 @@ PhotoTag::~PhotoTag() throw()
 }
 
 void
-PhotoTag::set_tagId_( gint32 tagId )
+PhotoTag::delete_async(Database & database,
+                       const SlotAsyncReady & slot) const throw()
 {
-    tagId_ = tagId;
 }
 
-void
-PhotoTag::set_photoId_( gint32 photoId )
+Glib::ustring
+PhotoTag::get_delete_query() const throw()
 {
-    photoId_ = photoId;
+    return Glib::ustring();
 }
 
-void
-PhotoTag::insert(DataModelPtr & model, gint32 lastIndex) throw(Error)
-{
-    std::vector<Gnome::Gda::Value> values;
-    values.push_back( Gnome::Gda::Value( get_photoId_() ) );
-    values.push_back( Gnome::Gda::Value( get_tagId_() ) ); 
-
-    gint32 row = 0;
-
-    try
-    {
-        row = model->append_values( values );
-        create( model, row );
-    }
-    catch( Glib::Error &e)
-    {
-        std::cerr<<"Error:"<<e.what()<<std::endl;
-    }
-
-    if( -1 == row )
-    {
-        //TBD::Error
-    }
-
-    return ;
-}
-
-void
-PhotoTag::update(DataModelPtr & model, gint32 row) throw(Error)
+Glib::ustring
+PhotoTag::get_save_query() const throw()
 {
-    return;    
+    return Glib::ustring::compose("INSERT {"
+                                  "  ?photo nao:hasTag <%1> ."
+                                  "} "
+                                  "WHERE {"
+                                  "  ?photo nie:isStoredAs <%2> ."
+                                  "}",
+                                  tag_->get_urn(), photo_->get_uri());
 }
 
 void
-PhotoTag::create(const DataModelPtr & dataModel, gint32 row)
-                 throw(Error)
-{
-    set_row( row );
-    set_tagId_( dataModel->get_value_at( 
-                        PHOTOID_COL, row ).get_int() );
-    set_tagId_( dataModel->get_value_at( 
-                        TAGID_COL, row ).get_int() );
-    return;
-}
-
-Glib::ustring
-PhotoTag::get_db_object_type_name() const throw()
+PhotoTag::save_async(Database & database, const SlotAsyncReady & slot)
+                     const throw()
 {
-    return "photo_tags";
+    database.save_async(*this, slot);
 }
 
 DeleteActionPtr
 PhotoTag::get_delete_action() throw()
 {
     DeleteActionPtr action( new DeleteAction( "PhotoTag" , NULL ) );
-    std::ostringstream sout;
-    sout<<"delete from photo_tags where tagid="<<get_tagId_()
-        <<" and photoid="<<get_photoId_();
-    action->add_command( sout.str() );
-    set_is_deleted( true );
     return action;
 }
 
-Glib::ustring
-PhotoTag::getQueryCriteria() const
-{
-    return " ";
-}
-
 } // namespace Solang
diff --git a/src/attribute/photo-tag.h b/src/attribute/photo-tag.h
index 329c2b2..c3858d4 100644
--- a/src/attribute/photo-tag.h
+++ b/src/attribute/photo-tag.h
@@ -1,5 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
  * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
  *
  * Solang is free software: you can redistribute it and/or modify it
@@ -24,7 +25,7 @@
 #include <glibmm.h>
 
 #include "db-object.h"
-#include "photo-search-criteria.h"
+#include "types.h"
 
 namespace Solang
 {
@@ -34,62 +35,33 @@ namespace Solang
 class PhotoTag :
     public DBObject
 {
-    private:
-        static const gint32 PHOTOID_COL;
-        static const gint32 TAGID_COL;
-
-    private:
-        gint32        photoId_;
-        gint32        tagId_;
-
     public:
-        PhotoTag();
-        PhotoTag( gint32 photoId, gint32 tagId );
-        ~PhotoTag() throw();
-
-        inline gint32
-        get_photoId_() const throw();
+        PhotoTag(const PhotoPtr & photo, const TagPtr & tag) throw();
 
-        void
-        set_photoId_( gint32 photoId );
-
-        inline gint32
-        get_tagId_() const throw();
-
-        void
-        set_tagId_( gint32 tagId );
+        ~PhotoTag() throw();
 
         virtual void
-        insert(DataModelPtr & model, gint32 lastIndex) throw(Error);
+        delete_async(Database & database, const SlotAsyncReady & slot)
+                     const throw();
 
-        virtual void
-        update(DataModelPtr & model, gint32 row) throw(Error);
+        virtual Glib::ustring
+        get_delete_query() const throw();
 
-        virtual void
-        create(const DataModelPtr & dataModel, gint32 row)
-               throw(Error);
-        
         virtual Glib::ustring
-        get_db_object_type_name() const throw();
+        get_save_query() const throw();
+
+        virtual void
+        save_async(Database & database, const SlotAsyncReady & slot)
+                   const throw();
 
         virtual DeleteActionPtr
         get_delete_action() throw();
 
-        virtual Glib::ustring
-        getQueryCriteria() const;
-};
-
-inline gint32
-PhotoTag::get_photoId_() const throw()
-{
-    return photoId_;
-}
+    private:
+        PhotoPtr photo_;
 
-inline gint32
-PhotoTag::get_tagId_() const throw()
-{
-    return tagId_;
-}
+        TagPtr tag_;
+};
 
 } // namespace Solang
 
diff --git a/src/attribute/property-manager.cpp b/src/attribute/property-manager.cpp
index 264fa92..be02919 100644
--- a/src/attribute/property-manager.cpp
+++ b/src/attribute/property-manager.cpp
@@ -153,6 +153,12 @@ PropertyManager::visit_renderer(
 }
 
 void
+PropertyManager::on_get_exif_data(ExifData & exif_data) throw()
+{
+    basicExifView_.populate(exif_data);
+}
+
+void
 PropertyManager::on_renderer_changed(
                      RendererRegistry & renderer_registry) throw()
 {
@@ -182,8 +188,15 @@ PropertyManager::on_selection_changed() throw()
     if( photos.empty() )
         return;
 
-    basicExifView_.populate( (*photos.begin())->get_exif_data() );
-    histogram_.set((*photos.begin())->get_thumbnail_buffer());
+    const PhotoPtr photo = *photos.begin();
+
+    histogram_.set(photo->get_thumbnail_buffer());
+
+    Engine & engine = application_->get_engine();
+    photo->get_exif_data_async(
+        *engine.get_db(),
+        sigc::mem_fun(*this,
+                      &PropertyManager::on_get_exif_data));
 
     return;
 }
diff --git a/src/attribute/property-manager.h b/src/attribute/property-manager.h
index 7321553..37184cb 100644
--- a/src/attribute/property-manager.h
+++ b/src/attribute/property-manager.h
@@ -68,6 +68,9 @@ public:
 
 protected:
     void
+    on_get_exif_data(ExifData & exif_data) throw();
+
+    void
     on_renderer_changed(RendererRegistry & renderer_registry) throw();
 
     void
diff --git a/src/attribute/search-basket.cpp b/src/attribute/search-basket.cpp
index 4f88a89..d87f1ba 100644
--- a/src/attribute/search-basket.cpp
+++ b/src/attribute/search-basket.cpp
@@ -278,7 +278,7 @@ void
 SearchBasket::apply_criterion()
 {
     Engine & engine = application_->get_engine();
-    engine.criterion_changed().emit();
+    engine.criteria_changed();
     return;
 
 }
diff --git a/src/attribute/tag-manager.cpp b/src/attribute/tag-manager.cpp
index 9002cdf..f09ba22 100644
--- a/src/attribute/tag-manager.cpp
+++ b/src/attribute/tag-manager.cpp
@@ -34,6 +34,7 @@
 #include "i-renderer.h"
 #include "main-window.h"
 #include "photo-tag.h"
+#include "tag.h"
 #include "tag-manager.h"
 #include "tag-new-dialog.h"
 
@@ -168,8 +169,6 @@ TagManager::init(Application & application)
     application_ = &application;
     tagView_.set_application( &application );
 
-    populate_view();
-
     RendererRegistry & renderer_registry
                            = application.get_renderer_registry();
 
@@ -191,6 +190,12 @@ TagManager::init(Application & application)
 
     ui_manager->insert_action_group(actionGroup_);
 
+    Glib::signal_idle().connect_once(
+        sigc::mem_fun(
+            *this,
+            &TagManager::populate_view),
+        Glib::PRIORITY_DEFAULT_IDLE);
+
     initialized_.emit(*this);
 }
 
@@ -253,13 +258,12 @@ TagManager::on_action_tag_new() throw()
     {
         case Gtk::RESPONSE_OK:
         {
-            TagPtr tag( new Tag() );
-            tag->set_name( tag_new_dialog.get_name() );
-            tag->set_description( tag_new_dialog.get_description() );
-            tag->set_icon_path( tag_new_dialog.get_icon_path() );
+            TagPtr tag(new Tag(tag_new_dialog.get_name()));
             DatabasePtr db = application_->get_engine().get_db();
-            tag->save( *db );
-            populate_view();
+            tag->save_async(
+                *db,
+                sigc::mem_fun(*this,
+                              &TagManager::on_updated_tag));
             break;
         }
 
@@ -282,9 +286,6 @@ TagManager::on_action_tag_edit() throw()
     Glib::RefPtr<Gtk::TreeSelection> selected
                                             = tagView_.get_selection();
 
-    if( Tag::ALL_PHOTOS_TAGID == selected->count_selected_rows() )
-        return;
-
     Gtk::TreeModel::iterator item = selected->get_selected();
     const TagViewModelColumnRecord &rec
                                 = tagView_.get_column_records();
@@ -304,12 +305,12 @@ TagManager::on_action_tag_edit() throw()
         {
             case Gtk::RESPONSE_OK:
             {
-                tag->set_name( tag_new_dialog.get_name() );
-                tag->set_description( tag_new_dialog.get_description() );
-                tag->set_icon_path( tag_new_dialog.get_icon_path() );
                 DatabasePtr db = application_->get_engine().get_db();
-                tag->save( *db );
-                populate_view();
+                tag->edit_async(
+                    tag_new_dialog.get_name(),
+                    *db,
+                    sigc::mem_fun(*this,
+                                  &TagManager::on_updated_tag));
                 break;
             }
 
@@ -333,14 +334,10 @@ TagManager::on_action_tag_delete() throw()
     Glib::RefPtr<Gtk::TreeSelection> selected
                                             = tagView_.get_selection();
 
-    if( Tag::ALL_PHOTOS_TAGID == selected->count_selected_rows() )
-        return;
-
     const TagViewModelColumnRecord &rec
                                 = tagView_.get_column_records();
 
-    DeletionQueue &queue
-                = application_->get_engine().get_delete_actions();
+    DatabasePtr db = application_->get_engine().get_db();
 
     const TreeModelPtr model = tagView_.get_model();
     const TreePathList selected_rows = selected->get_selected_rows();
@@ -353,12 +350,9 @@ TagManager::on_action_tag_delete() throw()
         Gtk::TreeModel::Row row = *model_iter;
         TagPtr tag = row[ rec.get_column_tag() ];
 
-        if( tag && tag->get_tag_id() )
-        {
-            DeleteActionPtr action = tag->get_delete_action();
-            queue.schedule_delete_action( action );
-        }
-
+        tag->delete_async(*db,
+                          sigc::mem_fun(*this,
+                                        &TagManager::on_updated_tag));
     }
 }
 
@@ -367,30 +361,32 @@ TagManager::on_action_apply_tag() throw()
 {
     Glib::RefPtr<Gtk::TreeSelection> selected
                                             = tagView_.get_selection();
+    Gtk::TreeModel::iterator item = selected->get_selected();
 
-    if( 0 == selected->count_selected_rows() )
+    if (false == item)
+    {
         return;
+    }
 
-    Gtk::TreeModel::iterator item = selected->get_selected();
     const TagViewModelColumnRecord &rec
                                 = tagView_.get_column_records();
 
-    if( item != selected->get_model()->children().end() )
-    {
-        Gtk::TreeModel::Row row= (*item);
-        TagPtr tag = row[ rec.get_column_tag() ];
+    Gtk::TreeModel::Row row= (*item);
+    TagPtr tag = row[ rec.get_column_tag() ];
 
-        if( Tag::ALL_PHOTOS_TAGID == tag->get_tag_id() )
-            return;
+    RendererRegistry & renderer_registry
+        = application_->get_renderer_registry();
+    const IRendererPtr renderer = renderer_registry.get_current();
 
-        RendererRegistry & renderer_registry
-            = application_->get_renderer_registry();
-        const IRendererPtr renderer = renderer_registry.get_current();
+    const DatabasePtr db = application_->get_engine().get_db();
+    PhotoList photos = renderer->get_current_selection();
 
-        PhotoList photos = renderer->get_current_selection();
-
-        Engine & engine = application_->get_engine();
-        engine.apply_tag_to_photos( photos, tag );
+    for (PhotoList::const_iterator photos_iter = photos.begin();
+         photos.end() != photos_iter;
+         photos_iter++)
+    {
+        PhotoTag photo_tag(*photos_iter, tag);
+        photo_tag.save_async(*db, sigc::slot<void>());
     }
 
     return;
@@ -399,7 +395,7 @@ TagManager::on_action_apply_tag() throw()
 void
 TagManager::on_action_remove_tag() throw()
 {
-    Glib::RefPtr<Gtk::TreeSelection> selected
+/*    Glib::RefPtr<Gtk::TreeSelection> selected
                                             = tagView_.get_selection();
 
     if( 0 == selected->count_selected_rows() )
@@ -432,12 +428,18 @@ TagManager::on_action_remove_tag() throw()
             DeleteActionPtr action = photoTag.get_delete_action();
             queue.schedule_delete_action( action );
         }
-    }
+    }*/
 
     return;
 }
 
 void
+TagManager::on_get_tags(TagList & tags) throw()
+{
+    tagView_.populate(tags);
+}
+
+void
 TagManager::on_renderer_changed(RendererRegistry & renderer_registry)
                                 throw()
 {
@@ -451,11 +453,18 @@ TagManager::on_renderer_changed(RendererRegistry & renderer_registry)
 }
 
 void
+TagManager::on_updated_tag() throw()
+{
+    populate_view();
+}
+
+void
 TagManager::populate_view() throw()
 {
     Engine & engine = application_->get_engine();
-    TagList tags = engine.get_tags();
-    tagView_.populate(tags);
+    engine.get_tags_async(sigc::mem_fun(
+                              *this,
+                              &TagManager::on_get_tags));
 }
 
 void
diff --git a/src/attribute/tag-manager.h b/src/attribute/tag-manager.h
index 0273a1f..c68a0b5 100644
--- a/src/attribute/tag-manager.h
+++ b/src/attribute/tag-manager.h
@@ -81,9 +81,15 @@ protected:
     on_action_remove_tag() throw();
 
     void
+    on_get_tags(TagList & tags) throw();
+
+    void
     on_renderer_changed(RendererRegistry & renderer_registry) throw();
 
     void
+    on_updated_tag() throw();
+
+    void
     populate_view() throw();
 
     void
diff --git a/src/attribute/tag-new-dialog.cpp b/src/attribute/tag-new-dialog.cpp
index e7bc18b..9f5abc3 100644
--- a/src/attribute/tag-new-dialog.cpp
+++ b/src/attribute/tag-new-dialog.cpp
@@ -210,20 +210,20 @@ TagNewDialog::setup_gui() throw()
     iconButton_.set_size_request(64, 64);
     iconButton_.signal_clicked().connect(sigc::mem_fun(*this,
         &TagNewDialog::on_icon_button_clicked));
-    mainTable_.attach(iconButton_, 0, 1, 0, 2,
-                      Gtk::FILL | Gtk::EXPAND,
-                      Gtk::FILL | Gtk::EXPAND,
-                      0, 0);
+//    mainTable_.attach(iconButton_, 0, 1, 0, 2,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      0, 0);
 
-    mainTable_.attach(parentLabel_, 1, 2, 0, 1,
-                      Gtk::FILL | Gtk::EXPAND,
-                      Gtk::FILL | Gtk::EXPAND,
-                      0, 0);
+//    mainTable_.attach(parentLabel_, 1, 2, 0, 1,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      0, 0);
 
-    mainTable_.attach(parentComboBox_, 2, 3, 0, 1,
-                      Gtk::FILL | Gtk::EXPAND,
-                      Gtk::FILL | Gtk::EXPAND,
-                      0, 0);
+//    mainTable_.attach(parentComboBox_, 2, 3, 0, 1,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      0, 0);
 
     mainTable_.attach(nameLabel_, 1, 2, 1, 2,
                       Gtk::FILL | Gtk::EXPAND,
@@ -235,19 +235,19 @@ TagNewDialog::setup_gui() throw()
                       Gtk::FILL | Gtk::EXPAND,
                       0, 0);
 
-    mainTable_.attach(descriptionLabel_, 1, 2, 2, 3,
-                      Gtk::FILL | Gtk::EXPAND,
-                      Gtk::FILL | Gtk::EXPAND,
-                      0, 0);
+//    mainTable_.attach(descriptionLabel_, 1, 2, 2, 3,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      0, 0);
 
     descriptionScrolledWindow_.set_policy(Gtk::POLICY_AUTOMATIC,
                                           Gtk::POLICY_AUTOMATIC);
-    mainTable_.attach(descriptionScrolledWindow_, 2, 3, 2, 3,
-                      Gtk::FILL | Gtk::EXPAND,
-                      Gtk::FILL | Gtk::EXPAND,
-                      0, 0);
+//    mainTable_.attach(descriptionScrolledWindow_, 2, 3, 2, 3,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      Gtk::FILL | Gtk::EXPAND,
+//                      0, 0);
 
-    descriptionScrolledWindow_.add(descriptionTextView_);
+//    descriptionScrolledWindow_.add(descriptionTextView_);
 
     add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
     add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
diff --git a/src/attribute/tag-view.cpp b/src/attribute/tag-view.cpp
index 12601a6..850ae3a 100644
--- a/src/attribute/tag-view.cpp
+++ b/src/attribute/tag-view.cpp
@@ -99,9 +99,7 @@ TagView::populate(const TagList & tags) throw()
         row[modelColumnRecord_.get_column_tag()] = tag;
         if( isSelectionAllowed_ )
         {
-            row[modelColumnRecord_.get_column_selected()]
-                        = (Tag::ALL_PHOTOS_TAGID != tag->get_tag_id())
-                            ? false : true;
+            row[modelColumnRecord_.get_column_selected()] = false;
         }
 
         PixbufPtr pixbuf;
@@ -139,8 +137,6 @@ TagView::on_row_activated ( const Gtk::TreeModel::Path& path,
     Gtk::TreeModel::Row row = (*current);
 
     TagPtr tag = row[modelColumnRecord_.get_column_tag()];
-    if( Tag::ALL_PHOTOS_TAGID == tag->get_tag_id() )
-        return; //User will not be able to unselect
 
     row[modelColumnRecord_.get_column_selected()] 
             = !( row[modelColumnRecord_.get_column_selected()] ) ;
diff --git a/src/attribute/tag.cpp b/src/attribute/tag.cpp
index 30c1201..bf68ae9 100644
--- a/src/attribute/tag.cpp
+++ b/src/attribute/tag.cpp
@@ -23,28 +23,19 @@
 #include <iostream>
 #include <sstream>
 
+#include "database.h"
 #include "id-base.h"
 #include "tag.h"
 
 namespace Solang
 {
 
-const gint32 Tag::ALL_PHOTOS_TAGID = 0;
-
-const gint32 Tag::TAGID_COL = 0;
-const gint32 Tag::NAME_COL = 1;
-const gint32 Tag::DESCRIPTION_COL = 2;
-const gint32 Tag::ICONPATH_COL = 3;
-
-Tag::Tag() throw() :
+Tag::Tag(const Glib::ustring & name, const std::string & urn)
+         throw() :
     DBObject(),
-    PhotoSearchCriteria()
-{
-}
-
-Tag::Tag(gint tagId, const Glib::ustring & name) throw() :
-    tagId_(tagId),
-    name_(name)
+    PhotoSearchCriteria(),
+    name_(name),
+    urn_(urn)
 {
 }
 
@@ -53,98 +44,81 @@ Tag::~Tag() throw()
 }
 
 void
-Tag::set_tag_id(gint tag_id) throw()
+Tag::delete_async(Database & database, const SlotAsyncReady & slot)
+                  const throw()
 {
-    tagId_ = tag_id;
+    database.delete_async(*this, slot);
 }
 
-void
-Tag::set_name(const Glib::ustring & name) throw()
+Glib::ustring
+Tag::get_delete_query() const throw()
 {
-    name_ = name;
+    return Glib::ustring::compose("DELETE {"
+                                  "  <%1> a nao:Tag ."
+                                  "}",
+                                  urn_);
 }
 
-void
-Tag::set_description(const Glib::ustring & description) throw()
+Glib::ustring
+Tag::get_query_criteria() const throw()
 {
-    description_ = description;
+    return Glib::ustring::compose("nao:hasTag <%1> .", urn_);
+}
+
+Glib::ustring
+Tag::get_save_query() const throw()
+{
+    return Glib::ustring::compose("INSERT {"
+                                  "  _:tag a nao:Tag ;"
+                                  "  nao:prefLabel '%1' ."
+                                  "} "
+                                  "WHERE {"
+                                  "  OPTIONAL {"
+                                  "     ?tag a nao:Tag ;"
+                                  "     nao:prefLabel '%2'"
+                                  "  } ."
+                                  "  FILTER (!bound(?tag)) "
+                                  "}",
+                                  name_, name_);
 }
 
 void
-Tag::insert(DataModelPtr & model, gint32 lastIndex) throw(Error)
+Tag::save_async(Database & database, const SlotAsyncReady & slot)
+                const throw()
 {
-    std::vector<Gnome::Gda::Value> values;
-    values.push_back( Gnome::Gda::Value( lastIndex + 1 ) ); //tagid
-    values.push_back( Gnome::Gda::Value( get_name() ) );
-    values.push_back( Gnome::Gda::Value( get_description() ) ); 
-    values.push_back( Gnome::Gda::Value( get_icon_path() ) ); 
-
-    gint32 row = model->append_values( values );
-
-    if( -1 == row )
-    {
-        //TBD::Error
-    }
-    set_tag_id( lastIndex + 1 );
-    set_row( row );
-
-    return ;
-
+    database.save_async(*this, slot);
 }
 
 void
-Tag::update(DataModelPtr & model, gint32 row) throw(Error)
-{
-    try
-    {
-        std::vector<Gnome::Gda::Value> values;
-        values.push_back( Gnome::Gda::Value( get_tag_id() ) );
-        values.push_back( Gnome::Gda::Value( get_name() ) );
-        values.push_back( Gnome::Gda::Value( get_description() ) );
-        values.push_back( Gnome::Gda::Value( get_icon_path() ) );
-        model->set_values( row, values );
-    }
-    catch (Glib::Error & e)
-    {
-        std::cerr << "Error::Could not save: "
-                  << e.what() << std::endl;
-    }
-
-    return;    
+Tag::edit_async(const Glib::ustring & name,
+                Database & database,
+                const SlotAsyncReady & slot) throw()
+{
+    database.edit_async(*this, name, slot);
 }
 
-void
-Tag::create(const DataModelPtr & dataModel, gint32 row) throw(Error)
+Glib::ustring
+Tag::get_edit_query(const Glib::ustring & name) const throw()
 {
-    set_row( row );
-    set_tag_id( dataModel->get_value_at( 
-                        TAGID_COL, row ).get_int() );
-    set_name( dataModel->get_value_at( 
-                        NAME_COL, row ).get_string() );
-    set_description( dataModel->get_value_at( 
-                        DESCRIPTION_COL, row ).get_string() );
-    set_icon_path( dataModel->get_value_at( 
-                        ICONPATH_COL, row ).get_string() );
-    return;
+    return Glib::ustring::compose("DELETE {"
+                                  "  <%1> nao:prefLabel '%2' ."
+                                  "} "
+                                  "INSERT {"
+                                  "  <%3> nao:prefLabel '%4' ."
+                                  "}",
+                                  urn_, name_, urn_, name);
 }
 
-#if 0
-Glib::ustring Tag::getCreateSQL() throw(Error)
+void
+Tag::set_name(const Glib::ustring & name) throw()
 {
-    std::ostringstream sout;
-    Glib::ustring sql("insert into tags(tagid, tag, description, iconPath) values(NULL,'");
-    sout<<get_name()<<"','"<<;
-    sout<<get_description()<<"','";
-    sout<<get_icon_path()<<"')";
-    sql += sout.str();
-    
+    name_ = name;
 }
-#endif
 
-Glib::ustring
-Tag::get_db_object_type_name() const throw()
+void
+Tag::set_description(const Glib::ustring & description) throw()
 {
-    return "tags";
+    description_ = description;
 }
 
 DeleteActionPtr
@@ -152,33 +126,9 @@ Tag::get_delete_action() throw()
 {
     DeleteActionPtr action(
             new DeleteAction(get_criteria_description(), this ));
-    if( get_is_deleted() )
-        return action;
-
-    {
-        std::ostringstream sout;
-        sout<<"delete from tags where tagid="<<get_tag_id();
-        action->add_command( sout.str() );
-    }
-    {
-        std::ostringstream sout;
-        sout<<"delete from photo_tags where tagid="<<get_tag_id();
-        action->add_command( sout.str() );
-    }
-    set_is_deleted( true );
     return action;
 }
 
-Glib::ustring
-Tag::get_query_criteria() const throw()
-{
-    std::ostringstream sout;
-
-    sout << " photo_tags.tagid ="<<get_tag_id() << " ";
-
-    return sout.str();
-}
-
 void
 Tag::set_icon_path(Glib::ustring const & value)
 {
@@ -209,4 +159,10 @@ Tag::get_criteria_icon_path() const throw()
     return PACKAGE_DATA_DIR"/"PACKAGE_TARNAME"/pixmaps/tag-16.png";
 }
 
+const std::string &
+Tag::get_urn() const throw()
+{
+    return urn_;
+}
+
 } // namespace Solang
diff --git a/src/attribute/tag.h b/src/attribute/tag.h
index f79461a..ec78b53 100644
--- a/src/attribute/tag.h
+++ b/src/attribute/tag.h
@@ -30,37 +30,47 @@
 namespace Solang
 {
 
+class Database;
+
 class Tag :
     public DBObject,
     public PhotoSearchCriteria 
 {
-    public:
-        static const gint32 ALL_PHOTOS_TAGID;
-
     private:
-        static const gint32 TAGID_COL;
-        static const gint32 NAME_COL;
-        static const gint32 DESCRIPTION_COL;
-        static const gint32 ICONPATH_COL;
-
-    private:
-        gint        tagId_;
-        Glib::ustring  name_;
+        Glib::ustring name_;
         Glib::ustring  description_;
         Glib::ustring  iconPath_;
+        std::string urn_;
 
     public:
-        Tag() throw();
-
-        Tag(gint tag_id, const Glib::ustring & name) throw();
+        Tag(const Glib::ustring & name,
+            const std::string & urn = std::string())
+            throw();
 
+        virtual
         ~Tag() throw();
 
-        inline gint
-        get_tag_id() const throw();
+        virtual void
+        delete_async(Database & database, const SlotAsyncReady & slot)
+                     const throw();
+
+        virtual Glib::ustring
+        get_delete_query() const throw();
+
+        virtual Glib::ustring
+        get_save_query() const throw();
+
+        virtual void
+        save_async(Database & database, const SlotAsyncReady & slot)
+                   const throw();
 
         void
-        set_tag_id(gint tag_id) throw();
+        edit_async(const Glib::ustring & name,
+                   Database & database,
+                   const SlotAsyncReady & slot) throw();
+
+        Glib::ustring
+        get_edit_query(const Glib::ustring & name) const throw();
 
         inline const Glib::ustring &
         get_name() const throw();
@@ -80,19 +90,6 @@ class Tag :
         void
         set_icon_path(const Glib::ustring & icon_path);
 
-        virtual void
-        insert(DataModelPtr & model, gint32 lastIndex) throw(Error);
-
-        virtual void
-        update(DataModelPtr & model, gint32 row) throw(Error);
-
-        virtual void
-        create(const DataModelPtr & dataModel, gint32 row)
-               throw(Error);
-        
-        virtual Glib::ustring
-        get_db_object_type_name() const throw();
-
         virtual Glib::ustring
         get_query_criteria() const throw();
 
@@ -111,15 +108,10 @@ class Tag :
         virtual Glib::ustring
         get_criteria_icon_path() const throw();
 
-
+        const std::string &
+        get_urn() const throw();
 };
 
-inline gint
-Tag::get_tag_id() const throw()
-{
-    return tagId_;
-}
-
 inline const Glib::ustring &
 Tag::get_name() const throw()
 {
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 1041b33..4285dbd 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -1,12 +1,33 @@
 noinst_LTLIBRARIES =	libcommon.la
 
+libcommon_la_built_sources = \
+	solang-marshal.c \
+	solang-marshal.h \
+	org-freedesktop-thumbnails-thumbnailer1-dbus-bindings.h
+
+BUILT_SOURCES = \
+	$(libcommon_la_built_sources)
+
 libcommon_la_SOURCES = \
+	$(libcommon_la_built_sources) \
+	database.cpp \
+	database.h \
+	delete-action.cpp \
+	delete-action.h \
+	db-object.cpp \
+	db-object.h \
+	tracker-client.cpp \
+	tracker-client.h \
 	content-type-repo.cpp \
 	content-type-repo.h \
 	cursor-changer.cpp \
 	cursor-changer.h \
 	error.cpp \
 	error.h \
+	exif-data-key.cpp \
+	exif-data-key.h \
+	exif-data.cpp \
+	exif-data.h \
 	export-queue-operations.cpp \
 	export-queue-operations.h \
 	flickr-context.cpp \
@@ -57,6 +78,10 @@ libcommon_la_SOURCES = \
 	spinner-tool-item.h \
 	thumbbuf-maker.cpp \
 	thumbbuf-maker.h \
+	thumbnailer.cpp \
+	thumbnailer.h \
+	thumbnailer-proxy.cpp \
+	thumbnailer-proxy.h \
 	types.h
 
 AM_CPPFLAGS = \
@@ -73,13 +98,55 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/renderer \
 	-I$(top_srcdir)/src/storage \
 	$(SOLANG_CFLAGS) \
-	$(EXIV2_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(FLICKCURL_CFLAGS) \
 	$(GTKMM_CFLAGS) \
-	$(GDAMM_CFLAGS) \
 	$(GDL_CFLAGS) \
 	$(GEGL_CFLAGS) \
-	$(BABL_CFLAGS)
+	$(BABL_CFLAGS) \
+	$(TRACKER_CFLAGS)
 
 AM_CXXFLAGS = \
 	 -Wall
+
+EXTRA_DIST = \
+	solang-marshal.list \
+	org-freedesktop-thumbnails-thumbnailer1-dbus.xml
+
+if MAINTAINER_MODE
+CLEANFILES = \
+	xgen-tmc \
+	xgen-tmh
+
+DISTCLEANFILES = \
+	$(libcommon_la_built_sources) \
+	stamp-solang-marshal.h
+
+org-freedesktop-thumbnails-thumbnailer1-dbus-bindings.h: org-freedesktop-thumbnails-thumbnailer1-dbus.xml Makefile
+	$(AM_V_GEN) $(DBUS_BINDING_TOOL) --mode=glib-client --prefix=org-freedesktop-thumbnails-thumbnailer1 $< > $@
+
+solang-marshal.h: stamp-solang-marshal.h
+	@true
+
+stamp-solang-marshal.h: solang-marshal.list Makefile
+	$(AM_V_GEN) ( \
+		cd $(srcdir) \
+		&& ( glib-genmarshal \
+			--prefix=solang_marshal \
+			--header solang-marshal.list ) >> xgen-tmh \
+		&& ( cmp -s xgen-tmh solang-marshal.h || cp xgen-tmh solang-marshal.h ) \
+		&& rm -f xgen-tmh \
+		&& echo timestamp > $(@F) \
+	)
+
+solang-marshal.c: solang-marshal.list solang-marshal.h Makefile
+	$(AM_V_GEN) ( \
+		cd $(srcdir) \
+		&& echo "#include \"solang-marshal.h\"" > xgen-tmc \
+		&& ( glib-genmarshal \
+			--prefix=solang_marshal \
+			--body solang-marshal.list ) >> xgen-tmc \
+		&& cp xgen-tmc solang-marshal.c \
+		&& rm -f xgen-tmc \
+	)
+endif
diff --git a/src/common/database.cpp b/src/common/database.cpp
new file mode 100644
index 0000000..a17dc1e
--- /dev/null
+++ b/src/common/database.cpp
@@ -0,0 +1,353 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
+ * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
+ *
+ * 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <glibmm/i18n.h>
+
+#include "database.h"
+#include "exif-data.h"
+#include "photo.h"
+#include "photo-tag.h"
+#include "progress-observer.h"
+#include "tag.h"
+#include "date-photo-info.h"
+
+namespace Solang
+{
+
+class Comparator
+{
+    public:
+        bool operator()  ( const PhotoSearchCriteriaPtr &lhs,
+                            const PhotoSearchCriteriaPtr &rhs )
+        {
+            return lhs->get_id() < rhs->get_id();
+        }
+};
+
+Database::Database() :
+    trackerClient_()
+{
+}
+
+//Database::Database( const Database &rhs )
+//    : path_(rhs.path_)
+//{
+//}
+
+//Database &
+//Database::operator =( const Database &rhs )
+//{
+//    if( this != &rhs )
+//    {
+//        path_ = rhs.path_;
+//    }
+//
+//    return *this;
+//}
+
+Database::~Database()
+{
+}
+
+void
+Database::get_exif_data_async(const Photo & photo,
+                              const SlotAsyncExifData & slot) const
+                              throw()
+{
+    trackerClient_.sparql_query_async(
+        photo.get_exif_data_query(),
+        sigc::bind(sigc::mem_fun(*this,
+                                 &Database::on_async_exif_data),
+                   slot));
+}
+
+void
+Database::delete_async(const Tag & tag, const SlotAsyncReady & slot)
+                       throw()
+{
+    trackerClient_.sparql_update_async(
+        tag.get_delete_query(),
+        sigc::bind(sigc::mem_fun(*this, &Database::on_async_ready),
+                   slot));
+}
+
+void
+Database::edit_async(Tag & tag,
+                     const Glib::ustring & name,
+                     const SlotAsyncReady & slot) throw()
+{
+    trackerClient_.sparql_update_async(
+        tag.get_edit_query(name),
+        sigc::bind(sigc::mem_fun(*this, &Database::on_async_ready),
+                   slot));
+    tag.set_name(name);
+}
+
+void
+Database::save_async(const Photo & photo, const SlotAsyncReady & slot)
+                     throw()
+{
+}
+
+void
+Database::save_async(const PhotoTag & photo_tag,
+                     const SlotAsyncReady & slot) throw()
+{
+    trackerClient_.sparql_update_async(
+        photo_tag.get_save_query(),
+        sigc::bind(sigc::mem_fun(*this, &Database::on_async_ready),
+                   slot));
+}
+
+void
+Database::save_async(const Tag & tag, const SlotAsyncReady & slot)
+                     throw()
+{
+    trackerClient_.sparql_update_async(
+        tag.get_save_query(),
+        sigc::bind(sigc::mem_fun(*this, &Database::on_async_ready),
+                   slot));
+}
+
+void
+Database::search_async(const PhotoSearchCriteriaList & criteria,
+                       const SlotAsyncPhotos & slot) const throw()
+{
+    Glib::ustring clauses = "";
+
+    for (PhotoSearchCriteriaList::const_iterator it = criteria.begin();
+         criteria.end() != it;
+         it++)
+    {
+        clauses += Glib::ustring::compose(
+                                      "{?photo %1}",
+                                      (*it)->get_query_criteria());
+    }
+
+    const Glib::ustring query
+        = Glib::ustring::compose(
+              "SELECT ?photo ?mime "
+              "WHERE {"
+              "  ?photo a nmm:Photo ;"
+              "  nie:mimeType ?mime ."
+              "  %1"
+              "}",
+              clauses);
+
+    trackerClient_.sparql_query_async(
+        query.c_str(),
+        sigc::bind(sigc::mem_fun(*this,
+                                 &Database::on_async_photos),
+                   slot));
+}
+
+//Group by year
+DatePhotoInfoList
+Database::get_dates_with_picture_count(
+              const ProgressObserverPtr & observer)
+{
+    Glib::ustring sql
+        = "select 0, 0, mod_year, count(*) from photos ";
+    sql += "group by mod_year";
+    return get_dates_with_picture_count( sql, observer );
+}
+
+//Group by year, month
+DatePhotoInfoList
+Database::get_dates_with_picture_count(
+              gint year,
+              const ProgressObserverPtr & observer)
+{
+    std::ostringstream sout;
+    sout<<"select 0, mod_month, mod_year, count(*) from photos ";
+    sout<<"where mod_year="<<year<<" ";
+    sout<<"group by mod_year,mod_month ";
+//    sout<<"order by mod_year desc, mod_month desc";
+    return get_dates_with_picture_count( sout.str(), observer );
+}
+
+//Group by year, month, day
+DatePhotoInfoList
+Database::get_dates_with_picture_count(
+              gint year, gint month,
+              const ProgressObserverPtr & observer)
+{
+    std::ostringstream sout;
+    sout<<"select mod_day, mod_month, mod_year, count(*) from photos ";
+    sout<<"where mod_year="<<year<<" ";
+    sout<<"and mod_month="<<month<<" ";
+    sout<<"group by mod_year,mod_month,mod_day ";
+//    sout<<"order by mod_year desc, mod_month desc, mod_day desc";
+    return get_dates_with_picture_count( sout.str(), observer );
+}
+
+DatePhotoInfoList
+Database::get_dates_with_picture_count(
+              const Glib::ustring & sql,
+              const ProgressObserverPtr & observer)
+{
+    DatePhotoInfoList infos;
+
+/*    try
+    {
+        const DataModelPtr model
+            = gdaConnection_->statement_execute_select(
+                  sql, Gnome::Gda::STATEMENT_MODEL_RANDOM_ACCESS);
+
+        const gint32 numRows
+                         = static_cast<gint32>(model->get_n_rows());
+
+        if (0 != observer)
+        {
+            observer->set_event_description(_("Summarizing photos"));
+            observer->set_num_events(numRows);
+            observer->set_current_events(0);
+        }
+
+        for( gint32 row = 0; row < numRows; row++ )
+        {
+            if (0 != observer && true == observer->get_stop())
+            {
+                break;
+            }
+
+            infos.push_back(
+                DatePhotoInfo(
+                    ModificationDate(
+                        model->get_value_at( 0, row ).get_int(),
+                        model->get_value_at( 1, row ).get_int(),
+                        model->get_value_at( 2, row ).get_int()),
+                    model->get_value_at( 3, row ).get_int()));
+
+            if (0 != observer)
+            {
+                observer->receive_event_notifiation();
+            }
+        }
+
+        if (0 != observer)
+        {
+            observer->reset();
+        }
+    }
+    catch (Glib::Error &e)
+    {
+        std::cerr << __FILE__ << ":" << __LINE__ << ", "
+                  << __FUNCTION__ << ": " << e.what()
+                  << std::endl;
+    }
+*/
+    return infos;
+}
+
+void
+Database::get_tags_async(const SlotAsyncTags & slot) const throw()
+{
+    trackerClient_.sparql_query_async(
+        "SELECT DISTINCT ?t ?u "
+        "WHERE {"
+        "  ?u a nao:Tag ;"
+        "  nao:prefLabel ?t ."
+        "} "
+        "ORDER BY ASC(?t)",
+        sigc::bind(sigc::mem_fun(*this, &Database::on_async_tags),
+                   slot));
+}
+
+void
+Database::on_async_exif_data(std::vector<UStringList> & result,
+                             const SlotAsyncExifData & slot) const
+                             throw()
+{
+    if (1 != result.size())
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Unexpected result" << std::endl;
+    }
+
+    ExifData exif_data;
+
+    if (false == result.empty())
+    {
+        const UStringList & data = result.front();
+        Photo::parse_exif_data(data, exif_data);
+    }
+
+    if (0 != slot)
+    {
+        slot(exif_data);
+    }
+}
+
+void
+Database::on_async_photos(std::vector<UStringList> & result,
+                          const SlotAsyncPhotos & slot) const throw()
+{
+    PhotoList photos;
+    for (std::vector<UStringList>::const_iterator it = result.begin();
+         result.end() != it;
+         it++)
+    {
+        PhotoPtr photo(new Photo((*it)[0], (*it)[1]));
+        photos.push_back(photo);
+    }
+
+    if (0 != slot)
+    {
+        slot(photos);
+    }
+}
+
+void
+Database::on_async_ready(const SlotAsyncReady & slot) const throw()
+{
+    if (0 != slot)
+    {
+        slot();
+    }
+}
+
+void
+Database::on_async_tags(std::vector<UStringList> & result,
+                        const SlotAsyncTags & slot) const throw()
+{
+    TagList tags;
+    for (std::vector<UStringList>::const_iterator it = result.begin();
+         result.end() != it;
+         it++)
+    {
+        TagPtr tag(new Tag((*it)[0], (*it)[1]));
+        tags.push_back(tag);
+    }
+
+    if (0 != slot)
+    {
+        slot(tags);
+    }
+}
+
+} // namespace Solang
diff --git a/src/database/database.h b/src/common/database.h
similarity index 50%
rename from src/database/database.h
rename to src/common/database.h
index adfa705..cfdff3b 100644
--- a/src/database/database.h
+++ b/src/common/database.h
@@ -23,68 +23,66 @@
 #include <set>
 #include <tr1/memory>
 
-#include <libgdamm.h>
+#include <sigc++/sigc++.h>
 
-#include "db-table.h"
-#include "photo.h"
 #include "photo-search-criteria.h"
-#include "tag.h"
+#include "tracker-client.h"
 #include "types.h"
 
 namespace Solang
 {
 
+class Photo;
+class PhotoTag;
+class Tag;
+
 class Database
 {
     private:
-        static const Glib::ustring DB_NAME;
-        Glib::ustring path_; //Path to SQLLite database
-        ConnectionPtr gdaConnection_;
-        std::map<Glib::ustring, DBTablePtr> tables_;
+        TrackerClient trackerClient_;
 
     public:
-        Database(const Glib::ustring & path);
+        typedef sigc::slot<void, ExifData &> SlotAsyncExifData;
 
-        Database( const Database &rhs );
+        typedef sigc::slot<void, PhotoList &> SlotAsyncPhotos;
 
-        Database & operator =( const Database &rhs );
+        typedef sigc::slot<void> SlotAsyncReady;
 
-        ~Database();
+        typedef sigc::slot<void, TagList &> SlotAsyncTags;
 
-        inline const Glib::ustring &
-        get_path() const;
+        Database();
 
-        void
-        set_path(const Glib::ustring & path);
+        ~Database();
 
         void
-        open() throw(Error);
+        delete_async(const Tag & tag, const SlotAsyncReady & slot)
+                     throw();
 
-        //Base functions
-
-        //Save DBObject(s) to table
         void
-        save( DBObject &object ) throw(Error);
+        edit_async(Tag & tag,
+                   const Glib::ustring & name,
+                   const SlotAsyncReady & slot) throw();
 
         void
-        save( const DBObjectList &objects,
-              ProgressObserverPtr &observer ) throw(Error);
+        get_exif_data_async(const Photo & photo,
+                            const SlotAsyncExifData & slot) const
+                            throw();
 
-        //Get table object
-        DBTablePtr
-        getTable(const Glib::ustring &tableName) const;
+        void
+        save_async(const Photo & photo, const SlotAsyncReady & slot)
+                   throw();
 
         void
-        run_sql(const Glib::ustring &sql) throw(Error);
+        save_async(const PhotoTag & photo_tag,
+                   const SlotAsyncReady & slot) throw();
 
         void
-        close() throw(Error);
+        save_async(const Tag & tag, const SlotAsyncReady & slot)
+                   throw();
 
-        //Utility functions
-        //The following function list of valid photo id's
-        PhotoList
-        search( const PhotoSearchCriteriaList &criterion,
-                const ProgressObserverPtr & observer) throw(Error);
+        void
+        search_async(const PhotoSearchCriteriaList & criteria,
+                     const SlotAsyncPhotos & slot) const throw();
 
         //Group by year
         DatePhotoInfoList
@@ -101,27 +99,31 @@ class Database
             gint year, gint month,
             const ProgressObserverPtr &);
 
+        void
+        get_tags_async(const SlotAsyncTags & slot) const throw();
+
     private:
         DatePhotoInfoList
         get_dates_with_picture_count(
             const Glib::ustring & sql,
             const ProgressObserverPtr &);
 
-        bool
-        db_file_exists() const throw();
+        void
+        on_async_exif_data(std::vector<UStringList> & result,
+                           const SlotAsyncExifData & slot) const
+                           throw();
 
         void
-        create_db() throw(Error);
+        on_async_photos(std::vector<UStringList> & result,
+                        const SlotAsyncPhotos & slot) const throw();
 
-//      TagList getTags(const PhotoPtr &photo) const throw(Error);
-//      void saveTags(const PhotoPtr &photo) throw(Error);
-};
+        void
+        on_async_ready(const SlotAsyncReady & slot) const throw();
 
-inline const Glib::ustring &
-Database::get_path() const
-{
-    return path_;
-}
+        void
+        on_async_tags(std::vector<UStringList> & result,
+                      const SlotAsyncTags & slot) const throw();
+};
 
 } // namespace Solang
 
diff --git a/src/database/db-table-visitor.h b/src/common/db-object.cpp
similarity index 62%
rename from src/database/db-table-visitor.h
rename to src/common/db-object.cpp
index 503e8a6..0a7746b 100644
--- a/src/database/db-table-visitor.h
+++ b/src/common/db-object.cpp
@@ -1,5 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
  * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
  *
  * Solang is free software: you can redistribute it and/or modify it
@@ -16,33 +17,29 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef SOLANG_DB_TABLE_VISITOR_H
-#define SOLANG_DB_TABLE_VISITOR_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
 
-#include "non-copyable.h"
-#include "photo.h"
-#include "progress-observer.h"
-#include "tag.h"
+#include "database.h"
+#include "db-object.h"
 
 namespace Solang
 {
 
-class DBTableVisitor :
-    public NonCopyable
+DBObject::DBObject() throw()
+    :isDeleted_()
 {
-    public:
-        DBTableVisitor();
+}
 
-        virtual
-        ~DBTableVisitor() throw();
-
-        virtual void
-        receive_data(PhotoList &) = 0;
-
-        virtual void
-        receive_data(TagList &) = 0;
-};
+DBObject::~DBObject() throw()
+{
+}
 
-} // namespace Solang
+void
+DBObject::set_is_deleted( bool value ) throw()
+{
+    isDeleted_ = value;
+}
 
-#endif // SOLANG_DB_TABLE_VISITOR_H
+} //namespace Solang
diff --git a/src/common/db-object.h b/src/common/db-object.h
new file mode 100644
index 0000000..be925c1
--- /dev/null
+++ b/src/common/db-object.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
+ * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
+ *
+ * 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_DB_OBJECT_H
+#define SOLANG_DB_OBJECT_H
+
+#include "delete-action.h"
+#include "error.h"
+#include "non-copyable.h"
+#include "types.h"
+
+namespace Solang
+{
+
+class Database;
+
+//Represents an object that is serialized to a database
+
+class DBObject :
+    public NonCopyable
+{
+    public:
+        typedef sigc::slot<void> SlotAsyncReady;
+
+        virtual
+        ~DBObject() throw();
+
+        virtual void
+        delete_async(Database & database, const SlotAsyncReady & slot)
+                     const throw() = 0;
+
+        virtual Glib::ustring
+        get_delete_query() const throw() = 0;
+
+        virtual Glib::ustring
+        get_save_query() const throw() = 0;
+
+        virtual void
+        save_async(Database & database, const SlotAsyncReady & slot)
+                   const throw() = 0;
+
+        inline bool
+        get_is_deleted() const throw();
+
+        void
+        set_is_deleted( bool value ) throw();
+
+    protected:
+        DBObject() throw();
+
+    private:
+        bool isDeleted_;
+};
+
+inline bool
+DBObject::get_is_deleted() const throw()
+{
+    return isDeleted_;
+}
+
+} // namespace Solang
+
+#endif // SOLANG_DB_OBJECT_H
diff --git a/src/database/delete-action.cpp b/src/common/delete-action.cpp
similarity index 94%
rename from src/database/delete-action.cpp
rename to src/common/delete-action.cpp
index 0a019f3..2eda816 100644
--- a/src/database/delete-action.cpp
+++ b/src/common/delete-action.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "database.h"
+#include "db-object.h"
 #include "delete-action.h"
 
 namespace Solang
@@ -71,11 +72,11 @@ DeleteAction::execute( Database &db ) throw()
     for( std::vector<Glib::ustring>::iterator sql = commands_.begin();
                                 sql != commands_.end(); sql++ )
     {
-        db.run_sql( *sql );
+//        db.run_sql( *sql );
     }
 
-    if( object_ )
-        object_->remove_physical_existence();
+//    if( object_ )
+//        object_->remove_physical_existence();
 
     return;
 }
diff --git a/src/database/delete-action.h b/src/common/delete-action.h
similarity index 100%
rename from src/database/delete-action.h
rename to src/common/delete-action.h
diff --git a/src/attribute/exif-data-key.cpp b/src/common/exif-data-key.cpp
similarity index 88%
rename from src/attribute/exif-data-key.cpp
rename to src/common/exif-data-key.cpp
index 7eace13..f35c674 100644
--- a/src/attribute/exif-data-key.cpp
+++ b/src/common/exif-data-key.cpp
@@ -11,9 +11,7 @@ namespace Solang
 Glib::ustring
 ExifDataKey::get_query_criteria() const throw()
 {
-    std::ostringstream sout;
-    sout<<key_<<" = '"<<value_<<"' ";
-    return sout.str();
+    return Glib::ustring::compose("%1 '%2' .", key_, value_);
 }
 
 PhotoSearchCriteria::ClubbingOperationType
diff --git a/src/attribute/exif-data-key.h b/src/common/exif-data-key.h
similarity index 98%
rename from src/attribute/exif-data-key.h
rename to src/common/exif-data-key.h
index d28a7c9..0517868 100644
--- a/src/attribute/exif-data-key.h
+++ b/src/common/exif-data-key.h
@@ -46,7 +46,7 @@ class ExifDataKey :
         {
         }
 
-        Glib::ustring
+        virtual Glib::ustring
         get_query_criteria() const throw();
 
         virtual ClubbingOperationType
diff --git a/src/common/exif-data.cpp b/src/common/exif-data.cpp
new file mode 100644
index 0000000..c63d093
--- /dev/null
+++ b/src/common/exif-data.cpp
@@ -0,0 +1,226 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
+ * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
+ * 
+ * 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include <sstream>
+
+#include <glibmm/i18n.h>
+
+#include "exif-data.h"
+
+namespace Solang
+{
+
+const Glib::ustring ExifData::meteringModeAverage_
+    = "http://www.tracker-project.org/temp/nmm#metering-mode-average";;
+
+const Glib::ustring ExifData::meteringModeCenterWeightedAverage_
+    = "http://www.tracker-project.org/temp/";
+          "nmm#metering-mode-center-weighted-average";
+
+const Glib::ustring ExifData::meteringModeSpot_
+    = "http://www.tracker-project.org/temp/nmm#metering-mode-spot";;
+
+const Glib::ustring ExifData::meteringModeMultiSpot_
+    = "http://www.tracker-project.org/temp/";
+          "nmm#metering-mode-multispot";
+
+const Glib::ustring ExifData::meteringModePattern_
+    = "http://www.tracker-project.org/temp/nmm#metering-mode-pattern";;
+
+const Glib::ustring ExifData::meteringModePartial_
+    = "http://www.tracker-project.org/temp/nmm#metering-mode-partial";;
+
+const Glib::ustring ExifData::whiteBalanceAuto_
+    = "http://www.tracker-project.org/temp/nmm#white-balance-auto";;
+
+const Glib::ustring ExifData::whiteBalanceManual_
+    = "http://www.tracker-project.org/temp/nmm#white-balance-manual";;
+
+ExifData::ExifData() :
+    camera_(),
+    exposureTime_(),
+    fnumber_(),
+    isoSpeed_(),
+    meteringMode_(),
+    meteringModeEnum_(),
+    focalLength_(),
+    whiteBalance_(),
+    whiteBalanceEnum_(),
+    pictureTakenTime_()
+{
+}
+
+ExifData::ExifData(const ExifData &rhs) :
+    camera_(rhs.camera_),
+    exposureTime_(rhs.exposureTime_),
+    fnumber_(rhs.fnumber_),
+    isoSpeed_(rhs.isoSpeed_),
+    meteringMode_(rhs.meteringMode_),
+    meteringModeEnum_(rhs.meteringModeEnum_),
+    focalLength_(rhs.focalLength_),
+    whiteBalance_(rhs.whiteBalance_),
+    whiteBalanceEnum_(rhs.whiteBalanceEnum_),
+    pictureTakenTime_( rhs.pictureTakenTime_ )
+{
+}
+
+ExifData::~ExifData() throw()
+{
+}
+
+const Glib::ustring &
+ExifData::get_camera() const throw()
+{
+    return camera_;
+}    
+
+const Glib::ustring &
+ExifData::get_exposure_time() const throw()
+{
+    return exposureTime_;
+}
+
+const Glib::ustring &
+ExifData::get_fnumber() const throw()
+{
+    return fnumber_;
+}    
+
+const Glib::ustring &
+ExifData::get_metering_mode_enum() const throw()
+{
+    return meteringModeEnum_;
+}
+
+const Glib::ustring &
+ExifData::get_white_balance_enum() const throw()
+{
+    return whiteBalanceEnum_;
+}
+
+void
+ExifData::set_camera(const Glib::ustring & camera) throw()
+{
+    camera_ = camera;
+}
+
+void
+ExifData::set_exposure_time(const Glib::ustring & exposure_time)
+                            throw()
+{
+    exposureTime_ = exposure_time;
+}
+
+void
+ExifData::set_fnumber(const Glib::ustring & fnumber) throw()
+{
+    fnumber_ = fnumber;
+}
+
+void
+ExifData::set_focal_length(const Glib::ustring & focal_length) throw()
+{
+    focalLength_ = focal_length;
+}
+
+void
+ExifData::set_iso_speed(const Glib::ustring & iso_speed) throw()
+{
+    isoSpeed_ = iso_speed;
+}
+
+void
+ExifData::set_metering_mode(const Glib::ustring & metering_mode)
+                            throw()
+{
+    if (meteringModeAverage_ == metering_mode)
+    {
+        meteringMode_ = _("Average");
+    }
+    else if (meteringModeCenterWeightedAverage_ == metering_mode)
+    {
+        meteringMode_ = _("Center Weighted Average");
+    }
+    else if (meteringModeSpot_ == metering_mode)
+    {
+        meteringMode_ = _("Spot");
+    }
+    else if (meteringModeMultiSpot_ == metering_mode)
+    {
+        meteringMode_ = _("Multi-spot");
+    }
+    else if (meteringModePattern_ == metering_mode)
+    {
+        meteringMode_ = _("Pattern");
+    }
+    else if (meteringModePartial_ == metering_mode)
+    {
+        meteringMode_ = _("Partial");
+    }
+    else
+    {
+        meteringMode_ = "";
+    }
+
+    meteringModeEnum_ = metering_mode;
+}
+
+void
+ExifData::set_white_balance(const Glib::ustring & white_balance)
+                            throw()
+{
+    if (whiteBalanceAuto_ == white_balance)
+    {
+        whiteBalance_ = _("Automatic");
+    }
+    else if (whiteBalanceManual_ == white_balance)
+    {
+        whiteBalance_ = _("Manual");
+    }
+    else
+    {
+        whiteBalance_ = "";
+    }
+
+    whiteBalanceEnum_ = white_balance;
+}
+
+ExifData &ExifData::operator =(const ExifData &rhs)
+{
+    if( this != &rhs )
+    {
+        camera_ = rhs.camera_;
+        exposureTime_ = rhs.exposureTime_;
+        fnumber_ = rhs.fnumber_;
+        isoSpeed_ = rhs.isoSpeed_;
+        meteringMode_ = rhs.meteringMode_;
+        meteringModeEnum_ = rhs.meteringModeEnum_;
+        focalLength_ = rhs.focalLength_;
+        whiteBalance_ = rhs.whiteBalance_;
+        whiteBalanceEnum_ = rhs.whiteBalanceEnum_;
+        pictureTakenTime_ = rhs.pictureTakenTime_;
+    }
+    return *this;
+}
+
+} // namespace Solang
diff --git a/src/attribute/exif-data.h b/src/common/exif-data.h
similarity index 50%
rename from src/attribute/exif-data.h
rename to src/common/exif-data.h
index dc438d9..eada0a5 100644
--- a/src/attribute/exif-data.h
+++ b/src/common/exif-data.h
@@ -1,5 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
  * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
  *
  * Solang is free software: you can redistribute it and/or modify it
@@ -23,7 +24,6 @@
 #include <vector>
 
 #include <glibmm.h>
-#include <exiv2/exif.hpp>
 
 #include "types.h"
 
@@ -33,68 +33,65 @@ namespace Solang
 class ExifData
 {
     private:
+        static const Glib::ustring meteringModeAverage_;
 
-        static const gint32 PHOTOID_COL;
-        static const gint32 APERTURE_COL;
-        static const gint32 SHUTTER_SPEED_COL;
-        static const gint32 EXPOSURE_PROGRAM_COL;
-        static const gint32 ISO_COL;
-        static const gint32 EXPOSURE_METERING_MODE_COL;
-        static const gint32 FOCAL_LENGTH_COL;
-        static const gint32 WHITE_BALANCE_COL;
-        static const gint32 FILM_FOCAL_LENGTH_COL;
-        static const gint32 PICTURE_TAKEN_TIME;
-
-
-        Glib::ustring        aperture_;
-        Glib::ustring        shutterSpeed_;
-        Glib::ustring        exposureProgram_;
-        gint32               isoSpeed_;
-        Glib::ustring        exposureMeteringMode_;
+        static const Glib::ustring meteringModeCenterWeightedAverage_;
+
+        static const Glib::ustring meteringModeSpot_;
+
+        static const Glib::ustring meteringModeMultiSpot_;
+
+        static const Glib::ustring meteringModePattern_;
+
+        static const Glib::ustring meteringModePartial_;
+
+        static const Glib::ustring whiteBalanceAuto_;
+
+        static const Glib::ustring whiteBalanceManual_;
+
+        Glib::ustring        camera_;
+        Glib::ustring        exposureTime_;
+        Glib::ustring        fnumber_;
+        Glib::ustring        isoSpeed_;
+        Glib::ustring        meteringMode_;
+        Glib::ustring        meteringModeEnum_;
         Glib::ustring        focalLength_;
         Glib::ustring        whiteBalance_;
-        Glib::ustring        focalLengthInFilm_;
+        Glib::ustring        whiteBalanceEnum_;
         Glib::ustring        pictureTakenTime_;
 
 
     public:
         ExifData();
-        ExifData( const Exiv2::ExifData &data );
         ExifData( const ExifData &rhs );
         ExifData &operator = ( const ExifData &rhs );
 
         ~ExifData() throw();
 
-        inline const Glib::ustring &
-        get_aperture() const throw()
-        {
-            return aperture_;
-        }    
+        const Glib::ustring &
+        get_camera() const throw();
 
-        inline const Glib::ustring &
-        get_shutter_speed() const throw()
-        {
-            return shutterSpeed_;
-        }
+        const Glib::ustring &
+        get_fnumber() const throw();
 
-        inline const Glib::ustring &
-        get_exposure_program() const throw()
-        {
-            return exposureProgram_;
-        }
+        const Glib::ustring &
+        get_exposure_time() const throw();
 
-        inline gint16
+        inline const Glib::ustring &
         get_iso_speed() const throw()
         {
             return isoSpeed_;
         }
 
         inline const Glib::ustring &
-        get_exposure_metering_mode() const throw()
+        get_metering_mode() const throw()
         {
-            return exposureMeteringMode_;
+            return meteringMode_;
         }
 
+        const Glib::ustring &
+        get_metering_mode_enum() const throw();
+
         inline const Glib::ustring &
         get_focal_length() const throw()
         {
@@ -107,11 +104,8 @@ class ExifData
             return whiteBalance_;
         }
 
-        inline const Glib::ustring &
-        get_focal_length_film() const throw()
-        {
-            return focalLengthInFilm_;
-        }        
+        const Glib::ustring &
+        get_white_balance_enum() const throw();
 
         inline const Glib::ustring &
         get_picture_taken_time() const throw()
@@ -119,10 +113,29 @@ class ExifData
             return pictureTakenTime_;
         }    
 
-        void insert( std::vector<Gnome::Gda::Value> &values );
-        void update( DataModelPtr &model, gint32 row );
-        void create(const DataModelPtr & model, gint32 row );
+        void
+        set_camera(const Glib::ustring & camera) throw();
+
+        void
+        set_exposure_time(const Glib::ustring & exposure_time)
+                          throw();
+
+        void
+        set_fnumber(const Glib::ustring & fnumber) throw();
+
+        void
+        set_focal_length(const Glib::ustring & focal_length) throw();
+
+        void
+        set_iso_speed(const Glib::ustring & iso_speed) throw();
+
+        void
+        set_metering_mode(const Glib::ustring & metering_mode)
+                          throw();
 
+        void
+        set_white_balance(const Glib::ustring & white_balance)
+                          throw();
 };
 
 } // namespace Solang
diff --git a/src/common/i-photo-destination.h b/src/common/i-photo-destination.h
index 89172d2..409aadf 100644
--- a/src/common/i-photo-destination.h
+++ b/src/common/i-photo-destination.h
@@ -47,11 +47,9 @@ class IPhotoDestination :
 
         virtual void
         export_photo(const PhotoPtr & photo,
-                     const IStoragePtr & storage,
                      const ProgressObserverPtr & observer) throw() = 0;
         virtual void
         export_photos(const PhotoList & photos,
-                      const IStoragePtr & storage,
                       const ProgressObserverPtr & observer) throw() = 0;
 
         virtual void
diff --git a/src/common/org-freedesktop-thumbnails-thumbnailer1-dbus.xml b/src/common/org-freedesktop-thumbnails-thumbnailer1-dbus.xml
new file mode 100644
index 0000000..9076691
--- /dev/null
+++ b/src/common/org-freedesktop-thumbnails-thumbnailer1-dbus.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/org/freedesktop/thumbnails/Thumbnailer1">
+  <interface name="org.freedesktop.thumbnails.Thumbnailer1">
+    <method name="Queue">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="as" name="uris" direction="in" />
+      <arg type="as" name="mime_types" direction="in" />
+      <arg type="s" name="flavor" direction="in" />
+      <arg type="s" name="scheduler" direction="in" />
+      <arg type="u" name="handle_to_unqueue" direction="in" />
+      <arg type="u" name="handle" direction="out" />
+    </method>
+
+    <method name="Dequeue">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="u" name="handle" direction="in" />
+    </method>
+
+    <method name="GetSupported">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true" />
+      <arg type="as" name="uri_schemes" direction="out" />
+      <arg type="as" name="mime_types" direction="out" />
+    </method>
+
+    <method name="GetSchedulers">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true" />
+      <arg type="as" name="schedulers" direction="out" />
+    </method>
+
+    <method name="GetFlavors">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true" />
+      <arg type="as" name="flavors" direction="out" />
+    </method>
+
+    <signal name="Started">
+      <arg type="u" name="handle" />
+    </signal>
+
+    <signal name="Finished">
+      <arg type="u" name="handle" />
+    </signal>
+
+    <signal name="Ready">
+      <arg type="u" name="handle" />
+      <arg type="as" name="uris" />
+    </signal>
+
+    <signal name="Error">
+      <arg type="u" name="handle" />
+      <arg type="as" name="failed_uris" />
+      <arg type="i" name="error_code" />
+      <arg type="s" name="message" />
+    </signal>
+  </interface>
+</node>
diff --git a/src/common/photo.cpp b/src/common/photo.cpp
index ac4d3a7..1bbabb0 100644
--- a/src/common/photo.cpp
+++ b/src/common/photo.cpp
@@ -20,31 +20,44 @@
 #include "config.h"
 #endif // HAVE_CONFIG_H
 
-#include <iostream>
-#include <libgdamm.h>
-
 #include "database.h"
+#include "exif-data.h"
 #include "photo.h"
 #include "i-storage.h"
 
 namespace Solang
 {
 
-const gint32 Photo::PHOTOID_COL                        = 0;
-const gint32 Photo::URI_COL                            = 1;
-const gint32 Photo::CONTENT_TYPE_COL                   = 2;
+void
+Photo::parse_exif_data(const UStringList & data, ExifData & exif_data)
+                       throw()
+{
+    exif_data.set_camera(data[0]);
+    exif_data.set_exposure_time(data[1]);
+    exif_data.set_fnumber(data[2]);
+    exif_data.set_focal_length(data[3]);
+    exif_data.set_iso_speed(data[4]);
+    exif_data.set_metering_mode(data[5]);
+}
 
-Photo::Photo() throw() :
+Photo::Photo(const Glib::ustring & uri,
+             const Glib::ustring & content_type) throw() :
     DBObject(),
-    photoId_(-1),
-    uri_(),
-    diskFilePath_(),
-    thumbnail_(),
-    exifData_(),
+    uri_(uri),
+    contentType_(content_type),
+    thumbnailPath_(),
+    thumbnailState_(THUMBNAIL_STATE_NONE),
     buffer_( 0 ),
     thumbnailBuffer_( 0 ),
     hasUnsavedData_( false )
 {
+    const std::string md5_checksum = Glib::Checksum::compute_checksum(
+                                         Glib::Checksum::CHECKSUM_MD5,
+                                         uri);
+    thumbnailPath_ = Glib::get_home_dir()
+                     + G_DIR_SEPARATOR_S + ".thumbnails"
+                     + G_DIR_SEPARATOR_S + "normal"
+                     + G_DIR_SEPARATOR_S + md5_checksum + ".png";
 }
 
 Photo::~Photo() throw()
@@ -52,138 +65,71 @@ Photo::~Photo() throw()
 }
 
 void
-Photo::set_photo_id( gint64 photoId ) throw()
+Photo::delete_async(Database & database, const SlotAsyncReady & slot)
+                    const throw()
 {
-    photoId_ = photoId;
 }
 
-void
-Photo::set_uri(const Glib::ustring & uri)
+Glib::ustring
+Photo::get_delete_query() const throw()
 {
-    uri_ = uri;
+    return Glib::ustring();
 }
 
-void
-Photo::set_thumbnail( const Thumbnail &thumb ) throw()
+Glib::ustring
+Photo::get_save_query() const throw()
 {
-    thumbnail_ = thumb;
+    return Glib::ustring();
 }
 
 void
-Photo::set_exif_data( const ExifData &exifData ) throw()
+Photo::save_async(Database & database, const SlotAsyncReady & slot)
+                  const throw()
 {
-    exifData_ = exifData;
+    database.save_async(*this, slot);
 }
 
-void
-Photo::set_disk_file_path(const IStoragePtr & storage)
+const std::string &
+Photo::get_thumbnail_path() const throw()
 {
-    diskFilePath_ = storage->retrieve(*this);
+    return thumbnailPath_;
 }
 
-void
-Photo::set_disk_file_path(const Glib::ustring & disk_file_path)
-{
-    diskFilePath_ = disk_file_path;
+Glib::ustring
+Photo::get_exif_data_query() const throw()
+{
+    return Glib::ustring::compose(
+        "SELECT ?camera ?exposure ?fn ?focal ?iso ?metering "
+        "WHERE {"
+        "  ?photo nie:isStoredAs '%1' ."
+        "  OPTIONAL { ?photo nmm:camera ?camera . }"
+        "  OPTIONAL { ?photo nmm:exposureTime ?exposure . }"
+        "  OPTIONAL { ?photo nmm:fnumber ?fn . }"
+        "  OPTIONAL { ?photo nmm:focalLength ?focal . }"
+        "  OPTIONAL { ?photo nmm:isoSpeed ?iso . }"
+        "  OPTIONAL { ?photo nmm:meteringMode ?metering . }"
+        "}",
+        uri_);
 }
 
 void
-Photo::set_content_type(const Glib::ustring & contentType) throw()
+Photo::get_exif_data_async(const Database & database,
+                           const SlotAsyncExifData & slot) const
+                           throw()
 {
-    contentType_ = contentType;
+    database.get_exif_data_async(*this, slot);
 }
 
 void
-Photo::insert( DataModelPtr &model, gint32 lastIndex) throw(Error)
-{
-    std::vector<Gnome::Gda::Value> values;
-
-    values.push_back( Gnome::Gda::Value( lastIndex + 1 ) ); //photoid
-    values.push_back( Gnome::Gda::Value( get_uri() ) );
-    values.push_back( Gnome::Gda::Value( get_content_type() ) );
-
-    modDate_.insert( values );
-    thumbnail_.insert( values );
-    exifData_.insert( values );
-
-    gint32 row=0;
-    try
-    {
-        row = model->append_values( values );
-    }
-    catch (Glib::Error & e)
-    {
-        std::cerr << "Error: " << e.what() << std::endl;
-        //TBD::Error
-    }
-
-    if( -1 == row )
-    {
-        //TBD::Error
-    }
-
-    set_row( row );
-
-    set_photo_id( lastIndex + 1 );
-
-    return;
-}
-
-void Photo::update( DataModelPtr &model, gint32 row) throw(Error)
-try
-{
-    try
-    {
-        std::vector<Gnome::Gda::Value> values;
-        values.push_back( Gnome::Gda::Value(
-                                            (gint32)get_photo_id() ) );
-        values.push_back( Gnome::Gda::Value( get_uri() ) );
-        values.push_back( Gnome::Gda::Value( get_content_type() ) );
-
-        modDate_.insert( values );
-        thumbnail_.insert( values );
-        exifData_.insert( values );
-
-        model->set_values( row, values );
-    }
-    catch(Glib::Error &e)
-    {
-        std::cerr<<"Error::Could not save: "<<e.what()<<std::endl;
-    }
-
-    return;
-
-}
-catch(Glib::Error &e)
+Photo::set_uri(const Glib::ustring & uri)
 {
-    std::cerr<<"Error:"<<e.what()<<std::endl;
-    throw;
+    uri_ = uri;
 }
 
 void
-Photo::create(const DataModelPtr & dataModel, int32_t row) throw(Error)
+Photo::set_content_type(const Glib::ustring & contentType) throw()
 {
-    set_row( row );
-
-    set_photo_id( dataModel->get_value_at(
-                                    PHOTOID_COL, row ).get_int());
-    set_uri( dataModel->get_value_at( URI_COL, row ).get_string());
-    set_content_type( dataModel->get_value_at(
-                          CONTENT_TYPE_COL, row ).get_string() );
-
-    ModificationDate date;
-    date.create( dataModel, row );
-    set_modification_date( date );
-
-    Thumbnail thumb;
-    thumb.create( dataModel, row );
-    set_thumbnail( thumb );
-
-    ExifData data;
-    data.create( dataModel, row );
-    set_exif_data( data );
-
-    return;
+    contentType_ = contentType;
 }
 
 DeleteActionPtr
@@ -191,32 +137,13 @@ Photo::get_delete_action() throw()
 {
     DeleteActionPtr action(
                         new DeleteAction( "Photo", this ));
-    if( get_is_deleted() )
-        return action;
-
-    {
-        std::ostringstream sout;
-        sout<<"delete from photos where photoid="<<get_photo_id();
-        action->add_command( sout.str() );
-    }
-    {
-        std::ostringstream sout;
-        sout<<"delete from photo_tags where photoid="<<get_photo_id();
-        action->add_command( sout.str() );
-    }
     return action;
 }
 
-Glib::ustring
-Photo::get_db_object_type_name() const throw()
-{
-    return "photos";
-}
-
-void
-Photo::set_modification_date( const ModificationDate &modDate )
+Photo::ThumbnailState
+Photo::get_thumbnail_state() const throw()
 {
-    modDate_ = modDate;
+    return thumbnailState_;
 }
 
 void
@@ -232,6 +159,13 @@ Photo::set_thumbnail_buffer( const PixbufPtr &buffer ) throw()
 }
 
 void
+Photo::set_thumbnail_state(Photo::ThumbnailState thumbnail_state)
+                           throw()
+{
+    thumbnailState_ = thumbnail_state;
+}
+
+void
 Photo::set_has_unsaved_data( bool value ) throw()
 {
     hasUnsavedData_ = value;
diff --git a/src/common/photo.h b/src/common/photo.h
index 065188d..0d6fec6 100644
--- a/src/common/photo.h
+++ b/src/common/photo.h
@@ -1,5 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
+ * Copyright (C) 2009 Debarshi Ray <rishi gnu org>
  * Copyright (C) 2009 Santanu Sinha <santanu sinha gmail com>
  *
  * Solang is free software: you can redistribute it and/or modify it
@@ -19,36 +20,67 @@
 #ifndef SOLANG_PHOTO_H
 #define SOLANG_PHOTO_H
 
+#include <string>
 #include <tr1/memory>
 
 #include <gdkmm.h>
 #include <glibmm.h>
 
 #include "db-object.h"
-#include "exif-data.h"
-#include "modification-date.h"
-#include "thumbnail.h"
 #include "types.h"
 
 namespace Solang
 {
 
+class ExifData;
 class Storage;
 
 class Photo :
     public DBObject
 {
     public:
-        Photo() throw();
+        enum ThumbnailState
+        {
+            THUMBNAIL_STATE_MASK    = 0x03,
+            THUMBNAIL_STATE_UNKNOWN = 0x00,
+            THUMBNAIL_STATE_NONE    = 0x01,
+            THUMBNAIL_STATE_READY   = 0x02,
+            THUMBNAIL_STATE_LOADING = 0x03,
+        };
+
+        typedef sigc::slot<void, ExifData &> SlotAsyncExifData;
+
+        static void
+        parse_exif_data(const UStringList & data,
+                        ExifData & exif_data) throw();
+
+        Photo(const Glib::ustring & uri,
+              const Glib::ustring & content_type) throw();
 
         virtual
         ~Photo() throw();
 
-        inline gint64
-        get_photo_id() const throw();
+        virtual void
+        delete_async(Database & database, const SlotAsyncReady & slot)
+                     const throw();
+
+        virtual Glib::ustring
+        get_delete_query() const throw();
+
+        virtual Glib::ustring
+        get_save_query() const throw();
+
+        virtual void
+        save_async(Database & database, const SlotAsyncReady & slot)
+                   const throw();
 
         void
-        set_photo_id( gint64 photoId ) throw();
+        get_exif_data_async(const Database & database,
+                            const SlotAsyncExifData & slot) const
+                            throw();
+
+        Glib::ustring
+        get_exif_data_query() const throw();
 
         inline const Glib::ustring &
         get_uri() const throw();
@@ -62,17 +94,8 @@ class Photo :
         void
         set_content_type( const Glib::ustring &contentType ) throw();
 
-        inline const Glib::ustring 
-        & get_disk_file_path() const throw();
-
-        inline const ModificationDate &
-        get_modification_date() const throw();
-
-        void
-        set_modification_date( const ModificationDate &modDate );
-
-        inline const Thumbnail &
-        get_thumbnail() const throw();
+        const std::string &
+        get_thumbnail_path() const throw();
 
         inline const PixbufPtr &
         get_buffer() const throw();
@@ -86,75 +109,36 @@ class Photo :
         void
         set_thumbnail_buffer( const PixbufPtr &buffer ) throw();
 
-        inline bool
-        get_has_unsaved_data() const throw();
+        ThumbnailState
+        get_thumbnail_state() const throw();
 
         void
-        set_has_unsaved_data( bool value ) throw();
-
-        void
-        set_thumbnail( const Thumbnail &thumb ) throw();
-
-        inline const ExifData &
-        get_exif_data() const throw();
+        set_thumbnail_state(ThumbnailState thumbnail_state) throw();
 
-        void 
-        set_exif_data( const ExifData &exif ) throw();
-
-        void
-        set_disk_file_path(const IStoragePtr & storage);
+        inline bool
+        get_has_unsaved_data() const throw();
 
         void
-        set_disk_file_path(const Glib::ustring & disk_file_path);
-
-        //Overrides from DBObject
-        virtual void
-        insert(DataModelPtr &model, gint32 lastIndex) throw(Error);
-
-        virtual void
-        update(DataModelPtr &model, gint32 row) throw(Error);
-
-        virtual void
-        create(const DataModelPtr & dataModel, gint32 row) throw(Error);
-        
-        virtual Glib::ustring
-        get_db_object_type_name() const throw();
+        set_has_unsaved_data( bool value ) throw();
 
         virtual DeleteActionPtr
         get_delete_action() throw();
 
     private:
-        void
-        make_thumb_path() throw(Error);
+        Glib::ustring uri_;
 
-    private:
-        static const gint32 PHOTOID_COL;
-        static const gint32 URI_COL;
-        static const gint32 CONTENT_TYPE_COL;
-
-        gint64 photoId_;
-        Glib::ustring uri_; //storage uri
         Glib::ustring contentType_; //content type
-        Glib::ustring diskFilePath_;
 
-        //Date
-        ModificationDate modDate_;
+        std::string thumbnailPath_;
+
+        ThumbnailState thumbnailState_;
 
         //Thumbnail
-        Thumbnail thumbnail_;
-        //Exif
-        ExifData exifData_;
         PixbufPtr buffer_;
         PixbufPtr thumbnailBuffer_;
         bool hasUnsavedData_;
 };
 
-inline gint64
-Photo::get_photo_id() const throw()
-{
-    return photoId_;
-}
-
 inline const Glib::ustring &
 Photo::get_uri() const throw()
 {
@@ -167,30 +151,6 @@ Photo::get_content_type() const throw()
     return contentType_;
 }
 
-inline const Thumbnail &
-Photo::get_thumbnail() const throw()
-{
-    return thumbnail_;
-}
-
-inline const ExifData &
-Photo::get_exif_data() const throw()
-{
-    return exifData_;
-}
-
-inline const Glib::ustring &
-Photo::get_disk_file_path() const throw()
-{
-    return diskFilePath_;
-}
-
-inline const ModificationDate &
-Photo::get_modification_date() const throw()
-{
-    return modDate_;
-}
-
 inline const PixbufPtr &
 Photo::get_buffer() const throw()
 {
diff --git a/src/common/pixbuf-maker.cpp b/src/common/pixbuf-maker.cpp
index 2703843..8de77b7 100644
--- a/src/common/pixbuf-maker.cpp
+++ b/src/common/pixbuf-maker.cpp
@@ -96,8 +96,8 @@ PixbufMaker::make_async(const SlotAsyncReady & slot,
                         throw(Gdk::PixbufError, Glib::ConvertError,
                               Glib::FileError)
 {
-    const std::string path = Glib::filename_from_utf8(
-                                 photo->get_disk_file_path());
+    const std::string path = Glib::filename_from_uri(
+                                 photo->get_uri());
     fd_ = create_fd(path);
     pixbufLoader_ = create_pixbuf_loader(path);
 
@@ -116,8 +116,8 @@ PixbufMaker::make_sync(const PhotoPtr & photo)
                        throw(Gdk::PixbufError, Glib::ConvertError,
                              Glib::FileError)
 {
-    const std::string path = Glib::filename_from_utf8(
-                                 photo->get_disk_file_path());
+    const std::string path = Glib::filename_from_uri(
+                                 photo->get_uri());
     fd_ = create_fd(path);
     pixbufLoader_ = create_pixbuf_loader(path);
     gssize nread;
diff --git a/src/common/solang-marshal.list b/src/common/solang-marshal.list
new file mode 100644
index 0000000..84fbc9c
--- /dev/null
+++ b/src/common/solang-marshal.list
@@ -0,0 +1 @@
+VOID:UINT,POINTER,UINT,STRING
diff --git a/src/common/thumbbuf-maker.cpp b/src/common/thumbbuf-maker.cpp
index 6e9ed7b..1f68caa 100644
--- a/src/common/thumbbuf-maker.cpp
+++ b/src/common/thumbbuf-maker.cpp
@@ -24,10 +24,8 @@
 
 #include <giomm.h>
 
-#include "content-type-repo.h"
 #include "photo.h"
 #include "thumbbuf-maker.h"
-#include "thumbnail.h"
 
 namespace Solang
 {
@@ -53,23 +51,6 @@ ThumbbufMaker::~ThumbbufMaker() throw()
 {
 }
 
-PixbufLoaderPtr
-ThumbbufMaker::create_pixbuf_loader(const std::string & path) const
-                                    throw(Gdk::PixbufError)
-{
-    const ContentTypeRepoPtr content_type_repo
-                                 = ContentTypeRepo::instance();
-    const Glib::ustring content_type
-        = content_type_repo->get_content_type(path);
-
-    if (false == content_type_repo->is_gdk_supported(content_type))
-    {
-        throw Gdk::PixbufError(Gdk::PixbufError::UNKNOWN_TYPE, "");
-    }
-
-    return Gdk::PixbufLoader::create(content_type, true);
-}
-
 ThumbbufMaker &
 ThumbbufMaker::operator=(const ThumbbufMaker & source) throw()
 {
@@ -86,98 +67,11 @@ ThumbbufMaker::operator=(const ThumbbufMaker & source) throw()
 }
 
 PixbufPtr
-ThumbbufMaker::operator()(const PhotoPtr & photo) throw()
+ThumbbufMaker::operator()(const PhotoPtr & photo) throw(Gdk::PixbufError,
+                                                        Glib::FileError)
 {
-    const Thumbnail & thumbnail = photo->get_thumbnail();
-
-    std::string path;
-    try
-    {
-        path = Glib::filename_from_utf8(thumbnail.get_path());
-    }
-    catch (const Glib::ConvertError & e)
-    {
-        g_warning("%s", e.what().c_str());
-        return PixbufPtr(0);
-    }
-
-    if (false == Glib::file_test(path, Glib::FILE_TEST_EXISTS))
-    {
-        try
-        {
-            path = Glib::filename_from_utf8(
-                             photo->get_disk_file_path());
-        }
-        catch (const Glib::ConvertError & e)
-        {
-            g_warning("%s", e.what().c_str());
-            return PixbufPtr(0);
-        }
-    }
-
-    PixbufLoaderPtr pixbuf_loader;
-    try
-    {
-        pixbuf_loader = create_pixbuf_loader(path);
-    }
-    catch(const Gdk::PixbufError & e)
-    {
-        g_warning("%s", e.what().c_str());
-        return PixbufPtr(0);
-    }
-
-    const FilePtr file = Gio::File::create_for_path(path);
-    DataInputStreamPtr fin;
-
-    try
-    {
-        fin = Gio::DataInputStream::create(file->read());
-    }
-    catch(const Gio::Error & e)
-    {
-        g_warning("%s", e.what().c_str());
-        return PixbufPtr(0);
-    }
-
-    gssize nread;
-    guint8 buffer[BUFSIZ];
-
-    while (0 < (nread = fin->read(buffer, sizeof(buffer))))
-    {
-        try
-        {
-            pixbuf_loader->write(buffer, nread);
-        }
-        catch (const Glib::FileError & e)
-        {
-            g_warning("%s", e.what().c_str());
-            break;
-        }
-        catch (const Gdk::PixbufError & e)
-        {
-            g_warning("%s", e.what().c_str());
-            break;
-        }
-    }
-
-    try
-    {
-        pixbuf_loader->close();
-    }
-    catch (const Glib::FileError & e)
-    {
-        g_warning("%s", e.what().c_str());
-    }
-    catch (const Gdk::PixbufError & e)
-    {
-        g_warning("%s", e.what().c_str());
-    }
-
-    PixbufPtr pixbuf = pixbuf_loader->get_pixbuf();
-    if (0 == pixbuf)
-    {
-        return PixbufPtr(0);
-    }
+    const std::string path = photo->get_thumbnail_path();
+    PixbufPtr pixbuf = Gdk::Pixbuf::create_from_file(path, width_, -1, true);
 
     if (true == rotate_)
     {
@@ -186,23 +80,15 @@ ThumbbufMaker::operator()(const PhotoPtr & photo) throw()
     }
 
     const gint height = pixbuf->get_height();
-    const gint width = pixbuf->get_width();
-    const gdouble aspect_ratio = static_cast<gdouble>(width)
-                                 / static_cast<gdouble>(height);
 
-    if (height > width)
+    if (height_ < height)
     {
+        const gdouble width = static_cast<gdouble>(pixbuf->get_width());
+        const gdouble aspect_ratio = width / static_cast<gdouble>(height);
         pixbuf = pixbuf->scale_simple(
                      static_cast<gint>(height_ * aspect_ratio),
                      height_, Gdk::INTERP_BILINEAR);
     }
-    else
-    {
-        pixbuf = pixbuf->scale_simple(
-                     width_,
-                     static_cast<gint>(width_ / aspect_ratio),
-                     Gdk::INTERP_BILINEAR);
-    }
 
     return pixbuf;
 }
diff --git a/src/common/thumbbuf-maker.h b/src/common/thumbbuf-maker.h
index c8df27f..a7d15da 100644
--- a/src/common/thumbbuf-maker.h
+++ b/src/common/thumbbuf-maker.h
@@ -22,7 +22,6 @@
 #include <functional>
 
 #include <gdkmm.h>
-#include <glibmm.h>
 
 #include "types.h"
 
@@ -43,12 +42,8 @@ class ThumbbufMaker :
         operator=(const ThumbbufMaker & source) throw();
 
         PixbufPtr
-        operator()(const PhotoPtr & photo) throw();
-
-    protected:
-        PixbufLoaderPtr
-        create_pixbuf_loader(const std::string & path) const
-                             throw(Gdk::PixbufError);
+        operator()(const PhotoPtr & photo) throw(Gdk::PixbufError,
+                                                 Glib::FileError);
 
     private:
         bool rotate_;
diff --git a/src/common/thumbnailer-proxy.cpp b/src/common/thumbnailer-proxy.cpp
new file mode 100644
index 0000000..28c56be
--- /dev/null
+++ b/src/common/thumbnailer-proxy.cpp
@@ -0,0 +1,441 @@
+/* -*- 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include <iostream>
+
+#include "solang-marshal.h"
+#include "org-freedesktop-thumbnails-thumbnailer1-dbus-bindings.h"
+#include "thumbnailer-proxy.h"
+
+namespace Solang
+{
+
+const std::string ThumbnailerProxy::INTERFACE
+    = "org.freedesktop.thumbnails.Thumbnailer1";
+
+const std::string ThumbnailerProxy::NAME
+    = "org.freedesktop.thumbnails.Thumbnailer1";
+
+const std::string ThumbnailerProxy::PATH
+    = "/org/freedesktop/thumbnails/Thumbnailer1";
+
+static UStringList
+list_from_strv(const char ** strv) throw()
+{
+    UStringList ustrings;
+
+    for (const char ** iter = strv; 0 != iter && 0 != *iter; iter++)
+    {
+        ustrings.push_back(Glib::ustring(*iter));
+    }
+
+    return ustrings;
+}
+
+static ConstCharPtrPtr
+strv_from_list(const UStringList & ustrings) throw()
+{
+    ConstCharPtrPtr strv(new const char * [ustrings.size() + 1]);
+
+    guint i = 0;
+    for (UStringList::const_iterator iter = ustrings.begin();
+         ustrings.end() != iter;
+         iter++, i++)
+    {
+        (&*strv)[i] = iter->c_str();
+    }
+    (&*strv)[i] = 0;
+
+    return strv;
+}
+
+static void
+signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_error_cb(
+    DBusGProxy * proxy,
+    guint handle,
+    const char ** uris,
+    gint code,
+    const gchar * message,
+    gpointer user_data)
+{
+    if (0 == user_data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of ThumbnailerProxy::SlotSignalReady"
+                  << std::endl;
+        return;
+    }
+
+    ThumbnailerProxy::SlotSignalError * const slot
+        = static_cast<ThumbnailerProxy::SlotSignalError *>(user_data);
+    UStringList ustrings = list_from_strv(uris);
+    Glib::ustring ustring = (0 == message) ? Glib::ustring(message)
+                                           : "";
+    (*slot)(handle, ustrings, code, ustring);
+}
+
+static void
+signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_finished_cb(
+    DBusGProxy * proxy,
+    guint handle,
+    gpointer user_data)
+{
+}
+
+static void
+signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_ready_cb(
+    DBusGProxy * proxy,
+    guint handle,
+    const char ** uris,
+    gpointer user_data)
+{
+    if (0 == user_data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of ThumbnailerProxy::SlotSignalReady"
+                  << std::endl;
+        return;
+    }
+
+    ThumbnailerProxy::SlotSignalReady * const slot
+        = static_cast<ThumbnailerProxy::SlotSignalReady *>(user_data);
+    UStringList ustrings = list_from_strv(uris);
+
+    (*slot)(handle, ustrings);
+}
+
+static void
+signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_started_cb(
+    DBusGProxy * proxy,
+    guint handle,
+    gpointer user_data)
+{
+    if (0 == user_data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of ThumbnailerProxy::SlotSignalStarted"
+                  << std::endl;
+        return;
+    }
+
+    ThumbnailerProxy::SlotSignalStarted * const slot
+        = static_cast<ThumbnailerProxy::SlotSignalStarted *>(user_data);
+
+    (*slot)(handle);
+}
+
+static void
+signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_queue_reply(
+    DBusGProxy * proxy,
+    guint handle,
+    GError * error,
+    gpointer user_data)
+{
+    if (0 != error)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << error->message << std::endl;
+        g_error_free(error);
+        return;
+    }
+
+    if (0 == user_data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of ThumbnailerProxy::SlotAsyncReply"
+                  << std::endl;
+        return;
+    }
+
+    ThumbnailerProxy::SlotAsyncQueue * const slot
+        = static_cast<ThumbnailerProxy::SlotAsyncQueue *>(user_data);
+
+    if (0 != slot)
+    {
+        (*slot)(handle);
+    }
+
+    delete slot;
+}
+
+static void
+signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_dequeue_reply(
+    DBusGProxy * proxy,
+    GError * error,
+    gpointer user_data)
+{
+    if (0 != error)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << error->message << std::endl;
+        g_error_free(error);
+        return;
+    }
+
+    if (0 == user_data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of ThumbnailerProxy::SlotAsyncReady"
+                  << std::endl;
+        return;
+    }
+
+    ThumbnailerProxy::SlotAsyncDequeue * const slot
+        = static_cast<ThumbnailerProxy::SlotAsyncDequeue *>(user_data);
+
+    if (0 != slot)
+    {
+        (*slot)();
+    }
+
+    delete slot;
+}
+
+static void
+slot_signal_error_destroy(gpointer data, GClosure * closure)
+{
+    if (0 == data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of ThumbnailerProxy::SlotSignalError"
+                  << std::endl;
+        return;
+    }
+
+    ThumbnailerProxy::SlotSignalError * const slot
+        = static_cast<ThumbnailerProxy::SlotSignalError *>(data);
+
+    delete slot;
+}
+
+static void
+slot_signal_ready_destroy(gpointer data, GClosure * closure)
+{
+    if (0 == data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of ThumbnailerProxy::SlotSignalReady"
+                  << std::endl;
+        return;
+    }
+
+    ThumbnailerProxy::SlotSignalReady * const slot
+        = static_cast<ThumbnailerProxy::SlotSignalReady *>(data);
+
+    delete slot;
+}
+
+ThumbnailerProxy::ThumbnailerProxy() throw() :
+    serviceAvailable_(false),
+    thumbnailerProxy_(0)
+{
+    GError * error = 0;
+    DBusGConnection * const connection = dbus_g_bus_get(
+                                             DBUS_BUS_SESSION,
+                                             &error);
+
+    if (0 != error)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << error->message << std::endl;
+        g_error_free(error);
+    }
+
+    serviceAvailable_ = true;
+
+    thumbnailerProxy_ = dbus_g_proxy_new_for_name(connection,
+                                                  NAME.c_str(),
+                                                  PATH.c_str(),
+                                                  INTERFACE.c_str());
+    dbus_g_connection_unref(connection);
+
+    dbus_g_object_register_marshaller(
+        solang_marshal_VOID__UINT_POINTER_UINT_STRING,
+        G_TYPE_NONE,
+        G_TYPE_UINT, 
+        G_TYPE_STRV, 
+        G_TYPE_UINT, 
+        G_TYPE_STRING,
+        G_TYPE_INVALID);
+
+    dbus_g_object_register_marshaller(
+        static_cast<GClosureMarshal>(
+            g_cclosure_marshal_VOID__UINT_POINTER),
+        G_TYPE_NONE,
+        G_TYPE_UINT,
+        G_TYPE_STRV,
+        G_TYPE_INVALID);
+
+    dbus_g_proxy_add_signal(thumbnailerProxy_,
+                            "Error",
+                            G_TYPE_UINT,
+                            G_TYPE_STRV,
+                            G_TYPE_UINT,
+                            G_TYPE_STRING,
+                            G_TYPE_INVALID);
+
+    dbus_g_proxy_add_signal(thumbnailerProxy_,
+                            "Finished",
+                            G_TYPE_UINT,
+                            G_TYPE_INVALID);
+
+    dbus_g_proxy_add_signal(thumbnailerProxy_,
+                            "Ready",
+                            G_TYPE_UINT,
+                            G_TYPE_STRV,
+                            G_TYPE_INVALID);
+
+    dbus_g_proxy_add_signal(thumbnailerProxy_,
+                            "Started",
+                            G_TYPE_UINT,
+                            G_TYPE_INVALID);
+}
+
+ThumbnailerProxy::~ThumbnailerProxy() throw()
+{
+    g_object_unref(thumbnailerProxy_);
+}
+
+guint
+ThumbnailerProxy::queue(const UStringList & uris,
+                        const UStringList & mime_types,
+                        const std::string & flavour,
+                        const std::string & scheduler,
+                        guint handle_to_dequeue) throw(Glib::Error)
+{
+    ConstCharPtrPtr uri_v = strv_from_list(uris);
+    ConstCharPtrPtr mime_type_v = strv_from_list(uris);
+    GError * error = 0;
+    guint handle;
+
+    org_freedesktop_thumbnails_Thumbnailer1_queue(
+        thumbnailerProxy_,
+        &*uri_v,
+        &*mime_type_v,
+        flavour.c_str(),
+        scheduler.c_str(),
+        handle_to_dequeue,
+        &handle,
+        &error);
+    if (0 != error)
+    {
+        Glib::Error::throw_exception(error);
+    }
+
+    return handle;
+}
+
+void
+ThumbnailerProxy::queue_async(const UStringList & uris,
+                              const UStringList & mime_types,
+                              const std::string & flavour,
+                              const std::string & scheduler,
+                              guint handle_to_dequeue,
+                              const SlotAsyncQueue & slot) throw()
+{
+    ConstCharPtrPtr uri_v = strv_from_list(uris);
+    ConstCharPtrPtr mime_type_v = strv_from_list(mime_types);
+    SlotAsyncQueue * const slot_copy = new SlotAsyncQueue(slot);
+
+    org_freedesktop_thumbnails_Thumbnailer1_queue_async(
+        thumbnailerProxy_,
+        &*uri_v,
+        &*mime_type_v,
+        flavour.c_str(),
+        scheduler.c_str(),
+        handle_to_dequeue,
+        signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_queue_reply,
+        slot_copy);
+}
+
+void
+ThumbnailerProxy::dequeue(guint handle) throw(Glib::Error)
+{
+    GError * error = 0;
+
+    org_freedesktop_thumbnails_Thumbnailer1_dequeue(thumbnailerProxy_,
+                                                    handle,
+                                                    &error);
+    if (0 != error)
+    {
+        Glib::Error::throw_exception(error);
+    }
+}
+
+void
+ThumbnailerProxy::dequeue_async(guint handle,
+                                const SlotAsyncDequeue & slot) throw()
+{
+    SlotAsyncDequeue * const slot_copy = new SlotAsyncDequeue(slot);
+
+    org_freedesktop_thumbnails_Thumbnailer1_dequeue_async(
+        thumbnailerProxy_,
+        handle,
+        signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_dequeue_reply,
+        slot_copy);
+}
+
+void
+ThumbnailerProxy::error_connect(const SlotSignalError & slot) throw()
+{
+    SlotSignalError * const slot_copy = new SlotSignalError(slot);
+
+    dbus_g_proxy_connect_signal(
+        thumbnailerProxy_,
+        "Error",
+        G_CALLBACK(signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_error_cb),
+        slot_copy,
+        slot_signal_error_destroy);
+}
+
+void
+ThumbnailerProxy::ready_connect(const SlotSignalReady & slot) throw()
+{
+    SlotSignalReady * const slot_copy = new SlotSignalReady(slot);
+
+    dbus_g_proxy_connect_signal(
+        thumbnailerProxy_,
+        "Ready",
+        G_CALLBACK(signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_ready_cb),
+        slot_copy,
+        slot_signal_ready_destroy);
+}
+
+void
+ThumbnailerProxy::started_connect(const SlotSignalStarted & slot) throw()
+{
+    SlotSignalStarted * const slot_copy = new SlotSignalStarted(slot);
+
+    dbus_g_proxy_connect_signal(
+        thumbnailerProxy_,
+        "Started",
+        G_CALLBACK(signal_proxy_org_freedesktop_thumbnails_Thumbnailer1_started_cb),
+        slot_copy,
+        slot_signal_ready_destroy);
+}
+
+ThumbnailerProxy::operator bool() const throw()
+{
+    return serviceAvailable_;
+}
+
+} // namespace Solang
diff --git a/src/common/thumbnailer-proxy.h b/src/common/thumbnailer-proxy.h
new file mode 100644
index 0000000..c86f789
--- /dev/null
+++ b/src/common/thumbnailer-proxy.h
@@ -0,0 +1,102 @@
+/* -*- 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_THUMBNAILER_PROXY_H
+#define SOLANG_THUMBNAILER_PROXY_H
+
+#include <string>
+
+#include <dbus/dbus-glib.h>
+#include <sigc++/sigc++.h>
+
+#include "types.h"
+
+namespace Solang
+{
+
+class ThumbnailerProxy
+{
+    public:
+        typedef sigc::slot<void> SlotAsyncDequeue;
+
+        typedef sigc::slot<void, guint> SlotAsyncQueue;
+
+        typedef sigc::slot<void,
+                           guint,
+                           UStringList &,
+                           guint,
+                           Glib::ustring &>
+            SlotSignalError;
+
+        typedef sigc::slot<void, guint, UStringList &>
+            SlotSignalReady;
+
+        typedef sigc::slot<void, guint> SlotSignalStarted;
+
+        ThumbnailerProxy() throw();
+
+        ~ThumbnailerProxy() throw();
+
+        guint
+        queue(const UStringList & uris,
+              const UStringList & mime_types,
+              const std::string & flavour,
+              const std::string & scheduler,
+              guint handle_to_dequeue) throw(Glib::Error);
+
+        void
+        queue_async(const UStringList & uris,
+                    const UStringList & mime_types,
+                    const std::string & flavour,
+                    const std::string & scheduler,
+                    guint handle_to_dequeue,
+                    const SlotAsyncQueue & slot) throw();
+
+        void
+        dequeue(guint handle) throw(Glib::Error);
+
+        void
+        dequeue_async(guint handle,
+                      const SlotAsyncDequeue & slot) throw();
+
+        void
+        error_connect(const SlotSignalError & slot) throw();
+
+        void
+        ready_connect(const SlotSignalReady & slot) throw();
+
+        void
+        started_connect(const SlotSignalStarted & slot) throw();
+
+        operator bool() const throw();
+
+    private:
+        static const std::string INTERFACE;
+
+        static const std::string NAME;
+
+        static const std::string PATH;
+
+        bool serviceAvailable_;
+
+        DBusGProxy * thumbnailerProxy_;
+};
+
+} // namespace Solang
+
+#endif // SOLANG_THUMBNAILER_PROXY_H
diff --git a/src/common/thumbnailer.cpp b/src/common/thumbnailer.cpp
new file mode 100644
index 0000000..b407551
--- /dev/null
+++ b/src/common/thumbnailer.cpp
@@ -0,0 +1,158 @@
+/* -*- 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include <utility>
+
+#include <glibmm.h>
+
+#include "photo.h"
+#include "thumbnailer.h"
+
+namespace Solang
+{
+
+Thumbnailer::Thumbnailer() throw() :
+    map_(),
+    pendingList_(),
+    thumbnailerProxy_()
+{
+    thumbnailerProxy_.error_connect(
+        sigc::mem_fun(*this,
+                      &Thumbnailer::on_signal_error));
+    thumbnailerProxy_.ready_connect(
+        sigc::mem_fun(*this,
+                      &Thumbnailer::on_signal_ready));
+    thumbnailerProxy_.started_connect(
+        sigc::mem_fun(*this,
+                      &Thumbnailer::on_signal_started));
+}
+
+Thumbnailer::~Thumbnailer() throw()
+{
+    signalTimeout_.disconnect();
+}
+
+void
+Thumbnailer::on_async_queue(guint handle, const PhotoList & photos)
+                            throw()
+{
+    std::map<Glib::ustring, PhotoPtr> m;
+
+    for (PhotoList::const_iterator iter = photos.begin();
+         photos.end() != iter;
+         iter++)
+    {
+        const PhotoPtr photo = *iter;
+        m.insert(std::make_pair(photo->get_uri(), photo));
+    }
+
+    map_.insert(std::make_pair(handle, m));
+}
+
+void
+Thumbnailer::on_signal_error(guint handle,
+                             UStringList & uris,
+                             guint code,
+                             Glib::ustring & message) throw()
+{
+}
+
+void
+Thumbnailer::on_signal_ready(guint handle, UStringList & uris)
+                             throw()
+{
+    if (map_.end() == map_.find(handle))
+    {
+        return;
+    }
+
+    std::map<Glib::ustring, PhotoPtr> & m = map_[handle];
+
+    for (UStringList::const_iterator iter = uris.begin();
+         uris.end() != iter;
+         iter++)
+    {
+        const Glib::ustring & uri = *iter;
+
+        if (m.end() == m.find(uri))
+        {
+            continue;
+        }
+        m[uri]->set_thumbnail_state(Photo::THUMBNAIL_STATE_READY);
+    }
+}
+
+void
+Thumbnailer::on_signal_started(guint handle) throw()
+{
+}
+
+bool
+Thumbnailer::process() throw()
+{
+    if (true == pendingList_.empty())
+    {
+        return true;
+    }
+
+    UStringList mime_types;
+    UStringList uris;
+
+    for (PhotoList::const_iterator iter = pendingList_.begin();
+         pendingList_.end() != iter;
+         iter++)
+    {
+        mime_types.push_back((*iter)->get_content_type());
+        uris.push_back((*iter)->get_uri());
+    }
+
+    thumbnailerProxy_.queue_async(
+        uris,
+        mime_types,
+        "normal",
+        "forward",
+        0,
+        sigc::bind(sigc::mem_fun(*this,
+                                 &Thumbnailer::on_async_queue),
+                   pendingList_));
+    pendingList_.clear();
+
+    return true;
+}
+
+void
+Thumbnailer::push(const PhotoPtr & photo) throw()
+{
+    pendingList_.push_back(photo);
+
+    if (0 == signalTimeout_)
+    {
+        signalTimeout_
+            = Glib::signal_timeout().connect(
+                  sigc::mem_fun(*this,
+                                &Thumbnailer::process),
+                  100,
+                  Glib::PRIORITY_DEFAULT);
+    }
+}
+
+} // namespace Solang
diff --git a/src/common/thumbnailer.h b/src/common/thumbnailer.h
new file mode 100644
index 0000000..998ef2b
--- /dev/null
+++ b/src/common/thumbnailer.h
@@ -0,0 +1,75 @@
+/* -*- 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_THUMBNAILER_H
+#define SOLANG_THUMBNAILER_H
+
+#include <map>
+
+#include <glibmm.h>
+#include <sigc++/sigc++.h>
+
+#include "thumbnailer-proxy.h"
+#include "types.h"
+
+namespace Solang
+{
+
+class Thumbnailer
+{
+    public:
+        Thumbnailer() throw();
+
+        ~Thumbnailer() throw();
+
+        void
+        push(const PhotoPtr & photo) throw();
+
+    private:
+        void
+        on_async_queue(guint handle, const PhotoList & photos)
+                       throw();
+
+        void
+        on_signal_error(guint handle,
+                        UStringList & uris,
+                        guint code,
+                        Glib::ustring & message) throw();
+
+        void
+        on_signal_ready(guint handle, UStringList & uris)
+                        throw();
+
+        void
+        on_signal_started(guint handle) throw();
+
+        bool
+        process(void) throw();
+
+        std::map<guint, std::map<Glib::ustring, PhotoPtr> > map_;
+
+        PhotoList pendingList_;
+
+        ThumbnailerProxy thumbnailerProxy_;
+
+        sigc::connection signalTimeout_;
+};
+
+} // namespace Solang
+
+#endif // SOLANG_THUMBNAILER_H
diff --git a/src/common/tracker-client.cpp b/src/common/tracker-client.cpp
new file mode 100644
index 0000000..d272063
--- /dev/null
+++ b/src/common/tracker-client.cpp
@@ -0,0 +1,204 @@
+/* -*- 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include <iostream>
+
+#include "tracker-client.h"
+
+namespace Solang
+{
+
+static void
+tracker_client_append_result_foreach(gpointer data,
+                                     gpointer user_data)
+{
+    if (0 == user_data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of std::vector<UStringList>"
+                  << std::endl;
+        return;
+    }
+
+    const GStrv element = static_cast<GStrv>(data);
+    std::vector<UStringList> * const resultv
+        = static_cast<std::vector<UStringList> *>(user_data);
+
+    UStringList strings;
+    for (gint i = 0; 0 != element[i]; i++)
+    {
+        strings.push_back(std::string(element[i]));
+    }
+    resultv->push_back(strings);
+}
+
+static void
+signal_proxy_tracker_reply_gptrarray(GPtrArray * result,
+                                     GError * error,
+                                     gpointer user_data) throw()
+{
+    if (0 != error)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << error->message << std::endl;
+        g_error_free(error);
+        return;
+    }
+
+    if (0 == user_data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of TrackerClient::SlotAsyncReply"
+                  << std::endl;
+        return;
+    }
+
+    TrackerClient::SlotAsyncReply * const slot
+        = static_cast<TrackerClient::SlotAsyncReply *>(user_data);
+
+    std::vector<UStringList> resultv;
+
+    g_ptr_array_foreach (result,
+                         tracker_client_append_result_foreach,
+                         &resultv);
+
+    g_ptr_array_foreach (result, (GFunc) g_strfreev, NULL);
+    g_ptr_array_free (result, TRUE);
+
+    if (0 != slot)
+    {
+        (*slot)(resultv);
+    }
+
+    delete slot;
+}
+
+static void
+signal_proxy_tracker_reply_void(GError * error, gpointer user_data)
+                                throw()
+{
+    if (0 != error)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << error->message << std::endl;
+        g_error_free(error);
+        return;
+    }
+
+    if (0 == user_data)
+    {
+        std::cerr << G_STRLOC << ", " << G_STRFUNC << ": "
+                  << "Not an instance of TrackerClient::SlotAsyncReady"
+                  << std::endl;
+        return;
+    }
+
+    TrackerClient::SlotAsyncReady * const slot
+        = static_cast<TrackerClient::SlotAsyncReady *>(user_data);
+
+    if (0 != slot)
+    {
+        (*slot)();
+    }
+
+    delete slot;
+}
+
+TrackerClient::TrackerClient() :
+    trackerClient_(tracker_connect(TRUE, -1))
+{
+}
+
+TrackerClient::~TrackerClient()
+{
+    tracker_disconnect(trackerClient_);
+}
+
+std::vector<UStringList>
+TrackerClient::sparql_query(const std::string & query) const
+                            throw(Glib::Error)
+{
+    GError * error = 0;
+    GPtrArray * const result = tracker_resources_sparql_query(
+                                   trackerClient_,
+                                   query.c_str(),
+                                   &error);
+    if (0 != error)
+    {
+        Glib::Error::throw_exception(error);
+    }
+
+    std::vector<UStringList> resultv;
+
+    g_ptr_array_foreach (result,
+                         tracker_client_append_result_foreach,
+                         &resultv);
+
+    g_ptr_array_foreach (result, (GFunc) g_strfreev, NULL);
+    g_ptr_array_free (result, TRUE);
+
+    return resultv;
+}
+
+guint
+TrackerClient::sparql_query_async(const std::string & query,
+                                  const SlotAsyncReply & slot) const
+                                  throw()
+{
+    SlotAsyncReply * const slot_copy = new SlotAsyncReply(slot);
+
+    return tracker_resources_sparql_query_async(
+               trackerClient_,
+               query.c_str(),
+               signal_proxy_tracker_reply_gptrarray,
+               slot_copy);
+}
+
+void
+TrackerClient::sparql_update(const std::string & query) const
+                             throw(Glib::Error)
+{
+    GError * error = 0;
+    tracker_resources_sparql_update(trackerClient_,
+                                    query.c_str(),
+                                    &error);
+    if (0 != error)
+    {
+        Glib::Error::throw_exception(error);
+    }
+}
+
+guint
+TrackerClient::sparql_update_async(const std::string & query,
+                                   const SlotAsyncReady & slot) const
+                                   throw()
+{
+    SlotAsyncReady * const slot_copy = new SlotAsyncReady(slot);
+
+    return tracker_resources_sparql_update_async(
+               trackerClient_,
+               query.c_str(),
+               signal_proxy_tracker_reply_void,
+               slot_copy);
+}
+
+} // namespace Solang
diff --git a/src/common/tracker-client.h b/src/common/tracker-client.h
new file mode 100644
index 0000000..5ce28e2
--- /dev/null
+++ b/src/common/tracker-client.h
@@ -0,0 +1,69 @@
+/* -*- 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_TRACKER_CLIENT_H
+#define SOLANG_TRACKER_CLIENT_H
+
+#include <string>
+#include <vector>
+
+#include <glibmm.h>
+#include <libtracker-client/tracker.h>
+#include <sigc++/sigc++.h>
+
+#include "types.h"
+
+namespace Solang
+{
+
+class TrackerClient
+{
+    public:
+        typedef sigc::slot<void, std::vector<UStringList> &>
+            SlotAsyncReply;
+
+        typedef sigc::slot<void> SlotAsyncReady;
+
+        TrackerClient();
+
+        ~TrackerClient();
+
+        std::vector<UStringList>
+        sparql_query(const std::string & query) const
+                     throw(Glib::Error);
+
+        guint
+        sparql_query_async(const std::string & query,
+                           const SlotAsyncReply & slot) const throw();
+
+        void
+        sparql_update(const std::string & query) const
+                      throw(Glib::Error);
+
+        guint
+        sparql_update_async(const std::string & query,
+                            const SlotAsyncReady & slot) const
+                            throw();
+
+    private:
+        ::TrackerClient * trackerClient_;
+};
+
+} // namespace Solang
+
+#endif // SOLANG_TRACKER_CLIENT_H
diff --git a/src/common/types.h b/src/common/types.h
index 0b64819..a36958e 100644
--- a/src/common/types.h
+++ b/src/common/types.h
@@ -29,11 +29,15 @@
 #include <giomm.h>
 #include <glibmm.h>
 #include <gtkmm.h>
-#include <libgdamm.h>
 
 namespace Solang
 {
 
+typedef std::tr1::shared_ptr<const char *> ConstCharPtrPtr;
+
+typedef std::vector<std::string> StringList;
+typedef std::vector<Glib::ustring> UStringList;
+
 class Application;
 typedef const Application * ConstApplicationPtr;
 typedef Application * ApplicationPtr;
@@ -220,15 +224,6 @@ typedef Glib::RefPtr<Gio::DataInputStream> DataInputStreamPtr;
 typedef Glib::RefPtr<const Gio::File> ConstFilePtr;
 typedef Glib::RefPtr<Gio::File> FilePtr;
 
-typedef Glib::RefPtr<const Gnome::Gda::Connection> ConstConnectionPtr;
-typedef Glib::RefPtr<Gnome::Gda::Connection> ConnectionPtr;
-
-typedef Glib::RefPtr<const Gnome::Gda::DataModel> ConstDataModelPtr;
-typedef Glib::RefPtr<Gnome::Gda::DataModel> DataModelPtr;
-
-typedef Glib::RefPtr<const Gnome::Gda::DataSelect> ConstDataSelectPtr;
-typedef Glib::RefPtr<Gnome::Gda::DataSelect> DataSelectPtr;
-
 typedef Glib::RefPtr<const Gtk::Action> ConstActionPtr;
 typedef Glib::RefPtr<Gtk::Action> ActionPtr;
 
diff --git a/src/edit-engine/Makefile.am b/src/edit-engine/Makefile.am
index 5ebcf88..2d26899 100644
--- a/src/edit-engine/Makefile.am
+++ b/src/edit-engine/Makefile.am
@@ -28,11 +28,11 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/edit-engine \
 	-I$(top_srcdir)/src/renderer \
 	$(SOLANG_CFLAGS) \
-	$(EXIV2_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(GTKMM_CFLAGS) \
-	$(GDAMM_CFLAGS) \
 	$(GDL_CFLAGS) \
-	$(GEGL_CFLAGS)
+	$(GEGL_CFLAGS) \
+	$(TRACKER_CFLAGS)
 
 AM_CXXFLAGS = \
 	 -Wall
diff --git a/src/editor/Makefile.am b/src/editor/Makefile.am
index 33adb7d..b2fda7f 100644
--- a/src/editor/Makefile.am
+++ b/src/editor/Makefile.am
@@ -55,11 +55,11 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/renderer \
 	-I$(top_srcdir)/src/storage \
 	$(SOLANG_CFLAGS) \
-	$(EXIV2_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(GTKMM_CFLAGS) \
-	$(GDAMM_CFLAGS) \
 	$(GDL_CFLAGS) \
-	$(GEGL_CFLAGS)
+	$(GEGL_CFLAGS) \
+	$(TRACKER_CFLAGS)
 
 AM_CXXFLAGS = \
 	 -Wall
diff --git a/src/editor/desaturate.cpp b/src/editor/desaturate.cpp
index 198b760..d8fe0c2 100644
--- a/src/editor/desaturate.cpp
+++ b/src/editor/desaturate.cpp
@@ -20,8 +20,6 @@
 #include "config.h"
 #endif
 
-#include <exiv2/image.hpp>
-#include <exiv2/exif.hpp>
 #include <gdkmm.h>
 
 #include "editable-photo.h"
diff --git a/src/editor/editable-photo.cpp b/src/editor/editable-photo.cpp
index 4c62eb7..214c990 100644
--- a/src/editor/editable-photo.cpp
+++ b/src/editor/editable-photo.cpp
@@ -43,7 +43,7 @@ EditablePhoto::EditablePhoto( const PhotoPtr &photo ) throw()
     buffer_( 0 ),
     editBuffer_( ),
     isDirty_( false ),
-    image_(),
+//    image_(),
     toSave_( false )
 {
     setup_photo_for_edit();
@@ -110,22 +110,21 @@ EditablePhoto::save( Engine &engine ) throw(Error)
 
         buffer_->save_to_buffer( buf, size, "jpeg", keys, values );
 
-        Exiv2::Image::AutoPtr target = Exiv2::ImageFactory::open(
-                                         (Exiv2::byte *)buf, size );
-        target->setMetadata( *image_ );
-        target->writeMetadata();
-
-        Exiv2::FileIo file( "/tmp/test.jpg" );
-        file.open("w");
-        file.write( target->io() );
-        file.close();
-
-        Glib::RefPtr<Gio::File> src = Gio::File::create_for_path(
-                                            "/tmp/test.jpg");
-        Glib::RefPtr<Gio::File> dest = Gio::File::create_for_path(
-                                        photo_->get_disk_file_path());
-        src->copy( dest, Gio::FILE_COPY_OVERWRITE );
-        engine.save( photo_ );
+//        Exiv2::Image::AutoPtr target = Exiv2::ImageFactory::open(
+//                                         (Exiv2::byte *)buf, size );
+//        target->setMetadata( *image_ );
+//        target->writeMetadata();
+
+//        Exiv2::FileIo file( "/tmp/test.jpg" );
+//        file.open("w");
+//        file.write( target->io() );
+//        file.close();
+
+//        Glib::RefPtr<Gio::File> src = Gio::File::create_for_path(
+//                                            "/tmp/test.jpg");
+//        Glib::RefPtr<Gio::File> dest = Gio::File::create_for_uri(
+//                                           photo_->get_uri());
+//        src->copy( dest, Gio::FILE_COPY_OVERWRITE );
     }
 }
 
@@ -135,23 +134,20 @@ EditablePhoto::setup_photo_for_edit( ) throw()
     if( !photo_ )
         return;
 
-    if( photo_->get_disk_file_path().empty() )
-        return;
-
-    image_ = Exiv2::ImageFactory::open(
-                            photo_->get_disk_file_path() );
+//    image_ = Exiv2::ImageFactory::open(
+//                 Glib::filename_from_uri(photo_->get_uri()));
 
-    image_->readMetadata();
+//    image_->readMetadata();
 
 #if 0
 
     gchar *buf;
 
-    image_->io()->read( (Exiv2::byte *)buf, image_->io()->size());
+//    image_->io()->read( (Exiv2::byte *)buf, image_->io()->size());
 
     Glib::Ref<Gdk::PixbufLoader> loader = Gdk::PixbufLoader::create();
 
-    loader->write( buf, image_->io()->size() );
+//    loader->write( buf, image_->io()->size() );
 
     buffer_ = loader->get_pixbuf();
 #endif
@@ -161,7 +157,7 @@ EditablePhoto::setup_photo_for_edit( ) throw()
     if( ! buffer_ )
     {
         buffer_ = Gdk::Pixbuf::create_from_file(
-                            photo_->get_disk_file_path());
+                      Glib::filename_from_uri(photo_->get_uri()));
     }
 }
 
diff --git a/src/editor/editable-photo.h b/src/editor/editable-photo.h
index 49360fc..b9b2adb 100644
--- a/src/editor/editable-photo.h
+++ b/src/editor/editable-photo.h
@@ -19,8 +19,6 @@
 #ifndef SOLANG_EDITABLE_PHOTO_H
 #define SOLANG_EDITABLE_PHOTO_H
 
-#include <exiv2/image.hpp>
-#include <exiv2/exif.hpp>
 #include <gdkmm.h>
 
 #include "edit-action-history.h"
@@ -43,8 +41,8 @@ class EditablePhoto
 
                 bool operator ()( const EditablePhotoPtr &lhs )
                 {
-                    return lhs->get_photo()->get_photo_id()
-                                == photo_->get_photo_id();
+                    return lhs->get_photo()->get_uri()
+                                == photo_->get_uri();
                 }
 
             private:
@@ -73,11 +71,11 @@ class EditablePhoto
         void
         set_edit_buffer( const BufferPtr &buffer ) throw();
 
-        inline Exiv2::ExifData &  //Modifiable
-        get_exif_data() throw();
+//        inline Exiv2::ExifData &  //Modifiable
+//        get_exif_data() throw();
 
-        inline Exiv2::XmpData &  //Modifiable
-        get_xmp_data() throw();
+//        inline Exiv2::XmpData &  //Modifiable
+//        get_xmp_data() throw();
 
         void
         save( Engine &engine ) throw(Error);
@@ -112,7 +110,7 @@ class EditablePhoto
         mutable PixbufPtr buffer_;
         mutable BufferPtr editBuffer_;
         mutable bool isDirty_;
-        Exiv2::Image::AutoPtr image_;
+//        Exiv2::Image::AutoPtr image_;
         bool toSave_;
         EditActionHistory appliedActions_;
 };
@@ -135,17 +133,17 @@ EditablePhoto::get_edit_buffer() throw()
     return pixbuf_to_edit_buffer();
 }
 
-inline Exiv2::ExifData &  //Modifiable
-EditablePhoto::get_exif_data() throw()
-{
-    return image_->exifData();
-}
-
-inline Exiv2::XmpData &  //Modifiable
-EditablePhoto::get_xmp_data() throw()
-{
-    return image_->xmpData();
-}
+//inline Exiv2::ExifData &  //Modifiable
+//EditablePhoto::get_exif_data() throw()
+//{
+//    return image_->exifData();
+//}
+
+//inline Exiv2::XmpData &  //Modifiable
+//EditablePhoto::get_xmp_data() throw()
+//{
+//    return image_->xmpData();
+//}
 
 inline bool
 EditablePhoto::get_to_save() const throw()
diff --git a/src/editor/flip.cpp b/src/editor/flip.cpp
index fd6f685..585d297 100644
--- a/src/editor/flip.cpp
+++ b/src/editor/flip.cpp
@@ -20,8 +20,8 @@
 #include "config.h"
 #endif
 
-#include <exiv2/image.hpp>
-#include <exiv2/exif.hpp>
+#include <iostream>
+
 #include <gdkmm.h>
 
 #include "editable-photo.h"
diff --git a/src/editor/rotate.cpp b/src/editor/rotate.cpp
index a51591f..bd52d93 100644
--- a/src/editor/rotate.cpp
+++ b/src/editor/rotate.cpp
@@ -20,8 +20,8 @@
 #include "config.h"
 #endif
 
-#include <exiv2/image.hpp>
-#include <exiv2/exif.hpp>
+#include <iostream>
+
 #include <gdkmm.h>
 
 #include "editable-photo.h"
@@ -123,20 +123,20 @@ Rotate::rotatePhoto( EditablePhoto &photo,
         }
 
         //Update exif
-        {
-            Exiv2::ExifData &exifData = photo.get_exif_data();
-            int32_t width = exifData["Exif.Photo.PixelXDimension"].toLong();
-            int32_t height = exifData["Exif.Photo.PixelYDimension"].toLong();
-            exifData["Exif.Photo.PixelXDimension"] = height;
-            exifData["Exif.Photo.PixelYDimension"] = width;
-        }
-        {
-            Exiv2::XmpData &xmpData = photo.get_xmp_data();
-            int32_t width = xmpData["Xmp.exif.PixelXDimension"].toLong();
-            int32_t height = xmpData["Xmp.exif.PixelYDimension"].toLong();
-            xmpData["Xmp.exif.PixelXDimension"] = height;
-            xmpData["Xmp.exif.PixelYDimension"] = width;
-        }
+//        {
+//            Exiv2::ExifData &exifData = photo.get_exif_data();
+//            int32_t width = exifData["Exif.Photo.PixelXDimension"].toLong();
+//            int32_t height = exifData["Exif.Photo.PixelYDimension"].toLong();
+//            exifData["Exif.Photo.PixelXDimension"] = height;
+//            exifData["Exif.Photo.PixelYDimension"] = width;
+//        }
+//        {
+//            Exiv2::XmpData &xmpData = photo.get_xmp_data();
+//            int32_t width = xmpData["Xmp.exif.PixelXDimension"].toLong();
+//            int32_t height = xmpData["Xmp.exif.PixelYDimension"].toLong();
+//            xmpData["Xmp.exif.PixelXDimension"] = height;
+//            xmpData["Xmp.exif.PixelYDimension"] = width;
+//        }
 
     }
     catch( Error &e )
diff --git a/src/editor/save-photos-window.cpp b/src/editor/save-photos-window.cpp
index cee6768..ab5b774 100644
--- a/src/editor/save-photos-window.cpp
+++ b/src/editor/save-photos-window.cpp
@@ -66,9 +66,8 @@ SavePhotosWindow::SavePhotosWindow( Engine &engine,
                                                 Gdk::INTERP_NEAREST);
         row[ modifiedPhotos_.name_ ] =
                         Glib::filename_display_basename(
-                            Glib::filename_from_utf8(
-                                (*photo)->get_photo()
-                                        ->get_disk_file_path()));
+                            Glib::filename_from_uri(
+                                (*photo)->get_photo()->get_uri()));
         row[ modifiedPhotos_.photo_ ] = *photo;
     }
     show_all_children();
diff --git a/src/editor/scale.cpp b/src/editor/scale.cpp
index 2ada0fe..b9d0560 100644
--- a/src/editor/scale.cpp
+++ b/src/editor/scale.cpp
@@ -20,8 +20,6 @@
 #include "config.h"
 #endif
 
-#include <exiv2/image.hpp>
-#include <exiv2/exif.hpp>
 #include <gdkmm.h>
 
 #include "editable-photo.h"
diff --git a/src/exporter/Makefile.am b/src/exporter/Makefile.am
index 1aa19dc..40bc380 100644
--- a/src/exporter/Makefile.am
+++ b/src/exporter/Makefile.am
@@ -24,10 +24,10 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/renderer \
 	-I$(top_srcdir)/src/storage \
 	$(SOLANG_CFLAGS) \
-	$(EXIV2_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(GTKMM_CFLAGS) \
-	$(GDAMM_CFLAGS) \
-	$(GDL_CFLAGS)
+	$(GDL_CFLAGS) \
+	$(TRACKER_CFLAGS)
 
 AM_CXXFLAGS = \
 	 -Wall
diff --git a/src/exporter/directory-destination.cpp b/src/exporter/directory-destination.cpp
index dc42a6f..77eb885 100644
--- a/src/exporter/directory-destination.cpp
+++ b/src/exporter/directory-destination.cpp
@@ -62,25 +62,10 @@ DirectoryDestination::final(Application & application) throw()
 void
 DirectoryDestination::export_photo(
                           const PhotoPtr & photo,
-                          const IStoragePtr & storage,
                           const ProgressObserverPtr & observer)
                           throw()
 {
-    photo->set_disk_file_path(storage);
-
-    std::string path;
-
-    try
-    {
-        path = Glib::filename_from_utf8(photo->get_disk_file_path());
-    }
-    catch (const Glib::ConvertError & e)
-    {
-        g_warning("%s", e.what().c_str());
-        return;
-    }
-
-    const FilePtr file = Gio::File::create_for_path(path);
+    const FilePtr file = Gio::File::create_for_uri(photo->get_uri());
     const FilePtr dest = Gio::File::create_for_path(
                              filename_ + "/" + file->get_basename());
 
@@ -97,7 +82,6 @@ DirectoryDestination::export_photo(
 void
 DirectoryDestination::export_photos(
                           const PhotoList & photos,
-                          const IStoragePtr & storage,
                           const ProgressObserverPtr & observer)
                           throw()
 {
@@ -136,7 +120,7 @@ DirectoryDestination::export_photos(
 
     for (it = photos.begin(); photos.end() != it; it++)
     {
-        export_photo(*it, storage, observer);
+        export_photo(*it, observer);
 
         if (0 != observer)
         {
diff --git a/src/exporter/directory-destination.h b/src/exporter/directory-destination.h
index cecd875..ca2c332 100644
--- a/src/exporter/directory-destination.h
+++ b/src/exporter/directory-destination.h
@@ -44,12 +44,10 @@ class DirectoryDestination :
 
         virtual void
         export_photo(const PhotoPtr & photo,
-                     const IStoragePtr & storage,
                      const ProgressObserverPtr & observer) throw();
 
         virtual void
         export_photos(const PhotoList & photos,
-                      const IStoragePtr & storage,
                       const ProgressObserverPtr & observer) throw();
 
         virtual void
diff --git a/src/exporter/exporter.cpp b/src/exporter/exporter.cpp
index 62062d3..19c6714 100644
--- a/src/exporter/exporter.cpp
+++ b/src/exporter/exporter.cpp
@@ -23,7 +23,7 @@
 #include <sigc++/sigc++.h>
 
 #include "application.h"
-#include "directory-storage.h"
+//#include "directory-storage.h"
 #include "engine.h"
 #include "exporter-dialog.h"
 #include "exporter.h"
@@ -226,13 +226,11 @@ Exporter::on_exporter_dialog_response(
             Glib::ThreadPool & thread_pool
                 = application_->get_thread_pool();
             Engine & engine = application_->get_engine();
-            const IStoragePtr & storage
-                = engine.get_current_storage_system("file");
 
             thread_pool.push(
-                sigc::bind(sigc::mem_fun2(engine,
-                                         &Engine::export_photos),
-                           photoDestination_, storage));
+                sigc::bind(sigc::mem_fun1(engine,
+                                          &Engine::export_photos),
+                           photoDestination_));
             break;
         }
 
diff --git a/src/importer/Makefile.am b/src/importer/Makefile.am
index f3f12d6..e19452b 100644
--- a/src/importer/Makefile.am
+++ b/src/importer/Makefile.am
@@ -42,13 +42,13 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/renderer \
 	-I$(top_srcdir)/src/storage \
 	$(SOLANG_CFLAGS) \
-	$(EXIV2_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(FLICKCURL_CFLAGS) \
 	$(GPHOTO2_CFLAGS) \
 	$(GTKMM_CFLAGS) \
-	$(GDAMM_CFLAGS) \
 	$(GDL_CFLAGS) \
 	$(SOUP_CFLAGS) \
+	$(TRACKER_CFLAGS) \
 	$(WEBKIT_CFLAGS)
 
 AM_CXXFLAGS = \
diff --git a/src/renderer/Makefile.am b/src/renderer/Makefile.am
index 5534e67..250c35e 100644
--- a/src/renderer/Makefile.am
+++ b/src/renderer/Makefile.am
@@ -37,13 +37,13 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/renderer \
 	-I$(top_srcdir)/src/storage \
 	$(SOLANG_CFLAGS) \
-	$(EXIV2_CFLAGS) \
+	$(DBUS_CFLAGS) \
 	$(GTKIMAGEVIEW_CFLAGS) \
 	$(GTKMM_CFLAGS) \
-	$(GDAMM_CFLAGS) \
 	$(GDL_CFLAGS) \
 	$(BABL_CFLAGS) \
-	$(GEGL_CFLAGS)
+	$(GEGL_CFLAGS) \
+	$(TRACKER_CFLAGS)
 
 AM_CXXFLAGS = \
 	 -Wall
diff --git a/src/renderer/browser-renderer.cpp b/src/renderer/browser-renderer.cpp
index e0048fb..439d831 100644
--- a/src/renderer/browser-renderer.cpp
+++ b/src/renderer/browser-renderer.cpp
@@ -21,6 +21,7 @@
 #include "config.h"
 #endif // HAVE_CONFIG_H
 
+#include <iostream>
 #include <sstream>
 #include <vector>
 
@@ -38,6 +39,7 @@
 #include "photo-search-criteria.h"
 #include "scale-action.h"
 #include "thumbbuf-maker.h"
+#include "thumbnailer.h"
 
 namespace Solang
 {
@@ -86,6 +88,7 @@ BrowserRenderer::BrowserRenderer() throw() :
     paginationBar_(),
     dummyLabel_(),
     scrolledWindow_(),
+    imageLoading_(0),
     treeModelFilter_(),
     thumbnailView_(thumbnailRendererWidth, thumbnailRendererHeight),
     zoomValue_(initialZoomValue),
@@ -278,8 +281,6 @@ BrowserRenderer::init(Application & application) throw()
                                        &BrowserRenderer::on_visible));
     thumbnailView_.set_model(treeModelFilter_);
 
-    Engine & engine = application.get_engine();
-
     MainWindow & main_window = application.get_main_window();
     main_window.add_dock_object_center(GDL_DOCK_OBJECT(dockItem_));
 
@@ -293,13 +294,6 @@ BrowserRenderer::init(Application & application) throw()
 
     ui_manager->insert_action_group(actionGroup_);
 
-    Glib::ThreadPool & thread_pool = application.get_thread_pool();
-    PhotoSearchCriteriaList criterion;
-
-    thread_pool.push(sigc::bind(
-        sigc::mem_fun1<const PhotoSearchCriteriaList &>(
-            engine, &Engine::show), criterion));
-
     signalInitEnd_
         = application.init_end().connect(
               sigc::mem_fun(*this,
@@ -443,6 +437,23 @@ BrowserRenderer::generate_thumbnails() throw()
     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.
@@ -453,24 +464,55 @@ BrowserRenderer::generate_thumbnails() throw()
 
         const PhotoPtr & photo
             = row[model_column_record.get_column_photo()];
-        const PixbufPtr & pixbuf
-            = row[model_column_record.get_column_pixbuf()];
+        const Photo::ThumbnailState thumbnail_state
+            = photo->get_thumbnail_state();
 
-        if (0 == photo->get_thumbnail_buffer() )
+        if (Photo::THUMBNAIL_STATE_NONE == thumbnail_state)
         {
             ThumbbufMaker thumbbuf_maker(thumbnail_width,
                                          thumbnail_height,
                                          false);
 
-            photo->set_thumbnail_buffer( thumbbuf_maker(photo) );
+            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);
 
-            row[model_column_record.get_column_pixbuf()]
-                = photo->get_thumbnail_buffer();
+                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);
 
-            row[model_column_record.get_column_tag_name()]
-                = photo->get_exif_data().get_picture_taken_time();
+                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
+        else if (Photo::THUMBNAIL_STATE_READY == thumbnail_state)
         {
             row[model_column_record.get_column_pixbuf()]
                 = photo->get_thumbnail_buffer();
@@ -673,6 +715,7 @@ BrowserRenderer::on_action_view_zoom_changed(
                      const ScaleActionPtr & scale_action) throw()
 {
     zoomValue_ = scale_action->get_value();
+    imageLoading_.reset();
 
     static sigc::connection connection;
 
@@ -756,7 +799,6 @@ BrowserRenderer::on_switch_page(GtkNotebookPage * notebook_page,
 
             ui_manager->insert_action_group(actionGroup_);
         }
-        reload();
     }
     else
     {
diff --git a/src/renderer/browser-renderer.h b/src/renderer/browser-renderer.h
index 7ec2eec..ad9c778 100644
--- a/src/renderer/browser-renderer.h
+++ b/src/renderer/browser-renderer.h
@@ -155,6 +155,8 @@ class BrowserRenderer :
 
         Gtk::ScrolledWindow scrolledWindow_;
 
+        PixbufPtr imageLoading_;
+
         TreeModelFilterPtr treeModelFilter_;
 
         ThumbnailView thumbnailView_;
diff --git a/src/renderer/console-renderer.cpp b/src/renderer/console-renderer.cpp
index 92b4b0b..9261414 100644
--- a/src/renderer/console-renderer.cpp
+++ b/src/renderer/console-renderer.cpp
@@ -47,8 +47,6 @@ ConsoleRenderer::init(Application & application) throw()
 void
 ConsoleRenderer::render(const PhotoPtr & photo) throw()
 {
-    std::cout << "Photo Path:" << photo->get_disk_file_path()
-              << std::endl;
     std::cout << "Photo Path:" << photo->get_uri() << std::endl;
 }
 
diff --git a/src/renderer/enlarged-renderer.cpp b/src/renderer/enlarged-renderer.cpp
index 371ea64..9ec35ee 100644
--- a/src/renderer/enlarged-renderer.cpp
+++ b/src/renderer/enlarged-renderer.cpp
@@ -121,11 +121,6 @@ EnlargedRenderer::init(Application & application) throw()
 void
 EnlargedRenderer::render(const PhotoPtr & photo) throw()
 {
-    Engine & engine = application_->get_engine();
-    const IStoragePtr & storage = engine.get_current_storage_system(
-                                      "file");
-    photo->set_disk_file_path(storage);
-
     if (0 == pixbufMaker_)
     {
         pixbufMaker_ = PixbufMaker::create(true);
diff --git a/src/renderer/pagination-bar.cpp b/src/renderer/pagination-bar.cpp
index f607eca..cd67f91 100644
--- a/src/renderer/pagination-bar.cpp
+++ b/src/renderer/pagination-bar.cpp
@@ -285,6 +285,8 @@ PaginationBar::scroll_to_position(guint position) throw()
     }
 
     const guint step = get_step();
+    const guint old_lower_limit = lowerLimit_;
+    const guint old_upper_limit = upperLimit_;
 
     if (position < lowerLimit_)
     {
@@ -325,7 +327,11 @@ PaginationBar::scroll_to_position(guint position) throw()
         }
     }
 
-    limitsChanged_.emit();
+    if (old_lower_limit != lowerLimit_
+        || old_upper_limit != upperLimit_)
+    {
+        limitsChanged_.emit();
+    }
 }
 
 void
diff --git a/src/renderer/slideshow-renderer.cpp b/src/renderer/slideshow-renderer.cpp
index f96b2c3..06d79a1 100644
--- a/src/renderer/slideshow-renderer.cpp
+++ b/src/renderer/slideshow-renderer.cpp
@@ -68,17 +68,12 @@ SlideshowRenderer::init(Application & application) throw()
 void
 SlideshowRenderer::render(const PhotoPtr & photo) throw()
 {
-    Engine & engine = application_->get_engine();
-    const IStoragePtr & storage = engine.get_current_storage_system(
-                                      "file");
-    photo->set_disk_file_path(storage);
-
     PixbufPtr pixbuf;
     std::string path;
 
     try
     {
-        path = Glib::filename_from_utf8(photo->get_disk_file_path());
+        path = Glib::filename_from_uri(photo->get_uri());
     }
     catch (const Glib::ConvertError & e)
     {
diff --git a/src/renderer/thumbnail-view.cpp b/src/renderer/thumbnail-view.cpp
index f7f2c0a..19dc038 100644
--- a/src/renderer/thumbnail-view.cpp
+++ b/src/renderer/thumbnail-view.cpp
@@ -230,20 +230,8 @@ ThumbnailView::on_drag_data_get_cb(const DragContextPtr & drag_context,
     for (photo_iter = photos.begin(); photos.end() != photo_iter;
          photo_iter++)
     {
-        PhotoPtr photo = *photo_iter;
-        std::string path;
-
-        try
-        {
-            path = "file://" + Glib::filename_from_utf8(
-                                   photo->get_disk_file_path());
-        }
-        catch (const Glib::ConvertError & e)
-        {
-            continue;
-        }
-
-        uris.push_back(path);
+        const PhotoPtr photo = *photo_iter;
+        uris.push_back(photo->get_uri());
     }
 
     data.set_uris(uris);



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