[niepce: 3/12] Import: rework the import UI. Modularize the importer.



commit 18d8463b5cdacb159e42d8860f8167208fd6f019
Author: Hubert Figuière <hub figuiere net>
Date:   Sat Dec 27 17:34:59 2014 -0500

    Import: rework the import UI. Modularize the importer.

 po/POTFILES.in                            |    1 +
 src/engine/Makefile.am                    |    5 ++
 src/engine/importer/directoryimporter.cpp |   84 +++++++++++++++++++++++++++++
 src/engine/importer/directoryimporter.hpp |   47 ++++++++++++++++
 src/engine/importer/iimporter.hpp         |   55 +++++++++++++++++++
 src/engine/importer/importedfile.cpp      |   10 ++++
 src/engine/importer/importedfile.hpp      |   53 ++++++++++++++++++
 src/niepce/ui/dialogs/importdialog.cpp    |   60 +++++++++++++-------
 src/niepce/ui/dialogs/importdialog.hpp    |   31 +++++++++--
 src/niepce/ui/dialogs/importdialog.ui     |   35 ++++++------
 10 files changed, 338 insertions(+), 43 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6ea19b5..6b697de 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -5,6 +5,7 @@ data/niepce.desktop.in.in
 magellan/src/mgwindow.cpp
 [type: gettext/glade]magellan/src/mgwindow.ui
 src/engine/db/library.cpp
+src/engine/importer/directoryimporter.cpp
 src/fwk/toolkit/application.cpp
 src/fwk/toolkit/frame.cpp
 src/fwk/toolkit/metadatawidget.cpp
diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am
index 1ed8d38..c980ffc 100644
--- a/src/engine/Makefile.am
+++ b/src/engine/Makefile.am
@@ -49,4 +49,9 @@ libniepceengine_a_SOURCES = \
        library/commands.hpp library/commands.cpp \
        library/thumbnailcache.hpp library/thumbnailcache.cpp \
        library/thumbnailnotification.hpp \
+       importer/iimporter.hpp \
+       importer/directoryimporter.hpp \
+       importer/directoryimporter.cpp \
+       importer/importedfile.hpp \
+       importer/importedfile.cpp \
        $(NULL)
