Ver Fonte

Move threading considerations into the model

Change-Id: I70f06512156fa3feee34f8a7aed27aac649c466f
Donald Carr há 9 anos atrás
pai
commit
9c5c0d1f82
4 ficheiros alterados com 100 adições e 73 exclusões
  1. 1 7
      qml/main.qml
  2. 2 27
      src/main.cpp
  3. 95 29
      src/picturemodel.cpp
  4. 2 10
      src/picturemodel.h

+ 1 - 7
qml/main.qml

@@ -61,12 +61,8 @@ Window {
     }
 
     Rectangle {
-        function checkModel() {
-            visible = (imageModel.rowCount() === 0)
-        }
-
         z: 1
-        visible: imageModel.rowCount() === 0
+        visible: imageModel.rowCount > 0
         color: "red"
 
         width: childrenRect.width
@@ -77,8 +73,6 @@ Window {
             font.pointSize: 40
             text: "No images found/provided"
         }
-
-        Component.onCompleted: modelRelay.countChanged.connect(checkModel);
     }
 
     Rectangle {

+ 2 - 27
src/main.cpp

@@ -3,7 +3,6 @@
 #include <QGuiApplication>
 #include <QQmlApplicationEngine>
 #include <QQmlContext>
-#include <QThread>
 #include <QSettings>
 #include <QSurfaceFormat>
 #include <QTimer>
@@ -14,13 +13,6 @@
 #include <QTextStream>
 
 #include <QDebug>
-#include <QAbstractItemModel>
-
-class ModelRelay : public QObject {
-    Q_OBJECT
-signals:
-    void countChanged();
-};
 
 class FileReader : public QObject {
     Q_OBJECT
@@ -61,29 +53,12 @@ int main(int argc, char *argv[])
     }
 
     QQmlApplicationEngine engine;
-    QThread scanningThread;
-    PictureModel *model = new PictureModel();
-    QString artPath = settings.value("artPath","/blackhole/media/art").toString();
-    QStringList extensions = settings.value("extensions", QStringList() << "jpg" << "png").toStringList();
-    settings.setValue("artPath", artPath);
-    settings.setValue("extensions", extensions);
-
-    model->setSupportedExtensions(extensions);
-    model->moveToThread(&scanningThread);
-    scanningThread.start();
-    QMetaObject::invokeMethod(model, "setModelRoot", Qt::QueuedConnection, Q_ARG(QString,artPath));
-
-    ModelRelay modelRelay;
-    QObject::connect(model, &PictureModel::countChanged, &modelRelay, &ModelRelay::countChanged, Qt::QueuedConnection);
-
-    engine.rootContext()->setContextProperty("imageModel", model);
-    engine.rootContext()->setContextProperty("modelRelay", &modelRelay);
+    PictureModel model;
 
+    engine.rootContext()->setContextProperty("imageModel", &model);
     engine.rootContext()->setContextProperty("fileReader", new FileReader(&app));
     engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
 
-    QObject::connect(&app, &QGuiApplication::lastWindowClosed, &scanningThread, &QThread::quit);
-
     return app.exec();
 }
 

+ 95 - 29
src/picturemodel.cpp

@@ -3,6 +3,8 @@
 #include <QDir>
 #include <QDebug>
 #include <QCoreApplication>
