Aufgrund einer Wartung wird GitLab am 29.10. zwischen 9:00 und 10:00 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to maintenance, GitLab will be temporarily unavailable on 29.10. between 9:00 and 10:00 am.

slideshow.h 5.08 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
#ifndef SLIDESHOW_H
#define SLIDESHOW_H

#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QObject>
#include <QWindow>
#include <atomic>
#include <deque>
#include <mutex>
#include <random>
#include <set>

class SlideShow : public QObject {
    Q_OBJECT
public:
    enum ShowOrder { Random, OldestFirst, NewestFirst, NameAZ, NameZA, Last = NameZA };
    Q_ENUM(ShowOrder)
private:
    /**
     * @brief path the path to the folder, in which the images are
     */
    QString path;
    /**
     * @brief showTimeInSeconds how long a image is visible
     */
    int showTimeInSeconds;
    /**
     * @brief order the oder of the images
     */
    ShowOrder order;
    /**
     * if the image deque is locked by the thread that loads the images asnyc, you can
     * set this bool to true. If this bool is true, the async loading thread will sort
     * the image deque when the loading is finished
     */
    std::atomic_bool shouldSort;
    // the mutex to protect the image deque
    std::recursive_mutex imageMutex;
    // all loaded images, sorted if order != Random
    std::deque<QFileInfo> images;
    // all paths that were already scanned
    std::set<QString> alreadyScanned;
    // a watcher to check if new files/folders gets added into the folder <path>
    QFileSystemWatcher watcher;
    // the current displayed image (index in the images deque)
    int currentImage = -1;
    // the id of the load timer
    int loadTimer = -1;
    /**
     * @brief offsetTimer the id of the offset timer. The offset timer should wait offsetWaitTime after the loadNextImage
     * is emitted to emit emit the showNextImage signal. So the Slideshow has some time to load the image
     */
    int offsetTimer = -1;
    // if a file contains [0-9]+s, the wait time will be this custom time
    bool wasCustomShowTime = false;
    /**
     * @brief windowVisibility the window visibility of the slideshow window
     */
    QWindow::Visibility windowVisibility = QWindow::Hidden;
    // the used random number generator for <order> = Random
    std::mt19937 randomNumberGenerator;
    // the distribution to get a random number from the random number generator
    std::uniform_int_distribution<size_t> dis;
    Q_PROPERTY(int showTimeInSeconds READ getShowTimeInSeconds WRITE setShowTimeInSeconds NOTIFY showTimeInSecondsChanged)
    Q_PROPERTY(ShowOrder showOrder READ getShowOrder WRITE setShowOrder NOTIFY showOrderChanged)
    Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged)
    Q_PROPERTY(QWindow::Visibility windowVisibility MEMBER windowVisibility NOTIFY windowVisibilityChanged)
    Q_PROPERTY(bool hasImages READ hasImages NOTIFY hasImagesChanged)
    // the time that should be waitet by the offset timer
    static constexpr int offsetWaitTime = 100;

public:
    static SlideShow &get() {
        static SlideShow s;
        return s;
    }

public:
    SlideShow();
    void setShowTimeInSeconds(int time);
    [[nodiscard]] int getShowTimeInSeconds() const { return showTimeInSeconds; }
    void setShowOrder(ShowOrder showOrder);
    [[nodiscard]] ShowOrder getShowOrder() const { return order; }
    void setPath(const QString &path);
    [[nodiscard]] QString getPath() const { return path; }
    [[nodiscard]] bool hasImages() const { return images.size(); }
    /**
     * @brief reportInvalidImage you can report the current image as invalid.
     * The image gets removed from a images deque and a new image gets selected
     */
    Q_INVOKABLE void reportInvalidImage();

protected:
    /**
     * @brief scanForNewFiles scans in the path for new files and updates the <watcher>. The scanning is done in a seperate thread.
     */
    void scanForNewFiles();
    /**
     * @brief sort Sorts the images deque. If the imageMutex can not be locked, shouldSort is set to true.
     */
    void sort();
    void timerEvent(QTimerEvent *event) override;
    /**
     * @brief loadNextImage determins the next image and emit the signal loadNextImage, if the imageMutex can be locked
     */
    void loadNextImage();

private:
    /**
     * @brief checkCustomShowTime checks if the path contains a custom show time ([0-9]+s) and manages the load timers
     * @param path The path that should be checked
     */
    void checkCustomShowTime(const QString &path);
    /**
     * @brief removeImage removes a image from the images deque and from the alreadyScanned set and updates the distribution
     * @param index index in the deque, can be invalid
     */
    void removeImage(int index);
    /**
     * @brief scanDirectory scans the directory path for new files. If a new directory is found, scan it recursive, even if recursive is false
     * @param path the path of the directory that should be scanned
     * @param recursive false, if only the directory should be scanned. If true, subdirectories are also scanned.
     */
    void scanDirectory(const QString &path, bool recursive);

signals:
    void loadNextImage(QString path);
    void showNextImage();
    void showTimeInSecondsChanged();
    void showOrderChanged();
    void pathChanged();
    void windowVisibilityChanged();
    void hasImagesChanged();
};

#endif // SLIDESHOW_H