diff --git a/src/engine/importer/directoryimporter.cpp b/src/engine/importer/directoryimporter.cpp
new file mode 100644
index 0000000..4a9a62a
--- /dev/null
+++ b/src/engine/importer/directoryimporter.cpp
@@ -0,0 +1,84 @@
+/*
+ * niepce - engine/importer/directoryimporter.cpp
+ *
+ * Copyright (C) 2014 Hubert Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glibmm/i18n.h>
+
+#include "fwk/utils/files.hpp"
+#include "fwk/utils/pathutils.hpp"
+#include "engine/importer/directoryimporter.hpp"
+#include "engine/importer/importedfile.hpp"
+
+namespace eng {
+
+class DirectoryImportedFile
+  : public ImportedFile
+{
+public:
+  DirectoryImportedFile(const std::string & path)
+    : m_path(path)
+    {
+      m_name = fwk::path_basename(path);
+    }
+  const std::string & name() override
+    {
+      return m_name;
+    }
+private:
+  std::string m_name;
+  std::string m_path;
+};
+
+
+DirectoryImporter::DirectoryImporter()
+{
+}
+
+DirectoryImporter::~DirectoryImporter()
+{
+}
+
+std::string DirectoryImporter::name() const
+{
+  return _("Directory");
+}
+
+bool DirectoryImporter::listTargetContent(const std::string & target)
+{
+  auto content = fwk::FileList::getFilesFromDirectory(target,
+                                                   &fwk::filter_xmp_out);
+  for(const auto & entry : *content)
+  {
+    std::lock_guard<std::mutex> lock(m_content_lock);
+    m_content.push_back(ImportedFile::Ptr(new DirectoryImportedFile(entry)));
+  }
+  return true;
+}
+
+std::list<ImportedFile::Ptr> DirectoryImporter::getTargetContent()
+{
+  std::list<ImportedFile::Ptr> content;
+  {
+    std::lock_guard<std::mutex> lock(m_content_lock);
+    content = std::move(m_content);
+    m_content.clear();
+  }
+  return content;
+}
+
+}
diff --git a/src/engine/importer/directoryimporter.hpp b/src/engine/importer/directoryimporter.hpp
new file mode 100644
index 0000000..cddefb9
--- /dev/null
+++ b/src/engine/importer/directoryimporter.hpp
@@ -0,0 +1,47 @@
+/*
+ * niepce - engine/importer/directoryimporter.hpp
+ *
+ * Copyright (C) 2014 Hubert Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include <mutex>
+
+#include "fwk/utils/files.hpp"
+#include "engine/importer/iimporter.hpp"
+
+namespace eng {
+
+
+class DirectoryImporter
+  : public IImporter {
+public:
+  DirectoryImporter();
+  virtual ~DirectoryImporter();
+
+  std::string name() const override;
+
+  bool listTargetContent(const std::string & target) override;
+  std::list<ImportedFile::Ptr> getTargetContent() override;
+
+private:
+  std::mutex m_content_lock;
+  std::list<ImportedFile::Ptr> m_content;
+};
+
+}
diff --git a/src/engine/importer/iimporter.hpp b/src/engine/importer/iimporter.hpp
new file mode 100644
index 0000000..595b7fd
--- /dev/null
+++ b/src/engine/importer/iimporter.hpp
@@ -0,0 +1,55 @@
+/*
+ * niepce - engine/importer/iimporter.hpp
+ *
+ * Copyright (C) 2014 Hubert Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "engine/importer/importedfile.hpp"
+
+namespace eng {
+
+/**
+ * Interface for importers.
+ */
+class IImporter {
+public:
+  virtual ~IImporter() {}
+
+  /** User visible importer name. */
+  virtual std::string name() const = 0;
+
+  /** list the target content and store it. */
+  virtual bool listTargetContent(const std::string & target) = 0;
+
+  /** get the target content. */
+  virtual std::list<ImportedFile::Ptr> getTargetContent() = 0;
+};
+
+}
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  c-basic-offset:2
+  indent-tabs-mode:nil
+  tab-width:2
+  fill-column:99
+  End:
+*/
diff --git a/src/engine/importer/importedfile.cpp b/src/engine/importer/importedfile.cpp
new file mode 100644
index 0000000..f59b1d0
--- /dev/null
+++ b/src/engine/importer/importedfile.cpp
@@ -0,0 +1,10 @@
+
+
+
+#include "importedfile.hpp"
+
+
+
+namespace eng {
+
+}
diff --git a/src/engine/importer/importedfile.hpp b/src/engine/importer/importedfile.hpp
new file mode 100644
index 0000000..cdef14f
--- /dev/null
+++ b/src/engine/importer/importedfile.hpp
@@ -0,0 +1,53 @@
+/*
+ * niepce - niepce/eng/importer/importedfile.hpp
+ *
+ * Copyright (C) 2014 Hubert Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+namespace eng {
+
+// XXX make not copyable
+class ImportedFile {
+public:
+  typedef std::shared_ptr<ImportedFile> Ptr;
+
+  virtual ~ImportedFile()
+    {}
+
+  virtual const std::string & name() = 0;
+private:
+};
+
+
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  c-basic-offset:2
+  indent-tabs-mode:nil
+  tab-width:2
+  fill-column:99
+  End:
+*/
+
diff --git a/src/niepce/ui/dialogs/importdialog.cpp b/src/niepce/ui/dialogs/importdialog.cpp
index c73252e..bf21897 100644
--- a/src/niepce/ui/dialogs/importdialog.cpp
+++ b/src/niepce/ui/dialogs/importdialog.cpp
@@ -35,6 +35,9 @@
 #include "fwk/utils/pathutils.hpp"
 #include "fwk/toolkit/configuration.hpp"
 #include "fwk/toolkit/application.hpp"
+#include "fwk/toolkit/widgets/imagegridview.hpp"
+#include "engine/importer/directoryimporter.hpp"
+#include "engine/importer/importedfile.hpp"
 #include "importdialog.hpp"
 
 using fwk::Configuration;
