From db09dc43f24bbc87e2e05e1a790e7bc4abf2087c Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 13 Feb 2020 21:52:17 +0100 Subject: [PATCH 1/4] split switcher and traverser to prepare for shuffle mode --- src/imageselector.cpp | 50 ++++++++++--------------- src/imageselector.h | 22 ++++++++--- src/imageswitcher.cpp | 6 +-- src/imageswitcher.h | 5 ++- src/main.cpp | 85 +++++++++++++++++++++++++------------------ src/pathtraverser.cpp | 55 ++++++++++++++++++++++++++++ src/pathtraverser.h | 41 +++++++++++++++++++++ src/slide.pro | 2 + 8 files changed, 189 insertions(+), 77 deletions(-) create mode 100644 src/pathtraverser.cpp create mode 100644 src/pathtraverser.h diff --git a/src/imageselector.cpp b/src/imageselector.cpp index 5f9261b..c9e1b9d 100644 --- a/src/imageselector.cpp +++ b/src/imageselector.cpp @@ -1,4 +1,5 @@ #include "imageselector.h" +#include "pathtraverser.h" #include "mainwindow.h" #include #include @@ -8,31 +9,30 @@ #include /* srand, rand */ #include /* time */ -ImageSelector::ImageSelector(std::string path, bool recursive): - path(path), - recursive(recursive) + +ImageSelector::ImageSelector(std::unique_ptr& pathTraverser): + pathTraverser(pathTraverser) +{ +} + +ImageSelector::~ImageSelector(){} + +DefaultImageSelector::DefaultImageSelector(std::unique_ptr& pathTraverser): + ImageSelector(pathTraverser) { srand (time(NULL)); } -std::string ImageSelector::getNextImage() const +DefaultImageSelector::~DefaultImageSelector(){} + +std::string DefaultImageSelector::getNextImage() const { - QDir directory(path.c_str()); std:: string filename; try { - if (recursive) - { - QStringList images = listImagesRecursive(); - unsigned int selectedImage = selectRandom(images); - filename = images.at(selectedImage).toStdString(); - } - else - { - QStringList images = directory.entryList(QStringList() << "*.jpg" << "*.JPG", QDir::Files); - unsigned int selectedImage = selectRandom(images); - filename = directory.filePath(images.at(selectedImage)).toStdString(); - } + QStringList images = pathTraverser->getImages(); + unsigned int selectedImage = selectRandom(images); + filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString()); } catch(const std::string& err) { @@ -42,24 +42,12 @@ std::string ImageSelector::getNextImage() const return filename; } -unsigned int ImageSelector::selectRandom(const QStringList& images) const +unsigned int DefaultImageSelector::selectRandom(const QStringList& images) const { std::cout << "images: " << images.size() << std::endl; if (images.size() == 0) { - throw std::string("No jpg images found in folder " + path); + throw std::string("No jpg images found in given folder"); } return rand() % images.size(); } - - -QStringList ImageSelector::listImagesRecursive() const -{ - QDirIterator it(QString(path.c_str()), QStringList() << "*.jpg" << "*.JPG", QDir::Files, QDirIterator::Subdirectories); - QStringList files; - while (it.hasNext()) - { - files.append(it.next()); - } - return files; -} diff --git a/src/imageselector.h b/src/imageselector.h index 2a5b2c7..beea8c9 100644 --- a/src/imageselector.h +++ b/src/imageselector.h @@ -2,20 +2,32 @@ #define IMAGESELECTOR_H #include +#include #include class MainWindow; +class PathTraverser; + class ImageSelector { public: - ImageSelector(std::string path, bool recursive); - std::string getNextImage() const; + ImageSelector(std::unique_ptr& pathTraverser); + virtual ~ImageSelector(); + virtual std::string getNextImage() const = 0; + +protected: + std::unique_ptr& pathTraverser; +}; + +class DefaultImageSelector : public ImageSelector +{ +public: + DefaultImageSelector(std::unique_ptr& pathTraverser); + virtual ~DefaultImageSelector(); + virtual std::string getNextImage() const; private: - QStringList listImagesRecursive() const; unsigned int selectRandom(const QStringList& images) const; - std::string path; - bool recursive; }; #endif // IMAGESELECTOR_H diff --git a/src/imageswitcher.cpp b/src/imageswitcher.cpp index ea9753a..e64979d 100644 --- a/src/imageswitcher.cpp +++ b/src/imageswitcher.cpp @@ -4,12 +4,12 @@ #include #include #include -#include #include +#include #include /* srand, rand */ #include /* time */ -ImageSwitcher::ImageSwitcher(MainWindow& w, unsigned int timeout, const ImageSelector& selector): +ImageSwitcher::ImageSwitcher(MainWindow& w, unsigned int timeout, std::unique_ptr& selector): QObject::QObject(), window(w), timeout(timeout), @@ -20,7 +20,7 @@ ImageSwitcher::ImageSwitcher(MainWindow& w, unsigned int timeout, const ImageSel void ImageSwitcher::updateImage() { - std::string filename(selector.getNextImage()); + std::string filename(selector->getNextImage()); if (filename == "") { window.warn("No image found."); diff --git a/src/imageswitcher.h b/src/imageswitcher.h index 8c6b027..d49d3ad 100644 --- a/src/imageswitcher.h +++ b/src/imageswitcher.h @@ -4,6 +4,7 @@ #include #include #include +#include class MainWindow; class ImageSelector; @@ -11,7 +12,7 @@ class ImageSwitcher : public QObject { Q_OBJECT public: - ImageSwitcher(MainWindow& w, unsigned int timeout, const ImageSelector& selector); + ImageSwitcher(MainWindow& w, unsigned int timeout, std::unique_ptr& selector); void start(); public slots: @@ -19,7 +20,7 @@ public slots: private: MainWindow& window; unsigned int timeout; - const ImageSelector& selector; + std::unique_ptr& selector; QTimer timer; }; diff --git a/src/main.cpp b/src/main.cpp index a922eab..8757bc4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include "mainwindow.h" #include "imageselector.h" #include "imageswitcher.h" +#include "pathtraverser.h" #include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include void usage(std::string programName) { std::cerr << "Usage: " << programName << " [-t rotation_seconds] [-o background_opacity(0..255)] [-b blur_radius] -p image_folder -r" << std::endl; @@ -16,46 +18,57 @@ void usage(std::string programName) { int main(int argc, char *argv[]) { - unsigned int rotationSeconds = 30; - std::string path = ""; + unsigned int rotationSeconds = 30; + std::string path = ""; - QApplication a(argc, argv); + QApplication a(argc, argv); - MainWindow w; - int opt; - bool recursive = false; - while ((opt = getopt(argc, argv, "b:p:t:o:r")) != -1) { - switch (opt) { - case 'p': - path = optarg; - break; - case 't': - rotationSeconds = atoi(optarg); - break; - case 'b': - w.setBlurRadius(atoi(optarg)); - break; - case 'o': - w.setBackgroundOpacity(atoi(optarg)); - break; - case 'r': - recursive = true; - break; - default: /* '?' */ - usage(argv[0]); - return 1; - } - } - - if (path.empty()) { - std::cout << "Error: Path expected." << std::endl; + MainWindow w; + int opt; + bool recursive = false; + while ((opt = getopt(argc, argv, "b:p:t:o:r")) != -1) { + switch (opt) { + case 'p': + path = optarg; + break; + case 't': + rotationSeconds = atoi(optarg); + break; + case 'b': + w.setBlurRadius(atoi(optarg)); + break; + case 'o': + w.setBackgroundOpacity(atoi(optarg)); + break; + case 'r': + recursive = true; + break; + default: /* '?' */ usage(argv[0]); return 1; } - w.show(); + } - ImageSelector selector(path, recursive); - ImageSwitcher switcher(w, rotationSeconds * 1000, selector); - switcher.start(); - return a.exec(); + if (path.empty()) + { + std::cout << "Error: Path expected." << std::endl; + usage(argv[0]); + return 1; + } + + std::unique_ptr pathTraverser; + if (recursive) + { + pathTraverser = std::unique_ptr(new RecursivePathTraverser(path)); + } else { + pathTraverser = std::unique_ptr(new DefaultPathTraverser(path)); + } + + std::unique_ptr selector = std::unique_ptr(new DefaultImageSelector(pathTraverser)); + + w.show(); + + ImageSwitcher switcher(w, rotationSeconds * 1000, selector); + switcher.start(); + return a.exec(); } diff --git a/src/pathtraverser.cpp b/src/pathtraverser.cpp new file mode 100644 index 0000000..5686e25 --- /dev/null +++ b/src/pathtraverser.cpp @@ -0,0 +1,55 @@ +#include "pathtraverser.h" +#include "mainwindow.h" +#include +#include +#include +#include +#include +#include /* srand, rand */ + +PathTraverser::PathTraverser(const std::string path): + path(path) +{} + +PathTraverser::~PathTraverser() {} + +RecursivePathTraverser::RecursivePathTraverser(const std::string path): + PathTraverser(path) +{} + +RecursivePathTraverser::~RecursivePathTraverser() {} + + +QStringList RecursivePathTraverser::getImages() const +{ + QDirIterator it(QString(path.c_str()), QStringList() << "*.jpg" << "*.JPG", QDir::Files, QDirIterator::Subdirectories); + QStringList files; + while (it.hasNext()) + { + files.append(it.next()); + } + return files; +} + +const std::string RecursivePathTraverser::getImagePath(const std::string image) const +{ + return image; +} + +DefaultPathTraverser::DefaultPathTraverser(const std::string path): + PathTraverser(path), + directory(path.c_str()) +{} + +DefaultPathTraverser::~DefaultPathTraverser() {} + + +QStringList DefaultPathTraverser::getImages() const +{ + return directory.entryList(QStringList() << "*.jpg" << "*.JPG", QDir::Files); +} + +const std::string DefaultPathTraverser::getImagePath(const std::string image) const +{ + return directory.filePath(QString(image.c_str())).toStdString(); +} diff --git a/src/pathtraverser.h b/src/pathtraverser.h new file mode 100644 index 0000000..d400ce8 --- /dev/null +++ b/src/pathtraverser.h @@ -0,0 +1,41 @@ +#ifndef PATHTRAVERSER_H +#define PATHTRAVERSER_H + +#include +#include +#include + +class MainWindow; +class PathTraverser +{ + public: + PathTraverser(const std::string path); + virtual ~PathTraverser(); + virtual QStringList getImages() const = 0; + virtual const std::string getImagePath(const std::string image) const = 0; + + protected: + const std::string path; +}; + +class RecursivePathTraverser : public PathTraverser +{ + public: + RecursivePathTraverser(const std::string path); + virtual ~RecursivePathTraverser(); + QStringList getImages() const; + virtual const std::string getImagePath(const std::string image) const; +}; + +class DefaultPathTraverser : public PathTraverser +{ + public: + DefaultPathTraverser(const std::string path); + virtual ~DefaultPathTraverser(); + QStringList getImages() const; + virtual const std::string getImagePath(const std::string image) const; + private: + QDir directory; +}; + +#endif // PATHTRAVERSER_H diff --git a/src/slide.pro b/src/slide.pro index 906ba94..8597bdf 100644 --- a/src/slide.pro +++ b/src/slide.pro @@ -27,11 +27,13 @@ SOURCES += \ main.cpp \ mainwindow.cpp \ imageswitcher.cpp \ + pathtraverser.cpp \ imageselector.cpp HEADERS += \ mainwindow.h \ imageselector.h \ + pathtraverser.h \ imageswitcher.h FORMS += \ From d21677399d3b5634943312b2715486632a467530 Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 13 Feb 2020 23:16:58 +0100 Subject: [PATCH 2/4] Enable shuffle mode Co-authored-by: data-dude92 <60513060+data-dude92@users.noreply.github.com> --- src/imageselector.cpp | 88 ++++++++++++++++++++++++++++++------------- src/imageselector.h | 22 ++++++++--- src/main.cpp | 21 +++++++++-- 3 files changed, 96 insertions(+), 35 deletions(-) diff --git a/src/imageselector.cpp b/src/imageselector.cpp index c9e1b9d..b3dc3c0 100644 --- a/src/imageselector.cpp +++ b/src/imageselector.cpp @@ -8,46 +8,80 @@ #include #include /* srand, rand */ #include /* time */ - +#include // std::shuffle +#include // std::default_random_engine ImageSelector::ImageSelector(std::unique_ptr& pathTraverser): - pathTraverser(pathTraverser) + pathTraverser(pathTraverser) { } ImageSelector::~ImageSelector(){} -DefaultImageSelector::DefaultImageSelector(std::unique_ptr& pathTraverser): - ImageSelector(pathTraverser) +RandomImageSelector::RandomImageSelector(std::unique_ptr& pathTraverser): + ImageSelector(pathTraverser) { - srand (time(NULL)); + srand (time(NULL)); } -DefaultImageSelector::~DefaultImageSelector(){} +RandomImageSelector::~RandomImageSelector(){} -std::string DefaultImageSelector::getNextImage() const +std::string RandomImageSelector::getNextImage() { - std:: string filename; - try - { - QStringList images = pathTraverser->getImages(); - unsigned int selectedImage = selectRandom(images); - filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString()); - } - catch(const std::string& err) - { - std::cerr << "Error: " << err << std::endl; - } - std::cout << "updating image: " << filename << std::endl; - return filename; + std:: string filename; + try + { + QStringList images = pathTraverser->getImages(); + unsigned int selectedImage = selectRandom(images); + filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString()); + } + catch(const std::string& err) + { + std::cerr << "Error: " << err << std::endl; + } + std::cout << "updating image: " << filename << std::endl; + return filename; } -unsigned int DefaultImageSelector::selectRandom(const QStringList& images) const +unsigned int RandomImageSelector::selectRandom(const QStringList& images) const { - std::cout << "images: " << images.size() << std::endl; - if (images.size() == 0) - { - throw std::string("No jpg images found in given folder"); - } - return rand() % images.size(); + std::cout << "images: " << images.size() << std::endl; + if (images.size() == 0) + { + throw std::string("No jpg images found in given folder"); + } + return rand() % images.size(); +} + +ShuffleImageSelector::ShuffleImageSelector(std::unique_ptr& pathTraverser): + ImageSelector(pathTraverser), + current_image_shuffle(-1), + images() +{ + srand (time(NULL)); +} + +ShuffleImageSelector::~ShuffleImageSelector() +{ +} + +std::string ShuffleImageSelector::getNextImage() +{ + if (images.size() == 0 || current_image_shuffle == images.size()) + { + current_image_shuffle = 0; + images = pathTraverser->getImages(); + std::cout << "Shuffling " << images.size() << " images." << std::endl; + std::random_device rd; + std::mt19937 randomizer(rd()); + std::shuffle(images.begin(), images.end(), randomizer); + } + if (images.size() == 0) + { + return ""; + } + std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString()); + std::cout << "updating image: " << filename << std::endl; + current_image_shuffle = current_image_shuffle + 1; + return filename; } diff --git a/src/imageselector.h b/src/imageselector.h index beea8c9..b01d662 100644 --- a/src/imageselector.h +++ b/src/imageselector.h @@ -13,21 +13,33 @@ class ImageSelector public: ImageSelector(std::unique_ptr& pathTraverser); virtual ~ImageSelector(); - virtual std::string getNextImage() const = 0; + virtual std::string getNextImage() = 0; protected: std::unique_ptr& pathTraverser; }; -class DefaultImageSelector : public ImageSelector +class RandomImageSelector : public ImageSelector { public: - DefaultImageSelector(std::unique_ptr& pathTraverser); - virtual ~DefaultImageSelector(); - virtual std::string getNextImage() const; + RandomImageSelector(std::unique_ptr& pathTraverser); + virtual ~RandomImageSelector(); + virtual std::string getNextImage(); private: unsigned int selectRandom(const QStringList& images) const; }; +class ShuffleImageSelector : public ImageSelector +{ +public: + ShuffleImageSelector(std::unique_ptr& pathTraverser); + virtual ~ShuffleImageSelector(); + virtual std::string getNextImage(); + +private: + int current_image_shuffle; + QStringList images; +}; + #endif // IMAGESELECTOR_H diff --git a/src/main.cpp b/src/main.cpp index 8757bc4..e7c0a7e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,7 +26,8 @@ int main(int argc, char *argv[]) MainWindow w; int opt; bool recursive = false; - while ((opt = getopt(argc, argv, "b:p:t:o:r")) != -1) { + bool shuffle = false; + while ((opt = getopt(argc, argv, "b:p:t:o:rs")) != -1) { switch (opt) { case 'p': path = optarg; @@ -43,6 +44,10 @@ int main(int argc, char *argv[]) case 'r': recursive = true; break; + case 's': + shuffle = true; + std::cout << "Shuffle mode is on." << std::endl; + break; default: /* '?' */ usage(argv[0]); return 1; @@ -60,11 +65,21 @@ int main(int argc, char *argv[]) if (recursive) { pathTraverser = std::unique_ptr(new RecursivePathTraverser(path)); - } else { + } + else + { pathTraverser = std::unique_ptr(new DefaultPathTraverser(path)); } - std::unique_ptr selector = std::unique_ptr(new DefaultImageSelector(pathTraverser)); + std::unique_ptr selector; + if (shuffle) + { + selector = std::unique_ptr(new ShuffleImageSelector(pathTraverser)); + } + else + { + selector = std::unique_ptr(new RandomImageSelector(pathTraverser)); + } w.show(); From 605c04fca3290186c96ac11b312091339d4a06a0 Mon Sep 17 00:00:00 2001 From: Manuel Dewald Date: Fri, 14 Feb 2020 23:13:34 +0100 Subject: [PATCH 3/4] add lib and include for libexif on mac --- README.md | 13 +++++++++++++ src/slide.pro | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/README.md b/README.md index e4f14b5..4e47f19 100644 --- a/README.md +++ b/README.md @@ -46,3 +46,16 @@ qmake ../src/slide.pro make sudo make install ``` + +### macOS + +Prerequisite: brew + +``` +brew install qt5 +brew install libexif +mkdir -p build +cd build +qmake ../src/slide.pro +make +``` diff --git a/src/slide.pro b/src/slide.pro index 8597bdf..7f8c9ab 100644 --- a/src/slide.pro +++ b/src/slide.pro @@ -22,6 +22,10 @@ DEFINES += QT_DEPRECATED_WARNINGS # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +mac: INCLUDEPATH += $$system(brew --prefix libexif)/include/ +mac: QMAKE_LFLAGS += -L$$system(brew --prefix libexif)/lib + + SOURCES += \ main.cpp \ From d399dfaff1c2057e2b6ec49ee42c55f12118987a Mon Sep 17 00:00:00 2001 From: Manuel Dewald Date: Fri, 14 Feb 2020 23:16:20 +0100 Subject: [PATCH 4/4] shuffle: reload files if image gets lost --- src/imageselector.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/imageselector.cpp b/src/imageselector.cpp index b3dc3c0..12f68a0 100644 --- a/src/imageselector.cpp +++ b/src/imageselector.cpp @@ -67,7 +67,7 @@ ShuffleImageSelector::~ShuffleImageSelector() std::string ShuffleImageSelector::getNextImage() { - if (images.size() == 0 || current_image_shuffle == images.size()) + if (images.size() == 0 || current_image_shuffle >= images.size()) { current_image_shuffle = 0; images = pathTraverser->getImages(); @@ -81,6 +81,12 @@ std::string ShuffleImageSelector::getNextImage() return ""; } std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString()); + if(!QFileInfo::exists(QString(filename.c_str()))) + { + std::cout << "file not found: " << filename << std::endl; + current_image_shuffle = images.size(); + return getNextImage(); + } std::cout << "updating image: " << filename << std::endl; current_image_shuffle = current_image_shuffle + 1; return filename;