+#include <QSettings>
+#include <QThread>
 
 struct FSNode {
   FSNode(const QString& rname, const FSNode *pparent = nullptr)
@@ -27,20 +29,44 @@ QString FSNode::qualifyNode(const FSNode *node) {
     return qualifiedPath;
 }
 
+class FSNodeTree : public QObject
+{
+    Q_OBJECT
+public:
+    FSNodeTree(PictureModel *p);
+
+    void addModelNode(const FSNode* parentNode);
+    void setSupportedExtensions(const QStringList extensions) { this->extensions = extensions; }
+    void setModelRoot(const QString& rootDir) { this->rootDir = rootDir; }
+
+    int fileCount() const { return files.length(); }
+    QUrl randomFileUrl() const;
+public slots:
+    void populate();
+signals:
+    void countChanged();
+private:
+    QList<const FSNode*> files;
+    QStringList extensions;
+    QString rootDir;
+};
 
-PictureModel::PictureModel(QObject *parent)
-    : QAbstractListModel(parent)
-{ /**/ }
-
-PictureModel::~PictureModel()
+FSNodeTree::FSNodeTree(PictureModel *p)
+    : QObject(nullptr)
 {
-    // TODO: Destroy model
+    connect(this, SIGNAL(countChanged()), p, SIGNAL(countChanged()));
 }
 
-void PictureModel::addModelNode(const FSNode* parentNode)
-{
-    QCoreApplication::processEvents();
 
+QUrl FSNodeTree::randomFileUrl() const {
+    if (files.size() <= 0)
+        return QString("qrc:///qt_logo_green_rgb.png");
+
+    return QUrl::fromLocalFile(FSNode::qualifyNode(files.at(qrand()%files.size())));
+}
+
+void FSNodeTree::addModelNode(const FSNode* parentNode)
+{
     // TODO: Check for symlink recursion
     QDir parentDir(FSNode::qualifyNode(parentNode));
 
@@ -61,47 +87,85 @@ void PictureModel::addModelNode(const FSNode* parentNode)
     }
 }
 
-void PictureModel::setModelRoot(const QString &root)
+void FSNodeTree::populate()
 {
-    QDir currentDir(root);
+    QDir currentDir(rootDir);
     if (!currentDir.exists()) {
         qDebug() << "Being told to watch a non existent directory";
     }
-    addModelNode(new FSNode(root));
+    if (extensions.empty()) {
+        qDebug() << "No supported extensions provided, defaulting to jpg and png";
+        extensions << "jpg" << "png";
+    }
+    addModelNode(new FSNode(rootDir));
 }
 
-void PictureModel::setSupportedExtensions(QStringList extensions) {
-    this->extensions = extensions;
+class PictureModel::PictureModelPrivate {
+public:
+    PictureModelPrivate(PictureModel* p);
+    ~PictureModelPrivate();
+
+    FSNodeTree *fsTree;
+private:
+    QThread scanningThread;
+};
+
+PictureModel::PictureModelPrivate::PictureModelPrivate(PictureModel* p)
+{
+    QSettings settings;
+    QString artPath = settings.value("artPath","/blackhole/media/art").toString();
+    QStringList extensions = settings.value("extensions", QStringList() << "jpg" << "png").toStringList();
+
+    settings.setValue("artPath", artPath);
+    settings.setValue("extensions", extensions);
+
+    fsTree = new FSNodeTree(p);
+
+    fsTree->setSupportedExtensions(extensions);
+    fsTree->setModelRoot(artPath);
+
+    fsTree->moveToThread(&scanningThread);
+    scanningThread.start();
+
+    QMetaObject::invokeMethod(fsTree, "populate", Qt::QueuedConnection);
+};
+
+PictureModel::PictureModelPrivate::~PictureModelPrivate()
+{
+    scanningThread.quit();
+    scanningThread.wait(5000);
+
+    delete fsTree;
+    fsTree = nullptr;
+};
+
+PictureModel::PictureModel(QObject *parent)
+    : QAbstractListModel(parent),
+      d(new PictureModelPrivate(this)) { /**/ }
+
+PictureModel::~PictureModel()
+{
+    delete d;
+    d = nullptr;
 }
 
 int PictureModel::rowCount(const QModelIndex &parent) const
 {
     Q_UNUSED(parent)
-    return files.length();
+    return d->fsTree->fileCount();
 }
 
 QUrl PictureModel::randomPicture() const
-{
-    if (files.size() <= 0)
-        return QString("qrc:///qt_logo_green_rgb.png");
-
-    return QUrl::fromLocalFile(FSNode::qualifyNode(files.at(qrand()%files.size())));
+{   return d->fsTree->randomFileUrl();
 }
 
 QVariant PictureModel::data(const QModelIndex &index, int role) const
 {
     Q_UNUSED(role)
-    if (index.row() < 0 || index.row() >= files.length())
+    if (index.row() < 0 || index.row() >= d->fsTree->fileCount())
         return QVariant();
 
-    const FSNode *node = files.at(index.row());
-
-    return FSNode::qualifyNode(node);
-}
-
-void PictureModel::addSupportedExtension(const QString &extension)
-{
-    extensions << extension;
+    return d->fsTree->randomFileUrl();
 }
 
 QHash<int, QByteArray> PictureModel::roleNames() const
@@ -110,3 +174,5 @@ QHash<int, QByteArray> PictureModel::roleNames() const
     roles[PathRole] = "path";
     return roles;
 }
+
+#include "picturemodel.moc"

+ 2 - 10
src/picturemodel.h

@@ -4,8 +4,6 @@
 #include <QAbstractListModel>
 #include <QUrl>
 
-class FSNode;
-
 class PictureModel : public QAbstractListModel
 {
     Q_OBJECT
@@ -23,12 +21,6 @@ public:
     Q_INVOKABLE QUrl randomPicture() const;
     QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
 
-    Q_INVOKABLE void setModelRoot(const QString &root);
-
-    void setSupportedExtensions(QStringList extensions);
-    void addSupportedExtension(const QString &extension);
-    void addModelNode(const FSNode *parent);
-
 signals:
     void countChanged();
 
@@ -36,8 +28,8 @@ protected:
     QHash<int, QByteArray> roleNames() const;
 
 private:
-    QList<const FSNode*> files;
-    QStringList extensions;
+    class PictureModelPrivate;
+    PictureModelPrivate *d;
 };
 
 #endif // PICTUREMODEL_H