@@ -44,16 +47,21 @@ namespace ui {
 
 ImportDialog::ImportDialog()
     : fwk::Dialog(GLADEDIR"importdialog.ui", "importDialog")
+    , m_importer(nullptr)
     , m_date_tz_combo(nullptr)
     , m_ufraw_import_check(nullptr)
     , m_rawstudio_import_check(nullptr)
     , m_directory_name(nullptr)
     , m_destinationFolder(nullptr)
     , m_attributesScrolled(nullptr)
-    , m_imagesList(nullptr)
+    , m_images_list_scrolled(nullptr)
 {
 }
 
+ImportDialog::~ImportDialog()
+{
+    delete m_importer;
+}
 
 void ImportDialog::setup_widget()
 {
@@ -61,8 +69,6 @@ void ImportDialog::setup_widget()
         return;
     }
 
-    add_header(_("Import"));
-
     Glib::RefPtr<Gtk::Builder> a_builder = builder();
     Gtk::Button *select_directories = nullptr;
 
@@ -73,19 +79,26 @@ void ImportDialog::setup_widget()
     a_builder->get_widget("ufraw_import_check", m_ufraw_import_check);
     a_builder->get_widget("rawstudio_import_check", m_rawstudio_import_check);
     a_builder->get_widget("directory_name", m_directory_name);
-    a_builder->get_widget("imagesList", m_imagesList);
     a_builder->get_widget("destinationFolder", m_destinationFolder);
 
+    // Metadata pane.
     a_builder->get_widget("attributes_scrolled", m_attributesScrolled);
-    // this is where we'll put the metadata controller.
     m_metadata_pane = MetaDataPaneController::Ptr(new MetaDataPaneController);
     auto w = m_metadata_pane->buildWidget();
     add(m_metadata_pane);
     m_attributesScrolled->add(*w);
     w->show_all();
 
-    m_imagesListModel = m_imagesListModelRecord.inject(*m_imagesList);
-    m_imagesList->set_model(m_imagesListModel);
+    // Gridview of previews.
+    a_builder->get_widget("images_list_scrolled", m_images_list_scrolled);
+    m_imagesListModel = Gtk::ListStore::create(m_grid_columns);
+    m_gridview = Gtk::manage(
+        new Gtk::IconView(
+            Glib::RefPtr<Gtk::TreeModel>::cast_dynamic(m_imagesListModel)));
+    m_gridview->set_pixbuf_column(m_grid_columns.pixbuf);
+    m_gridview->set_text_column(m_grid_columns.filename);
+    m_gridview->show();
+    m_images_list_scrolled->add(*m_gridview);
     m_is_setup = true;
 }
 
@@ -119,12 +132,15 @@ void ImportDialog::doSelectDirectories()
 
 void ImportDialog::setToImport(const Glib::ustring & f)
 {
-
-    auto future1 = std::async(std::launch::async,
-                              [f] () {
-                                  return fwk::FileList::getFilesFromDirectory(
-                                      f, &fwk::filter_xmp_out);
-                              });
+    if (!m_importer) {
+        // FIXME this should be the right kind
+        m_importer = new eng::DirectoryImporter;
+    }
+    auto target_content = std::async(std::launch::async,
+                                     [f, this] () {
+                                         return m_importer->listTargetContent(
+                                             f);
+                                     });
 
     m_folder_path_to_import = f;
     m_destinationFolder->set_text(fwk::path_basename(f));
@@ -132,15 +148,16 @@ void ImportDialog::setToImport(const Glib::ustring & f)
 
     m_imagesListModel->clear();
 
-    auto list_to_import = future1.get();
+    if(target_content.get()) {
+        auto list_to_import = m_importer->getTargetContent();
 
-    std::for_each(list_to_import->begin(), list_to_import->end(),
-                  [this] (const std::string & s) {
-                      DBG_OUT("selected %s", s.c_str());
-                      Gtk::TreeIter iter = m_imagesListModel->append();
-                      iter->set_value(m_imagesListModelRecord.m_col1, s);
-                  }
-        );
+        for(const auto & f : list_to_import) {
+            DBG_OUT("selected %s", f->name().c_str());
+            Gtk::TreeIter iter = m_imagesListModel->append();
+            iter->set_value(m_grid_columns.filename, Glib::ustring(f->name()));
+            iter->set_value(m_grid_columns.file, std::move(f));
+        }
+    }
 }
 
 }
@@ -150,6 +167,7 @@ void ImportDialog::setToImport(const Glib::ustring & f)
   mode:c++
   c-file-style:"stroustrup"
   c-file-offsets:((innamespace . 0))
+  c-basic-offset:2
   indent-tabs-mode:nil
   tab-width:2
   fill-column:99
diff --git a/src/niepce/ui/dialogs/importdialog.hpp b/src/niepce/ui/dialogs/importdialog.hpp
index ea92537..d7601f3 100644
--- a/src/niepce/ui/dialogs/importdialog.hpp
+++ b/src/niepce/ui/dialogs/importdialog.hpp
@@ -29,6 +29,7 @@
 
 #include <glibmm/refptr.h>
 
+#include "engine/importer/importedfile.hpp"
 #include "fwk/toolkit/gtkutils.hpp"
 #include "fwk/toolkit/dialog.hpp"
 #include "imageliststore.hpp"
@@ -41,6 +42,14 @@ class CheckButton;
 class TreeView;
 }
 
