File indexing completed on 2024-04-21 16:32:05

0001 /* This file is part of Kairo Timer
0002 
0003    SPDX-FileCopyrightText: 2016 (c) Kevin Ottens <ervin@kde.org>
0004 
0005    SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 
0007 */
0008 
0009 #include "circuitlistmodel.h"
0010 
0011 #include <QDebug>
0012 #include <QFileSystemWatcher>
0013 #include <QStandardPaths>
0014 
0015 #include <memory>
0016 
0017 #include "circuitreader.h"
0018 
0019 #ifdef Q_OS_ANDROID
0020 #include <QStorageInfo>
0021 #endif
0022 
0023 CircuitListModel::CircuitListModel(QObject *parent)
0024     : QAbstractListModel{parent},
0025       m_watcher{new QFileSystemWatcher{this}}
0026 {
0027     auto dir = storageDir();
0028     if (!dir.exists())
0029         dir.mkpath(".");
0030 
0031     connect(m_watcher, &QFileSystemWatcher::directoryChanged,
0032             this, &CircuitListModel::onDirectoryContentChanged);
0033     connect(m_watcher, &QFileSystemWatcher::fileChanged,
0034             this, &CircuitListModel::onDirectoryContentChanged);
0035     m_watcher->addPath(dir.path());
0036 
0037     onDirectoryContentChanged();
0038 }
0039 
0040 QHash<int, QByteArray> CircuitListModel::roleNames() const
0041 {
0042     auto roles = QAbstractListModel::roleNames();
0043     roles.insert(FilePathRole, "filePath");
0044     return roles;
0045 }
0046 
0047 int CircuitListModel::rowCount(const QModelIndex &parent) const
0048 {
0049     if (!parent.isValid())
0050         return m_circuits.size();
0051     else
0052         return 0;
0053 }
0054 
0055 QVariant CircuitListModel::data(const QModelIndex &index, int role) const
0056 {
0057     if (index.parent().isValid()
0058      || index.row() < 0
0059      || index.row() >= rowCount()
0060      || index.column() != 0) {
0061         return {};
0062     }
0063 
0064     auto circuitFile = m_circuits.at(index.row());
0065 
0066     switch (role) {
0067     case Qt::DisplayRole:
0068         return circuitFile.name;
0069     case FilePathRole:
0070         return circuitFile.filePath;
0071     default:
0072         return {};
0073     }
0074 }
0075 
0076 CircuitModel CircuitListModel::loadCircuit(int index)
0077 {
0078     if (index < 0 || index >= m_circuits.size()) {
0079         qWarning() << "Wrong index passed to loadCircuit";
0080         return {};
0081     }
0082 
0083     const auto path = m_circuits.at(index).filePath;
0084     auto file = std::unique_ptr<QFile>(new QFile(path));
0085     auto reader = CircuitReader{file.get()};
0086     return reader.readCircuit();
0087 }
0088 
0089 QString CircuitListModel::path() const
0090 {
0091 #ifndef Q_OS_ANDROID
0092     return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
0093 #else
0094     auto volumes = QStorageInfo::mountedVolumes();
0095     auto paths = QStringList();
0096     paths.reserve(volumes.size());
0097     std::transform(volumes.constBegin(), volumes.constEnd(),
0098                    std::back_inserter(paths),
0099                    [] (const QStorageInfo &volume) {
0100                        return volume.rootPath();
0101                    });
0102     auto validPaths = QStringList();
0103     std::copy_if(paths.constBegin(), paths.constEnd(),
0104                  std::back_inserter(validPaths),
0105                  [] (const QString &path) {
0106                      return path.startsWith("/storage/") && !path.startsWith("/storage/emulated");
0107                  });
0108     return validPaths.first() + "/Android/Kairo";
0109 #endif
0110 }
0111 
0112 void CircuitListModel::onDirectoryContentChanged()
0113 {
0114     const auto entries = storageDir().entryInfoList({"*.kairo"}, QDir::Files|QDir::Readable);
0115     auto circuits = QVector<CircuitFile>{};
0116     std::transform(entries.constBegin(), entries.constEnd(),
0117                    std::back_inserter(circuits),
0118                    [] (const QFileInfo &entry) {
0119                        const auto path = entry.absoluteFilePath();
0120                        auto file = std::unique_ptr<QFile>(new QFile(path));
0121                        auto reader = CircuitReader{file.get()};
0122                        const auto metaData = reader.readMetaData();
0123                        return CircuitFile{path, metaData.value("name").toString()};
0124                    });
0125     std::sort(circuits.begin(), circuits.end());
0126 
0127     if (m_circuits != circuits) {
0128         beginResetModel();
0129         m_circuits = circuits;
0130         endResetModel();
0131     }
0132 }
0133 
0134 QDir CircuitListModel::storageDir()
0135 {
0136     return {path()};
0137 }
0138 
0139 bool CircuitListModel::CircuitFile::operator<(const CircuitListModel::CircuitFile &other) const
0140 {
0141     return name < other.name;
0142 }
0143 
0144 bool CircuitListModel::CircuitFile::operator==(const CircuitListModel::CircuitFile &other) const
0145 {
0146     return name == other.name
0147         && filePath == other.filePath;
0148 }