#include "batchprocessing.h" #include "ui_batchprocessing.h" #include #include #include #include #include #include #include #include #include #include "scriptengine.h" #ifdef Q_OS_LINUX #include #include #include #include #include #endif QList> scanDirectories(const QStringList &paths) { QList> files; QStringList scannedDirs; std::function scanDirectory = [&](const QString &root, const QString &path) { QFileInfo info(path); if(info.isDir() && !scannedDirs.contains(info.canonicalFilePath())) { scannedDirs.append(info.canonicalFilePath()); QDir dir(path); QStringList entries = dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); for(QString &entry : entries) scanDirectory(root, dir.absoluteFilePath(entry)); } else if(info.isFile()) { files.append({path, root}); } }; for(const QString &path : paths) scanDirectory(path, path); return files; } void BatchProcessing::scanScriptDir() { QString current; if(_ui->scriptsList->currentItem()) current = _ui->scriptsList->currentItem()->text(); _ui->scriptsList->clear(); QDir dir(_scriptBasePath); QStringList scripts = dir.entryList(QDir::Files | QDir::Readable); _ui->scriptsList->addItems(scripts); int idx = scripts.indexOf(current); if(idx>=0)_ui->scriptsList->setCurrentRow(idx); } BatchProcessing::BatchProcessing(QWidget *parent) : QDialog(parent) { _ui = new Ui::BatchProcessing; _ui->setupUi(this); QStringList scriptsPath = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); if(scriptsPath.size()) { QDir dir(scriptsPath.first()); if(!dir.exists("scripts")) { if(!dir.mkpath("scripts")) qWarning() << "Failed to create scripts directory"; } dir.cd("scripts"); _scriptBasePath = dir.absolutePath() + "/"; scanScriptDir(); _fileWatcher.addPath(_scriptBasePath); connect(&_fileWatcher, &QFileSystemWatcher::directoryChanged, this, &BatchProcessing::scanScriptDir); } else { qWarning() << "Failed to get app data location"; } connect(_ui->addFilesButton, &QPushButton::released, this, &BatchProcessing::addFiles); connect(_ui->addDirButton, &QPushButton::released, this, &BatchProcessing::addDir); connect(_ui->removeButton, &QPushButton::released, this, &BatchProcessing::removePath); connect(_ui->removeAllButton, &QPushButton::released, this, &BatchProcessing::removeAllPaths); connect(_ui->startButton, &QPushButton::released, this, &BatchProcessing::runScript); connect(_ui->stopButton, &QPushButton::released, this, &BatchProcessing::stopScript); connect(_ui->browseButton, &QPushButton::released, this, &BatchProcessing::browse); connect(_ui->openScriptsButton, &QPushButton::released, this, &BatchProcessing::openScriptDir); _textColor = _ui->log->palette().text().color(); QSettings settings; _ui->outputPath->setText(settings.value("batchprocessing/outputpath", QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first()).toString()); _ui->pathsList->addItem("/home/nou/Obrázky/astro/2019-12-03"); } BatchProcessing::~BatchProcessing() { delete _engineThread; QSettings settings; settings.setValue("batchprocessing/outputpath", _ui->outputPath->text()); delete _ui; } void BatchProcessing::closeEvent(QCloseEvent *event) { if(_engineThread) { QMessageBox::StandardButton ret = QMessageBox::question(this, tr("Interrupt running script?"), tr("Interrupt running script?")); if(ret == QMessageBox::StandardButton::Yes) { _engineThread->interrupt(); event->accept(); } else { event->ignore(); } } else { event->accept(); } } void BatchProcessing::addFiles() { QSettings settings; QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files"), settings.value("batchprocessing/inputpath", QDir::homePath()).toString()); if(!files.isEmpty()) { _ui->pathsList->addItems(files); settings.setValue("batchprocessing/inputpath", QFileInfo(files.first()).absolutePath()); } } void BatchProcessing::addDir() { QSettings settings; QString dir = QFileDialog::getExistingDirectory(this, tr("Select directory"), settings.value("batchprocessing/inputpath", QDir::homePath()).toString()); if(!dir.isEmpty()) { _ui->pathsList->addItem(dir); settings.setValue("batchprocessing/inputpath", dir); } } void BatchProcessing::removePath() { for(auto &item : _ui->pathsList->selectedItems()) delete item; } void BatchProcessing::removeAllPaths() { _ui->pathsList->clear(); } void BatchProcessing::browse() { QString output = QFileDialog::getExistingDirectory(this, tr("Select output directory"), "/home/nou/Obrázky"); if(!output.isEmpty()) _ui->outputPath->setText(output); } void BatchProcessing::openScriptDir() { #ifdef Q_OS_LINUX QDBusConnection con = QDBusConnection::sessionBus(); QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1", "ShowFolders"); QList args = {QStringList(QUrl::fromLocalFile(_scriptBasePath).toString()), QString()}; message.setArguments(args); con.call(message); #endif #ifdef Q_OS_WINDOWS QProcess::startDetached("explorer.exe", {QDir::toNativeSeparators(_scriptBasePath)}); #endif #ifdef Q_OS_MACOS QDesktopServices::openUrl(QUrl::fromLocalFile(_scriptBasePath)); #endif } void BatchProcessing::runScript() { _ui->log->clear(); auto selectedItems = _ui->scriptsList->selectedItems(); if(selectedItems.size()) { _engineThread = new Script::ScriptEngineThread(this); connect(_engineThread, &Script::ScriptEngineThread::newMessage, this, &BatchProcessing::newMessage); connect(_engineThread, &Script::ScriptEngineThread::finished, this, &BatchProcessing::scriptFinished); QStringList paths; for(int i=0; i<_ui->pathsList->count(); i++) paths.append(_ui->pathsList->item(i)->text()); QFileInfo outDir(_ui->outputPath->text()); if(outDir.exists() && outDir.isWritable()) { _engineThread->setParams(_scriptBasePath + selectedItems.first()->text(), scanDirectories(paths), _ui->outputPath->text()); _engineThread->start(); _ui->startButton->setEnabled(false); _ui->stopButton->setEnabled(true); } else { QMessageBox::warning(this, tr("Invalid output directory"), tr("Output directory path doesn't exist or is not writable")); } } } void BatchProcessing::stopScript() { qDebug() << "Stop script"; if(_engineThread) _engineThread->interrupt(); } void BatchProcessing::scriptFinished() { _ui->startButton->setEnabled(true); _ui->stopButton->setEnabled(false); qDebug() << "script finished"; _engineThread->deleteLater(); _engineThread = nullptr; } void BatchProcessing::newMessage(const QString &message, bool error) { if(error)_ui->log->setTextColor(Qt::red); else _ui->log->setTextColor(_textColor); _ui->log->append(message); } QJSValue BatchProcessing::getString(const QString &label, const QString &text) { bool ok = false; QString ret = QInputDialog::getText(this, tr("Enter text"), label, QLineEdit::Normal, text, &ok); return ok ? ret : QJSValue(); } QJSValue BatchProcessing::getInt(const QString &label, int value) { bool ok = false; int ret = QInputDialog::getInt(this, tr("Enter integer number"), label, value, INT_MIN, INT_MAX, 1, &ok); return ok ? ret : QJSValue(); } QJSValue BatchProcessing::getFloat(const QString &label, double value, int decimals) { bool ok = false; double ret = QInputDialog::getDouble(this, tr("Enter float number"), label, value, -INFINITY, INFINITY, decimals, &ok); return ok ? ret : QJSValue(); } QJSValue BatchProcessing::getItem(const QStringList &items, const QString &label, int current) { bool ok = false; QString ret = QInputDialog::getItem(this, tr("Select item"), label, items, current, false, &ok); return ok ? ret : QJSValue(); }