+namespace fwk {
+class ImageGridView;
+}
+
+namespace eng {
+class IImporter;
+}
+
 namespace ui {
 
 class ImportDialog
@@ -49,7 +58,19 @@ class ImportDialog
 public:
     typedef std::shared_ptr<ImportDialog> Ptr;
 
+    class PreviewGridModel
+        : public Gtk::TreeModel::ColumnRecord
+    {
+    public:
+        Gtk::TreeModelColumn<Glib::ustring> filename;
+        Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf>> pixbuf;
+        Gtk::TreeModelColumn<eng::ImportedFile::Ptr> file;
+        PreviewGridModel()
+            { add(filename); add(pixbuf); add(file); }
+    };
+
     ImportDialog();
+    virtual ~ImportDialog();
 
     void setup_widget() override;
 
@@ -64,8 +85,8 @@ private:
 
     void doSelectDirectories();
 
-  Glib::ustring m_folder_path_to_import;
-//  std::list<std::string> m_list_to_import;
+    eng::IImporter *m_importer;
+    Glib::ustring m_folder_path_to_import;
 
     Gtk::ComboBox *m_date_tz_combo;
     Gtk::CheckButton *m_ufraw_import_check;
@@ -73,10 +94,12 @@ private:
     Gtk::Label *m_directory_name;
     Gtk::Entry *m_destinationFolder;
     Gtk::ScrolledWindow *m_attributesScrolled;
-    Gtk::TreeView *m_imagesList;
-    fwk::TextModelRecord m_imagesListModelRecord;
+    Gtk::ScrolledWindow *m_images_list_scrolled;
+    PreviewGridModel m_grid_columns;
     Glib::RefPtr<Gtk::ListStore> m_imagesListModel;
 
+    Gtk::IconView *m_gridview;
+
     MetaDataPaneController::Ptr m_metadata_pane;
 };
 
diff --git a/src/niepce/ui/dialogs/importdialog.ui b/src/niepce/ui/dialogs/importdialog.ui
index f47659c..76d8afe 100644
--- a/src/niepce/ui/dialogs/importdialog.ui
+++ b/src/niepce/ui/dialogs/importdialog.ui
@@ -223,7 +223,6 @@
                     <property name="xalign">0</property>
                     <property name="label" translatable="yes">_Images to import</property>
                     <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">imagesList</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
@@ -232,21 +231,13 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkScrolledWindow" id="scroller1">
+                  <object class="GtkScrolledWindow" id="images_list_scrolled">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="hscrollbar_policy">never</property>
                     <property name="shadow_type">in</property>
                     <child>
-                      <object class="GtkTreeView" id="imagesList">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="headers_visible">False</property>
-                        <property name="headers_clickable">False</property>
-                        <child internal-child="selection">
-                          <object class="GtkTreeSelection" id="treeview-selection1"/>
-                        </child>
-                      </object>
+                      <placeholder/>
                     </child>
                   </object>
                   <packing>
@@ -388,12 +379,15 @@
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
                             <property name="label_xalign">0</property>
-                            <property name="shadow_type">in</property>
+                            <property name="shadow_type">none</property>
                             <child>
                               <object class="GtkAlignment" id="alignment1">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="left_padding">12</property>
+                                <property name="top_padding">4</property>
+                                <property name="bottom_padding">4</property>
+                                <property name="left_padding">16</property>
+                                <property name="right_padding">4</property>
                                 <child>
                                   <object class="GtkComboBox" id="preset_combo">
                                     <property name="visible">True</property>
@@ -430,12 +424,15 @@
                             <property name="can_focus">False</property>
                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | 
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                             <property name="label_xalign">0</property>
-                            <property name="shadow_type">in</property>
+                            <property name="shadow_type">none</property>
                             <child>
                               <object class="GtkAlignment" id="alignment2">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="left_padding">12</property>
+                                <property name="top_padding">4</property>
+                                <property name="bottom_padding">4</property>
+                                <property name="left_padding">16</property>
+                                <property name="right_padding">4</property>
                                 <child>
                                   <object class="GtkBox" id="vbox1">
                                     <property name="visible">True</property>
@@ -502,19 +499,21 @@
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
                             <property name="label_xalign">0</property>
-                            <property name="shadow_type">in</property>
+                            <property name="shadow_type">none</property>
                             <child>
                               <object class="GtkAlignment" id="attributes_frame_bin">
                                 <property name="visible">True</property>
                                 <property name="can_focus">False</property>
-                                <property name="left_padding">12</property>
+                                <property name="top_padding">4</property>
+                                <property name="bottom_padding">4</property>
+                                <property name="left_padding">16</property>
+                                <property name="right_padding">4</property>
                                 <child>
                                   <object class="GtkScrolledWindow" id="attributes_scrolled">
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
                                     <property name="vexpand">True</property>
                                     <property name="hscrollbar_policy">never</property>
-                                    <property name="shadow_type">in</property>
                                     <child>
                                       <placeholder/>
                                     </child>


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