[niepce] importer: camera importer (part 1)
- From: Hubert Figuière <hub src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [niepce] importer: camera importer (part 1)
- Date: Thu, 1 Jun 2017 03:40:14 +0000 (UTC)
commit fe38dcf6e43d9c623cbe3068031d298dce9f78f3
Author: Hubert Figuière <hub figuiere net>
Date: Thu May 25 00:08:30 2017 -0400
importer: camera importer (part 1)
- implement more of the gphoto wrapper.
- tweak the importer interface.
camerawire/src/Makefile.am | 5 +-
camerawire/src/cwwindow.hpp | 2 +-
configure.ac | 2 +-
src/engine/Makefile.am | 1 +
src/engine/importer/cameraimporter.cpp | 71 +++++-
src/engine/importer/cameraimporter.hpp | 5 +
src/engine/importer/directoryimporter.cpp | 12 +-
src/engine/importer/importedfile.hpp | 3 +-
src/fwk/base/option.hpp | 68 +++---
src/fwk/utils/gphoto.cpp | 285 ++++++++++++++++----
src/fwk/utils/gphoto.hpp | 102 +++++---
src/niepce/Makefile.am | 1 +
src/niepce/ui/Makefile.am | 4 +-
src/niepce/ui/dialogs/importdialog.cpp | 4 +-
.../ui/dialogs/importers/cameraimporterui.cpp | 46 +++-
.../ui/dialogs/importers/cameraimporterui.hpp | 15 +-
.../ui/dialogs/importers/cameraimporterui.ui | 50 ++++
src/niepce/ui/dialogs/importers/importerui.cpp | 29 ++-
src/niepce/ui/dialogs/importers/importerui.hpp | 26 +-
19 files changed, 561 insertions(+), 170 deletions(-)
---
diff --git a/camerawire/src/Makefile.am b/camerawire/src/Makefile.am
index 1a8fba9..41debe6 100644
--- a/camerawire/src/Makefile.am
+++ b/camerawire/src/Makefile.am
@@ -13,9 +13,10 @@ camerawire_SOURCES = \
cwwindow.hpp cwwindow.cpp \
main.cpp
-camerawire_LDADD = @FRAMEWORK_LIBS@ \
- @GPHOTO_LIBS@ \
+camerawire_LDADD = \
$(top_builddir)/src/fwk/toolkit/libniepceframework.a \
$(top_builddir)/src/fwk/utils/libniepceutils.a \
$(top_builddir)/src/fwk/base/libfwkbase.a \
+ @FRAMEWORK_LIBS@ \
+ @GPHOTO_LIBS@ \
$(NULL)
diff --git a/camerawire/src/cwwindow.hpp b/camerawire/src/cwwindow.hpp
index 08fca8f..a2177d5 100644
--- a/camerawire/src/cwwindow.hpp
+++ b/camerawire/src/cwwindow.hpp
@@ -56,7 +56,7 @@ private:
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > m_icon;
Gtk::TreeModelColumn<std::string> m_label;
- Gtk::TreeModelColumn<fwk::GpDevice::Ptr> m_camera;
+ Gtk::TreeModelColumn<fwk::GpDevicePtr> m_camera;
Gtk::TreeModelColumn<bool> m_persistent;
};
diff --git a/configure.ac b/configure.ac
index 152e5a8..1981c19 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,7 +18,7 @@ EXEMPI_VERSION=2.2.0
SQLITE_VERSION=3.0
GEGL_VERSION=0.3.0
LIBOPENRAW_VERSION=0.1.0
-LIBGPHOTO_VERSION=2.4
+LIBGPHOTO_VERSION=2.5
dnl need at least 2.5.0 because of xmlTextReader
LIBXML2_VERSION=2.5.0
BOOST_VERSION=1.34
diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am
index b26bd29..f71d219 100644
--- a/src/engine/Makefile.am
+++ b/src/engine/Makefile.am
@@ -1,6 +1,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/src/ @FRAMEWORK_CFLAGS@ \
+ @GPHOTO_CFLAGS@ \
$(NULL)
TESTS = test_library test_filebundle test_opqueue
diff --git a/src/engine/importer/cameraimporter.cpp b/src/engine/importer/cameraimporter.cpp
index b6b8727..96466d2 100644
--- a/src/engine/importer/cameraimporter.cpp
+++ b/src/engine/importer/cameraimporter.cpp
@@ -20,14 +20,44 @@
#include "cameraimporter.hpp"
+#include "fwk/base/debug.hpp"
+
namespace eng {
+
+class CameraImportedFile
+ : public ImportedFile
+{
+public:
+ CameraImportedFile(const std::pair<std::string, std::string>& desc)
+ : CameraImportedFile(desc.first, desc.second)
+ { }
+
+ CameraImportedFile(const std::string& folder, const std::string& filename)
+ : m_folder(folder)
+ , m_filename(filename)
+ , m_path(m_folder + "/" + m_filename)
+ { }
+ const std::string& name() const override
+ { return m_filename; }
+ const std::string& path() const override
+ { return m_path; }
+private:
+ std::string m_folder;
+ std::string m_filename;
+ std::string m_path;
+};
+
+
CameraImporter::CameraImporter()
{
}
CameraImporter::~CameraImporter()
{
+ if (m_camera) {
+ m_camera->close();
+ }
}
const std::string& CameraImporter::id() const
@@ -36,20 +66,59 @@ const std::string& CameraImporter::id() const
return _id;
}
-bool CameraImporter::list_source_content(const std::string & source,
+bool CameraImporter::list_source_content(const std::string& source,
const SourceContentReady& callback)
{
+ if (ensure_camera_open(source)) {
+ auto content = m_camera->list_content();
+ std::list<ImportedFilePtr> file_list;
+ for (auto item : content) {
+ file_list.push_back(ImportedFilePtr(new CameraImportedFile(item)));
+ }
+
+ callback(std::move(file_list));
+ return true;
+ }
+ return false;
}
bool CameraImporter::get_previews_for(const std::string& source,
const std::list<std::string>& paths,
const PreviewReady& callback)
{
+ if (ensure_camera_open(source)) {
+ for (auto path: paths) {
+ DBG_OUT("want thumbnail %s", path.c_str());
+ fwk::Thumbnail thumbnail = m_camera->get_preview(path);
+ callback(path, thumbnail);
+ }
+
+ return true;
+ }
+ return false;
}
bool CameraImporter::do_import(const std::string & source,
const FileImporter & importer)
{
+ if (ensure_camera_open(source)) {
+
+ }
+ return false;
+}
+
+bool CameraImporter::ensure_camera_open(const std::string& source)
+{
+ if (!m_camera || m_camera->path() != source) {
+ auto result = fwk::GpDeviceList::obj().get_device(source);
+ if (result.ok()) {
+ m_camera.reset(new fwk::GpCamera(result.unwrap()));
+ }
+ }
+ if (m_camera) {
+ m_camera->open();
+ }
+ return !!m_camera;
}
}
diff --git a/src/engine/importer/cameraimporter.hpp b/src/engine/importer/cameraimporter.hpp
index 61bb59d..61f0fe7 100644
--- a/src/engine/importer/cameraimporter.hpp
+++ b/src/engine/importer/cameraimporter.hpp
@@ -24,6 +24,7 @@
#include <list>
#include "fwk/utils/files.hpp"
+#include "fwk/utils/gphoto.hpp"
#include "engine/importer/iimporter.hpp"
namespace eng {
@@ -43,6 +44,10 @@ public:
bool do_import(const std::string & source,
const FileImporter & importer) override;
+private:
+ bool ensure_camera_open(const std::string&);
+ std::string m_camera_desc;
+ fwk::GpCameraPtr m_camera;
};
}
diff --git a/src/engine/importer/directoryimporter.cpp b/src/engine/importer/directoryimporter.cpp
index 767f318..76ce623 100644
--- a/src/engine/importer/directoryimporter.cpp
+++ b/src/engine/importer/directoryimporter.cpp
@@ -37,10 +37,10 @@ public:
{
m_name = fwk::path_basename(path);
}
- const std::string & name() const override
- {
- return m_name;
- }
+ const std::string& name() const override
+ { return m_name; }
+ const std::string& path() const override
+ { return m_path; }
private:
std::string m_name;
std::string m_path;
@@ -83,8 +83,8 @@ bool DirectoryImporter::get_previews_for(const std::string& source,
const PreviewReady& callback)
{
for (auto path : paths) {
- auto full_path = Glib::build_filename(source, path);
- auto thumbnail = fwk::Thumbnail::thumbnail_file(full_path, 160, 160, 0);
+ DBG_OUT("path %s", path.c_str());
+ auto thumbnail = fwk::Thumbnail::thumbnail_file(path, 160, 160, 0);
callback(path, thumbnail);
}
return true;
diff --git a/src/engine/importer/importedfile.hpp b/src/engine/importer/importedfile.hpp
index af3c2fb..2114900 100644
--- a/src/engine/importer/importedfile.hpp
+++ b/src/engine/importer/importedfile.hpp
@@ -34,7 +34,8 @@ public:
virtual ~ImportedFile()
{}
- virtual const std::string & name() const = 0;
+ virtual const std::string& name() const = 0;
+ virtual const std::string& path() const = 0;
};
typedef std::shared_ptr<ImportedFile> ImportedFilePtr;
diff --git a/src/fwk/base/option.hpp b/src/fwk/base/option.hpp
index 76df967..2bdd7fc 100644
--- a/src/fwk/base/option.hpp
+++ b/src/fwk/base/option.hpp
@@ -30,42 +30,44 @@ template<class T>
class Option
{
public:
- typedef T data_type;
+ typedef T data_type;
- Option()
- : m_none(true)
- {
- }
- Option(T&& data)
- : m_none(false)
- , m_data(data)
- {
- }
- Option(const T& data)
- : m_none(false)
- , m_data(data)
- {
- }
- template<class... Args>
- Option(Args&&... args)
- : m_none(false)
- , m_data(args...)
- {
- }
+ Option()
+ : m_none(true)
+ {
+ }
+ Option(T&& data)
+ : m_none(false)
+ , m_data(data)
+ {
+ }
+ Option(const T& data)
+ : m_none(false)
+ , m_data(data)
+ {
+ }
+ template<class... Args>
+ Option(Args&&... args)
+ : m_none(false)
+ , m_data(args...)
+ {
+ }
- T&& unwrap()
- {
- if (m_none) {
- throw std::runtime_error("none option value");
- }
- m_none = true;
- return std::move(m_data);
- }
- bool empty() const
- { return m_none; }
+ T&& unwrap()
+ {
+ if (m_none) {
+ throw std::runtime_error("none option value");
+ }
+ m_none = true;
+ return std::move(m_data);
+ }
+ bool ok() const
+ { return !empty(); }
+ bool empty() const
+ { return m_none; }
private:
- bool m_none;
- T m_data;
+ bool m_none;
+ T m_data;
};
diff --git a/src/fwk/utils/gphoto.cpp b/src/fwk/utils/gphoto.cpp
index 8d302a3..3c2a24c 100644
--- a/src/fwk/utils/gphoto.cpp
+++ b/src/fwk/utils/gphoto.cpp
@@ -1,7 +1,8 @@
+/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode:nil; -*- */
/*
* niepce - fwk/utils/gphoto.cpp
*
- * Copyright (C) 2009 Hubert Figuiere
+ * Copyright (C) 2009-2017 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
@@ -18,102 +19,276 @@
*/
#include <string.h>
+#include <string>
+#include <vector>
-extern "C" {
+#include <gphoto2-port-info-list.h>
+#include <gphoto2-abilities-list.h>
+#include <gphoto2-camera.h>
+#include <gphoto2-context.h>
#include <gphoto2-port-result.h>
-}
+
+#include <gdkmm/pixbufloader.h>
#include "fwk/base/debug.hpp"
+#include "fwk/utils/pathutils.hpp"
+#include "fwk/toolkit/thumbnail.hpp"
#include "gphoto.hpp"
namespace fwk {
-#define GP_CHECK(x,op) if (x < GP_OK) { \
- DBG_OUT("%s failed with %d",#op,x); }
+#define GP_CHECK(x, op) if (x < GP_OK) { \
+ DBG_OUT("%s failed with %d", #op, x); }
-GpDevice::GpDevice(const std::string & model, const std::string & path)
- : m_model(model)
- , m_path(path)
+GpDevice::GpDevice(const std::string& model, const std::string& path)
+ : m_model(model)
+ , m_path(path)
{
}
GpDeviceList::GpDeviceList()
- : m_abilities(NULL)
- , m_ports(NULL)
+ : m_abilities(nullptr)
+ , m_ports(nullptr)
{
- reload();
+ reload();
}
GpDeviceList::~GpDeviceList()
{
- _gp_cleanup();
+ gp_cleanup();
}
-void GpDeviceList::_gp_cleanup()
+void GpDeviceList::gp_cleanup()
{
- if (m_abilities) {
- ::gp_abilities_list_free(m_abilities);
- m_abilities = NULL;
- }
- if (m_ports) {
- ::gp_port_info_list_free(m_ports);
- m_ports = NULL;
- }
+ if (m_abilities) {
+ ::gp_abilities_list_free(m_abilities);
+ m_abilities = nullptr;
+ }
+ if (m_ports) {
+ ::gp_port_info_list_free(m_ports);
+ m_ports = nullptr;
+ }
}
void GpDeviceList::reload()
{
- _gp_cleanup();
+ gp_cleanup();
- int ret;
- ret = ::gp_port_info_list_new(&m_ports);
- GP_CHECK(ret, gp_port_info_list_new);
- ret = ::gp_port_info_list_load(m_ports);
- GP_CHECK(ret, gp_port_list_load);
+ int ret;
+ ret = ::gp_port_info_list_new(&m_ports);
+ GP_CHECK(ret, gp_port_info_list_new);
+ ret = ::gp_port_info_list_load(m_ports);
+ GP_CHECK(ret, gp_port_list_load);
ret = ::gp_abilities_list_new(&m_abilities);
- GP_CHECK(ret, gp_abilities_list_new);
- ret = ::gp_abilities_list_load(m_abilities, NULL);
- GP_CHECK(ret, gp_abilities_list_load);
+ GP_CHECK(ret, gp_abilities_list_new);
+ ret = ::gp_abilities_list_load(m_abilities, NULL);
+ GP_CHECK(ret, gp_abilities_list_load);
}
void GpDeviceList::detect()
{
- if((!m_ports) || (!m_abilities)) {
- reload();
- }
- ::CameraList *cameraList;
- int ret;
-
- ret = ::gp_list_new(&cameraList);
- GP_CHECK(ret, gp_list_new);
- ret = ::gp_abilities_list_detect(m_abilities, m_ports, cameraList, NULL);
- GP_CHECK(ret, gp_abilities_list_detect);
-
- int count = ::gp_list_count(cameraList);
- for (int i = 0; i < count; i++) {
- const char * name;
- const char * value;
- ret = ::gp_list_get_name(cameraList, i, &name);
- GP_CHECK(ret, gp_list_get_name);
- ret = ::gp_list_get_value(cameraList, i, &value);
- GP_CHECK(ret, gp_list_get_value);
- if ((count > 1) && (strcmp(value, "usb:") == 0)) {
- continue;
+ if((!m_ports) || (!m_abilities)) {
+ reload();
+ }
+ ::CameraList *camera_list;
+ int ret;
+
+ ret = ::gp_list_new(&camera_list);
+ GP_CHECK(ret, gp_list_new);
+ ret = ::gp_abilities_list_detect(m_abilities, m_ports, camera_list, nullptr);
+ GP_CHECK(ret, gp_abilities_list_detect);
+
+ int count = ::gp_list_count(camera_list);
+ for (int i = 0; i < count; i++) {
+ const char * name = nullptr;
+ const char * value = nullptr;
+
+ ret = ::gp_list_get_name(camera_list, i, &name);
+ GP_CHECK(ret, gp_list_get_name);
+
+ ret = ::gp_list_get_value(camera_list, i, &value);
+ GP_CHECK(ret, gp_list_get_value);
+
+ if ((count > 1) && (strcmp(value, "usb:") == 0)) {
+ continue;
+ }
+ DBG_OUT("found %s %s", name, value);
+ push_back(GpDevicePtr(new GpDevice(name, value)));
+ }
+ ::gp_list_free(camera_list);
+}
+
+fwk::Option<GpDevicePtr> GpDeviceList::get_device(const std::string& device)
+{
+ for (auto d : fwk::GpDeviceList::obj()) {
+ if (d->get_path() == device) {
+ return fwk::Option<GpDevicePtr>(d);
+ }
}
- DBG_OUT("found %s %s", name, value);
- push_back(GpDevice::Ptr(new GpDevice(name,value)));
- }
- ::gp_list_free(cameraList);
+ return fwk::Option<GpDevicePtr>();
+}
+
+class GpCamera::Priv {
+public:
+ Priv()
+ : camera(nullptr)
+ , context(::gp_context_new())
+ {
+ }
+ ~Priv()
+ {
+ if (camera) {
+ ::gp_camera_unref(camera);
+ }
+ ::gp_context_unref(context);
+ }
+ ::Camera* camera;
+ ::GPContext* context;
+};
+
+GpCamera::GpCamera(const GpDevicePtr& device)
+ : m_device(device)
+ , m_priv(new Priv)
+{
}
+GpCamera::~GpCamera()
+{
+ delete m_priv;
+}
+
+bool GpCamera::open()
+{
+ bool success = false;
+ if (m_priv->camera) {
+ close();
+ }
+ ::gp_camera_new(&m_priv->camera);
+
+ CameraAbilities abilities;
+ auto al = fwk::GpDeviceList::obj().get_abilities_list();
+ int model_index = ::gp_abilities_list_lookup_model(al, m_device->get_model().c_str());
+ ::gp_abilities_list_get_abilities(al, model_index, &abilities);
+ ::gp_camera_set_abilities(m_priv->camera, abilities);
+ GPPortInfo info;
+ auto info_list = ::fwk::GpDeviceList::obj().get_port_info_list();
+ DBG_OUT("looking up port %s", m_device->get_path().c_str());
+ int port_index = ::gp_port_info_list_lookup_path(info_list, m_device->get_path().c_str());
+ DBG_OUT("port index = %d", port_index);
+ if (port_index >= 0) {
+ ::gp_port_info_list_get_info(info_list, port_index, &info);
+ ::gp_camera_set_port_info(m_priv->camera, info);
+ int result = ::gp_camera_init(m_priv->camera, m_priv->context);
+ DBG_OUT("camera init returned %d", result);
+ switch (result) {
+ case GP_OK:
+ DBG_OUT("camera open");
+ success = true;
+ break;
+ case GP_ERROR_CANCEL:
+ break;
+ default:
+ close();
+ }
+ }
+
+ return success;
+}
+
+bool GpCamera::close()
+{
+ ::gp_camera_unref(m_priv->camera);
+ m_priv->camera = nullptr;
+ return true;
+}
+
+void GpCamera::process_folders(const std::vector<std::string>& folders,
+ std::list<std::pair<std::string, std::string>>& files) const
+{
+ for (auto folder : folders) {
+ CameraList *flist;
+ ::gp_list_new(&flist);
+ int result = ::gp_camera_folder_list_files(m_priv->camera, folder.c_str(), flist,
+ m_priv->context);
+ DBG_OUT("listed folder %d", result);
+ if (result == GP_OK) {
+ int count = ::gp_list_count(flist);
+ DBG_OUT("processing folder %s, count %d", folder.c_str(), count);
+ for (int i = 0; i < count; i++) {
+ const char *name = nullptr;
+ ::gp_list_get_name(flist, i, &name);
+ files.push_back(std::make_pair(folder, name));
+ }
+ }
+ gp_list_unref(flist);
+ }
+}
+
+std::list<std::pair<std::string, std::string>> GpCamera::list_content() const
+{
+ std::list<std::pair<std::string, std::string>> files;
+
+ DBG_OUT("list content");
+ CameraList *list = nullptr;
+
+ // XXX fixme this should not be hardcoded.
+ std::string root_folder = "/store_00010001/DCIM";
+ ::gp_list_new(&list);
+ int result = gp_camera_folder_list_folders(m_priv->camera, root_folder.c_str(), list,
+ m_priv->context);
+
+ DBG_OUT("initial folder list %d", result);
+ if (result == GP_OK) {
+ std::vector<std::string> folders;
+ int count = gp_list_count(list);
+ DBG_OUT("list count %d", count);
+
+ for (int i = 0; i < count; i++) {
+ const char* name = nullptr;
+ ::gp_list_get_name(list, i, &name);
+ DBG_OUT("found folder %s", name);
+ folders.push_back(root_folder + "/" + name);
+ }
+
+ process_folders(folders, files);
+ }
+ ::gp_list_unref(list);
+ return files;
+}
+
+fwk::Thumbnail GpCamera::get_preview(const std::string& path) const
+{
+ fwk::Thumbnail thumbnail;
+ CameraFile* file;
+ std::string folder = fwk::path_dirname(path);
+ std::string name = fwk::path_basename(path);
+
+ ::gp_file_new(&file);
+ int result = ::gp_camera_file_get (m_priv->camera, folder.c_str(), name.c_str(),
+ GP_FILE_TYPE_PREVIEW, file,
+ m_priv->context);
+ DBG_OUT("file_get %s %d", path.c_str(), result);
+ if (result >= 0) {
+ const char *fd;
+ unsigned long fs;
+ ::gp_file_get_data_and_size(file, &fd, &fs);
+
+ Glib::RefPtr<Gdk::PixbufLoader> loader = Gdk::PixbufLoader::create();
+ loader->write(reinterpret_cast<const guint8*>(fd), fs);
+ loader->close();
+ thumbnail = fwk::Thumbnail(loader->get_pixbuf());
+ }
+ ::gp_file_unref(file);
+ return thumbnail;
+}
}
diff --git a/src/fwk/utils/gphoto.hpp b/src/fwk/utils/gphoto.hpp
index 8a069d1..95f694f 100644
--- a/src/fwk/utils/gphoto.hpp
+++ b/src/fwk/utils/gphoto.hpp
@@ -1,3 +1,4 @@
+/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode:nil; -*- */
/*
* niepce - fwk/utils/gphoto.hpp
*
@@ -17,79 +18,98 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-#ifndef __FWK_GPHOTO_HPP_
-#define __FWK_GPHOTO_HPP_
+#pragma once
#include <list>
#include <string>
#include <memory>
-extern "C" {
#include <gphoto2-port-info-list.h>
#include <gphoto2-abilities-list.h>
-}
-#include "fwk/base/util.hpp"
+#include "fwk/base/option.hpp"
#include "fwk/base/singleton.hpp"
+#include "fwk/base/util.hpp"
namespace fwk {
+class Thumbnail;
+
+/** Describe a gphoto device: model + port (path)
+ */
class GpDevice
{
public:
- NON_COPYABLE(GpDevice);
-
- typedef std::shared_ptr<GpDevice> Ptr;
-
- GpDevice(const std::string & model, const std::string & path);
-
- const std::string & get_model() const
- {
- return m_model;
- }
- const std::string & get_path() const
- {
- return m_path;
- }
+ NON_COPYABLE(GpDevice);
+
+ GpDevice(const std::string& model, const std::string& path);
+
+ const std::string& get_model() const
+ {
+ return m_model;
+ }
+ const std::string& get_path() const
+ {
+ return m_path;
+ }
private:
- std::string m_model;
- std::string m_path;
+ std::string m_model;
+ std::string m_path;
};
+typedef std::shared_ptr<GpDevice> GpDevicePtr;
-
+/** The device list from gphoto.
+ */
class GpDeviceList
- : public fwk::Singleton<GpDeviceList>
- , public std::list<GpDevice::Ptr>
+ : public fwk::Singleton<GpDeviceList>
+ , public std::list<GpDevicePtr>
{
public:
- ~GpDeviceList();
-
- void reload();
- void detect();
+ ~GpDeviceList();
+
+ void reload();
+ void detect();
+ ::CameraAbilitiesList* get_abilities_list() const
+ { return m_abilities; }
+ ::GPPortInfoList* get_port_info_list() const
+ { return m_ports; }
+ fwk::Option<GpDevicePtr> get_device(const std::string& device);
protected:
- friend class fwk::Singleton<GpDeviceList>;
- GpDeviceList();
+ friend class fwk::Singleton<GpDeviceList>;
+ GpDeviceList();
private:
- void _gp_cleanup();
- ::CameraAbilitiesList *m_abilities;
- ::GPPortInfoList *m_ports;
+ void gp_cleanup();
+ ::CameraAbilitiesList* m_abilities;
+ ::GPPortInfoList* m_ports;
};
-
-
+/** A gphoto camera.
+ */
class GpCamera
{
public:
- GpCamera(const GpDevice::Ptr & device);
+ NON_COPYABLE(GpCamera);
+
+ GpCamera(const GpDevicePtr& device);
+ virtual ~GpCamera();
+
+ const std::string& path() const
+ { return m_device->get_path(); }
+ bool open();
+ bool close();
+ std::list<std::pair<std::string, std::string>> list_content() const;
+ fwk::Thumbnail get_preview(const std::string& path) const;
private:
- GpDevice::Ptr m_device;
+ void process_folders(const std::vector<std::string>& folders,
+ std::list<std::pair<std::string, std::string>>& files) const;
+ class Priv;
+ GpDevicePtr m_device;
+ Priv* m_priv;
};
-}
+typedef std::unique_ptr<GpCamera> GpCameraPtr;
-
-#endif
+}
diff --git a/src/niepce/Makefile.am b/src/niepce/Makefile.am
index 0802144..196424a 100644
--- a/src/niepce/Makefile.am
+++ b/src/niepce/Makefile.am
@@ -22,6 +22,7 @@ niepce_LDADD = \
$(top_builddir)/src/ncr/libncr.a \
$(top_builddir)/src/ext/libview/libview.a \
@FRAMEWORK_LIBS@ \
+ @GPHOTO_LIBS@ \
@BABL_LIBS@ \
@GEGL_LIBS@ @OPENRAW_LIBS@
diff --git a/src/niepce/ui/Makefile.am b/src/niepce/ui/Makefile.am
index b659540..fad15e1 100644
--- a/src/niepce/ui/Makefile.am
+++ b/src/niepce/ui/Makefile.am
@@ -4,6 +4,7 @@ gladefiles = dialogs/preferences.ui \
dialogs/importdialog.ui \
dialogs/editlabels.ui \
dialogs/importers/directoryimporterui.ui \
+ dialogs/importers/cameraimporterui.ui \
$(NULL)
gladedir = @datarootdir@/niepce/glade/
@@ -13,7 +14,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/ -I$(srcdir)/.. \
-I$(top_srcdir)/src/ext \
-DGLADEDIR=\"$(gladedir)\" \
-DDATADIR=\"$(datadir)\" \
- @FRAMEWORK_CFLAGS@
+ @FRAMEWORK_CFLAGS@ @GPHOTO_CFLAGS@ \
+ $(NULL)
EXTRA_DIST = $(gladefiles)
diff --git a/src/niepce/ui/dialogs/importdialog.cpp b/src/niepce/ui/dialogs/importdialog.cpp
index a238adb..f3b2c33 100644
--- a/src/niepce/ui/dialogs/importdialog.cpp
+++ b/src/niepce/ui/dialogs/importdialog.cpp
@@ -172,9 +172,9 @@ void ImportDialog::append_files_to_import()
std::list<std::string> paths;
for(const auto & f : files_to_import) {
DBG_OUT("selected %s", f->name().c_str());
- paths.push_back(f->name());
+ paths.push_back(f->path());
Gtk::TreeIter iter = m_images_list_model->append();
- m_images_list_map.insert(std::make_pair(f->name(), iter));
+ m_images_list_map.insert(std::make_pair(f->path(), iter));
iter->set_value(m_grid_columns.filename, Glib::ustring(f->name()));
iter->set_value(m_grid_columns.file, std::move(f));
}
diff --git a/src/niepce/ui/dialogs/importers/cameraimporterui.cpp
b/src/niepce/ui/dialogs/importers/cameraimporterui.cpp
index 7b4d708..75c1f54 100644
--- a/src/niepce/ui/dialogs/importers/cameraimporterui.cpp
+++ b/src/niepce/ui/dialogs/importers/cameraimporterui.cpp
@@ -1,3 +1,4 @@
+/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode:nil; -*- */
/*
* niepce - ui/dialogs/importer/cameraimporterui.cpp
*
@@ -19,7 +20,10 @@
#include <glibmm/i18n.h>
#include <gtkmm/label.h>
+#include <gtkmm/grid.h>
+#include <gtkmm/comboboxtext.h>
+#include "fwk/base/debug.hpp"
#include "fwk/toolkit/frame.hpp"
#include "engine/importer/cameraimporter.hpp"
#include "cameraimporterui.hpp"
@@ -27,14 +31,50 @@
namespace ui {
CameraImporterUI::CameraImporterUI()
- : ImporterUI(std::make_shared<eng::CameraImporter>(), _("Camera"))
+ : ImporterUI(std::make_shared<eng::CameraImporter>(), _("Camera"))
+ , m_camera_list_combo(nullptr)
+ , m_select_camera_btn(nullptr)
{
}
Gtk::Widget* CameraImporterUI::setup_widget(const fwk::Frame::Ptr&)
{
- Gtk::Label* label = Gtk::manage(new Gtk::Label("camera! camera! camera!"));
- return label;
+ Gtk::Grid* main_widget;
+ m_builder = Gtk::Builder::create_from_file(GLADEDIR"cameraimporterui.ui",
+ "main_widget");
+ m_builder->get_widget("main_widget", main_widget);
+ m_builder->get_widget("select_camera_btn", m_select_camera_btn);
+ m_select_camera_btn->signal_clicked()
+ .connect(sigc::mem_fun(*this, &CameraImporterUI::select_camera));
+ m_builder->get_widget("camera_list_combo", m_camera_list_combo);
+
+ fwk::GpDeviceList::obj().detect();
+
+ // XXX restore the selection from the preferences.
+ int i = 0;
+ for (auto device : fwk::GpDeviceList::obj()) {
+ m_camera_list_combo->append(device->get_path(), device->get_model());
+ if (i == 0) {
+ m_camera_list_combo->set_active_id(device->get_path());
+ }
+ i++;
+ }
+ if (i == 0) {
+ m_camera_list_combo->append("", _("No camera found"));
+ m_camera_list_combo->set_active_id("");
+ m_camera_list_combo->set_sensitive(false);
+ m_select_camera_btn->set_sensitive(false);
+ }
+
+ return main_widget;
+}
+
+void CameraImporterUI::select_camera()
+{
+ std::string source = m_camera_list_combo->get_active_id();
+ if (!source.empty() && m_source_selected_cb) {
+ m_source_selected_cb(source);
+ }
}
}
diff --git a/src/niepce/ui/dialogs/importers/cameraimporterui.hpp
b/src/niepce/ui/dialogs/importers/cameraimporterui.hpp
index c72be2b..3fc8a35 100644
--- a/src/niepce/ui/dialogs/importers/cameraimporterui.hpp
+++ b/src/niepce/ui/dialogs/importers/cameraimporterui.hpp
@@ -1,3 +1,4 @@
+/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode:nil; -*- */
/*
* niepce - ui/dialogs/importer/cameraimporterui.hpp
*
@@ -24,6 +25,7 @@
namespace Gtk {
class Widget;
+class ComboBoxText;
}
namespace fwk {
@@ -33,16 +35,17 @@ class Frame;
namespace ui {
class CameraImporterUI
- : public ImporterUI
+ : public ImporterUI
{
public:
- CameraImporterUI();
-
- Gtk::Widget* setup_widget(const fwk::Frame::Ptr&) override;
+ CameraImporterUI();
+ Gtk::Widget* setup_widget(const fwk::Frame::Ptr&) override;
+ void select_camera();
private:
- std::string select_source();
- void do_select_directories();
+
+ Gtk::ComboBoxText* m_camera_list_combo;
+ Gtk::Button* m_select_camera_btn;
};
}
diff --git a/src/niepce/ui/dialogs/importers/cameraimporterui.ui
b/src/niepce/ui/dialogs/importers/cameraimporterui.ui
new file mode 100644
index 0000000..8144192
--- /dev/null
+++ b/src/niepce/ui/dialogs/importers/cameraimporterui.ui
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkOffscreenWindow">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkGrid" id="main_widget">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkComboBoxText" id="camera_list_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Available cameras:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="select_camera_btn">
+ <property name="label" translatable="yes">Select</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/src/niepce/ui/dialogs/importers/importerui.cpp b/src/niepce/ui/dialogs/importers/importerui.cpp
index ce146d8..ce7df85 100644
--- a/src/niepce/ui/dialogs/importers/importerui.cpp
+++ b/src/niepce/ui/dialogs/importers/importerui.cpp
@@ -1,3 +1,22 @@
+/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode:nil; -*- */
+/*
+ * niepce - ui/dialogs/importer/importerui.cpp
+ *
+ * Copyright (C) 2017 Hubert Figuière
+ *
+ * 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 "fwk/toolkit/frame.hpp"
@@ -8,25 +27,25 @@ namespace ui {
ImporterUI::ImporterUI(std::shared_ptr<eng::IImporter>&& importer,
const std::string& name)
- : m_importer(importer)
- , m_name(name)
+ : m_importer(importer)
+ , m_name(name)
{
}
std::shared_ptr<eng::IImporter> ImporterUI::get_importer()
{
- return m_importer;
+ return m_importer;
}
const std::string& ImporterUI::id() const
{
- return m_importer->id();
+ return m_importer->id();
}
const std::string& ImporterUI::name() const
{
- return m_name;
+ return m_name;
}
diff --git a/src/niepce/ui/dialogs/importers/importerui.hpp b/src/niepce/ui/dialogs/importers/importerui.hpp
index 5016673..8925b5f 100644
--- a/src/niepce/ui/dialogs/importers/importerui.hpp
+++ b/src/niepce/ui/dialogs/importers/importerui.hpp
@@ -1,3 +1,4 @@
+/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode:nil; -*- */
/*
* niepce - ui/dialogs/importer/importerui.hpp
*
@@ -28,25 +29,26 @@ class Frame;
namespace ui {
class ImporterUI
- : public IImporterUI
+ : public IImporterUI
+ , public sigc::trackable
{
public:
- ImporterUI(std::shared_ptr<eng::IImporter>&& importer,
- const std::string& name);
+ ImporterUI(std::shared_ptr<eng::IImporter>&& importer,
+ const std::string& name);
- std::shared_ptr<eng::IImporter> get_importer() override;
+ std::shared_ptr<eng::IImporter> get_importer() override;
- const std::string& name() const override;
- const std::string& id() const override;
+ const std::string& name() const override;
+ const std::string& id() const override;
- void set_source_selected_callback(const SourceSelected&) override;
+ void set_source_selected_callback(const SourceSelected&) override;
protected:
- std::shared_ptr<eng::IImporter> m_importer;
- std::string m_name;
- std::weak_ptr<fwk::Frame> m_frame;
- Glib::RefPtr<Gtk::Builder> m_builder;
- SourceSelected m_source_selected_cb;
+ std::shared_ptr<eng::IImporter> m_importer;
+ std::string m_name;
+ std::weak_ptr<fwk::Frame> m_frame;
+ Glib::RefPtr<Gtk::Builder> m_builder;
+ SourceSelected m_source_selected_cb;
};
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]