diff --git a/batchprocessing.cpp b/batchprocessing.cpp index a682aec..5dfbecc 100644 --- a/batchprocessing.cpp +++ b/batchprocessing.cpp @@ -17,12 +17,12 @@ #include #endif -QStringList scanDirectories(const QStringList &paths) +QList> scanDirectories(const QStringList &paths) { - QStringList files; + QList> files; QStringList scannedDirs; - std::function scanDirectory = [&](const QString &path) + std::function scanDirectory = [&](const QString &root, const QString &path) { QFileInfo info(path); if(info.isDir() && !scannedDirs.contains(info.canonicalFilePath())) @@ -31,16 +31,16 @@ QStringList scanDirectories(const QStringList &paths) QDir dir(path); QStringList entries = dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); for(QString &entry : entries) - scanDirectory(dir.absoluteFilePath(entry)); + scanDirectory(root, dir.absoluteFilePath(entry)); } else if(info.isFile()) { - files.append(path); + files.append({path, root}); } }; for(const QString &path : paths) - scanDirectory(path); + scanDirectory(path, path); return files; } diff --git a/scriptengine.cpp b/scriptengine.cpp index 3cdba65..dc32057 100644 --- a/scriptengine.cpp +++ b/scriptengine.cpp @@ -20,7 +20,7 @@ ScriptEngine::ScriptEngine(QObject *parent) : QObject(parent) _semaphore.release(_pool->maxThreadCount()); } -void ScriptEngine::setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir) +void ScriptEngine::setParams(const QString &scriptPath, const QList> &paths, const QString &outputDir) { _scriptPath = scriptPath; _paths = paths; @@ -67,7 +67,23 @@ bool ScriptEngine::isMarked(const File *file) const return _database->isMarked(file->absoluteFilePath()); } -bool ScriptEngine::convert(File *file, QString &outpath, QString format, QVariantMap params) +void ScriptEngine::setMaxThread(int maxthread) +{ + int newval = std::max(std::min(QThread::idealThreadCount(), maxthread), 1); + int oldval = _pool->maxThreadCount(); + if(newval > oldval) + _semaphore.release(newval - oldval); + else if(newval < oldval) + _semaphore.acquire(oldval - newval); + _pool->setMaxThreadCount(newval); +} + +void ScriptEngine::sync() +{ + _pool->waitForDone(); +} + +bool ScriptEngine::convert(File *file, QString &outpath, const QString &format, const QVariantMap ¶ms, bool async) { QString path; QDir dir(_outputDir); @@ -79,9 +95,17 @@ bool ScriptEngine::convert(File *file, QString &outpath, QString format, QVarian path = dir.absoluteFilePath(outpath); info.setFile(path); - //qDebug() << info.absolutePath() + "/" + info.completeBaseName() + "." + format.toLower(); - _semaphore.acquire(); - _pool->start(new ConvertRunable(file->absoluteFilePath(), info.absolutePath() + "/" + info.completeBaseName() + "." + format.toLower(), format, params, &_semaphore)); + outpath = info.absolutePath() + "/" + info.completeBaseName() + "." + format.toLower(); + if(async) + { + _semaphore.acquire(); + _pool->start(new ConvertRunable(file->absoluteFilePath(), outpath, format, params, &_semaphore)); + } + else + { + ConvertRunable crun(file->absoluteFilePath(), outpath, format, params, nullptr); + crun.run(); + } return true; } @@ -90,11 +114,16 @@ QJSValue ScriptEngine::newObject() return _jsEngine->newObject(); } +QJSValue ScriptEngine::newArray(uint size) +{ + return _jsEngine->newArray(size); +} + void ScriptEngine::run() { QJSValue jsPaths = _jsEngine->newArray(_paths.size()); for(qsizetype i=0; i<_paths.size(); i++) - jsPaths.setProperty(i, _jsEngine->newQObject(new File(_paths[i], this))); + jsPaths.setProperty(i, _jsEngine->newQObject(new File(_paths[i].first, _paths[i].second, this))); _jsEngine->globalObject().setProperty("files", jsPaths); @@ -138,9 +167,10 @@ void File::loadFitsKeywords() } else return; - for(const FITSRecord &record : info.fitsHeader) + for(auto &record : info.fitsHeader) { - _fitsKeywords[record.key] = record.value.toString(); + _fitsKeywords.append(record.key); + _fitsRecords.insert(record.key, record); } } } @@ -165,9 +195,14 @@ bool File::mkpath(const QString &path) const } } -File::File(const QString &path, Script::ScriptEngine *engine) : +File::File(const QString &path, Script::ScriptEngine *engine) : File(path, QString(), engine) +{ +} + +File::File(const QString &path, const QString &root, ScriptEngine *engine) : _engine(engine), _path(path), + _root(root), _info(path) { } @@ -187,6 +222,18 @@ QString File::absolutePath() const return _info.absolutePath(); } +QString File::relativeFilePath() const +{ + QDir dir(_root); + return dir.relativeFilePath(_info.absoluteFilePath()); +} + +QString File::relativePath() const +{ + QDir dir(_root); + return dir.relativeFilePath(_info.absolutePath()); +} + QString File::baseName() const { return _info.baseName(); @@ -209,53 +256,101 @@ qint64 File::size() const QStringList File::fitsKeywords() { - QThread::msleep(500); loadFitsKeywords(); - return _fitsKeywords.keys(); + return _fitsKeywords; } QString File::fitsValue(const QString &key) { loadFitsKeywords(); - if(_fitsKeywords.contains(key)) - return _fitsKeywords[key]; + if(_fitsRecords.contains(key)) + return _fitsRecords[key].value.toString(); else return QString(); } +QJSValue File::fitsValues(const QString &key) +{ + loadFitsKeywords(); + if(_fitsRecords.contains(key)) + { + QList values = _fitsRecords.values(key); + QJSValue array = _engine->newArray(values.size()); + for(qsizetype i=0; inewArray(_fitsRecords.size()); + uint i = 0; + for(auto &record : _fitsRecords) + { + QJSValue item = _engine->newObject(); + item.setProperty("key", QString::fromUtf8(record.key)); + item.setProperty("value", record.value.toString()); + item.setProperty("comment", QString::fromUtf8(record.comment)); + item.setProperty("xisf", record.xisf); + array.setProperty(i++, item); + } + + return array; +} + bool File::isMarked() const { return _engine->isMarked(this); } -bool File::copy(const QString &newpath) const +File* File::copy(const QString &newpath) const { if(mkpath(newpath)) { if(QFile::copy(_path, _engine->outputDir() + newpath)) - return true; + return new File(_engine->outputDir() + newpath, _engine); _engine->logError("Failed copy to " + newpath); - return false; + return nullptr; } - return false; + return nullptr; } -bool File::move(const QString &newpath) const +bool File::move(const QString &newpath) { if(mkpath(newpath)) { if(QFile::rename(_path, _engine->outputDir() + newpath)) + { + _path = _engine->outputDir() + newpath; return true; + } _engine->logError("Failed move to " + newpath); return false; } return false; } -bool File::convertTo(const QString &format) +File* File::convert(const QString &outpath, const QString &format, const QVariantMap ¶ms) { - _engine->reportError("Not implemented"); - return false; + QString path = outpath; + if(_engine->convert(this, path, format, params, false)) + return new File(path, _engine); + else + return nullptr; +} + +File* File::convertAsync(const QString &outpath, const QString &format, const QVariantMap ¶ms) +{ + QString path = outpath; + if(_engine->convert(this, path, format, params, true)) + return new File(path, _engine); + else + return nullptr; } QJSValue File::stats() @@ -298,7 +393,7 @@ ScriptEngineThread::~ScriptEngineThread() if(_engine)_engine->interrupt(); } -void ScriptEngineThread::setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir) +void ScriptEngineThread::setParams(const QString &scriptPath, const QList> &paths, const QString &outputDir) { _engine->setParams(scriptPath, paths, outputDir); } diff --git a/scriptengine.h b/scriptengine.h index 1aea2be..83abc4c 100644 --- a/scriptengine.h +++ b/scriptengine.h @@ -8,6 +8,7 @@ #include #include #include "database.h" +#include "imageinfo.h" namespace Script { @@ -23,10 +24,10 @@ class ScriptEngine : public QObject QSemaphore _semaphore; QString _scriptPath; QString _outputDir; - QStringList _paths; + QList> _paths; public: explicit ScriptEngine(QObject *parent = nullptr); - void setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir); + void setParams(const QString &scriptPath, const QList> &paths, const QString &outputDir); void reportError(const QString &message); const QString& outputDir() const; void interrupt(); @@ -35,8 +36,11 @@ public: Q_INVOKABLE void mark(File *file); Q_INVOKABLE void unmark(File *file); Q_INVOKABLE bool isMarked(const File *file) const; - Q_INVOKABLE bool convert(File *file, QString &outpath, QString format, QVariantMap params); + Q_INVOKABLE void setMaxThread(int maxthread); + Q_INVOKABLE void sync(); + bool convert(File *file, QString &outpath, const QString &format, const QVariantMap ¶ms, bool async); QJSValue newObject(); + QJSValue newArray(uint size); public slots: void run(); signals: @@ -52,7 +56,7 @@ class ScriptEngineThread : public QObject public: ScriptEngineThread(QObject *parent = nullptr); ~ScriptEngineThread(); - void setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir); + void setParams(const QString &scriptPath, const QList> &paths, const QString &outputDir); void start(); void interrupt(); signals: @@ -65,27 +69,35 @@ class File : public QObject Q_OBJECT ScriptEngine *_engine; QString _path; + QString _root; QFileInfo _info; bool _fitsKeywordsLoaded = false; - QMap _fitsKeywords; + QStringList _fitsKeywords; + QMultiHash _fitsRecords; void loadFitsKeywords(); bool mkpath(const QString &path) const; QJSValue _stats; public: explicit File(const QString &path, ScriptEngine *engine); + explicit File(const QString &path, const QString &root, ScriptEngine *engine); Q_INVOKABLE QString fileName() const; Q_INVOKABLE QString absoluteFilePath() const; Q_INVOKABLE QString absolutePath() const; + Q_INVOKABLE QString relativeFilePath() const; + Q_INVOKABLE QString relativePath() const; Q_INVOKABLE QString baseName() const; Q_INVOKABLE QString completeBaseName() const; Q_INVOKABLE QString suffix() const; Q_INVOKABLE qint64 size() const; Q_INVOKABLE QStringList fitsKeywords(); Q_INVOKABLE QString fitsValue(const QString &key); + Q_INVOKABLE QJSValue fitsValues(const QString &key); + Q_INVOKABLE QJSValue fitsRecords(); Q_INVOKABLE bool isMarked() const; - Q_INVOKABLE bool copy(const QString &newpath) const; - Q_INVOKABLE bool move(const QString &newpath) const; - Q_INVOKABLE bool convertTo(const QString &format); + Q_INVOKABLE File* copy(const QString &newpath) const; + Q_INVOKABLE bool move(const QString &newpath); + Q_INVOKABLE File* convert(const QString &outpath, const QString &format, const QVariantMap ¶ms); + Q_INVOKABLE File* convertAsync(const QString &outpath, const QString &format, const QVariantMap ¶ms); Q_INVOKABLE QJSValue stats(); };