281 lines
8.9 KiB
C++
281 lines
8.9 KiB
C++
#include "batchprocessing.h"
|
|
#include "ui_batchprocessing.h"
|
|
#include <functional>
|
|
#include <QDir>
|
|
#include <QFileDialog>
|
|
#include <QStandardPaths>
|
|
#include <QProcess>
|
|
#include <QSettings>
|
|
#include <QCloseEvent>
|
|
#include <QMessageBox>
|
|
#include <QDesktopServices>
|
|
#include <QInputDialog>
|
|
#include "scriptengine.h"
|
|
|
|
#ifdef Q_OS_LINUX
|
|
#include <QCloseEvent>
|
|
#include <QDBusConnection>
|
|
#include <QDBusMessage>
|
|
#endif
|
|
|
|
QList<QPair<QString, QString>> scanDirectories(const QStringList &paths)
|
|
{
|
|
QList<QPair<QString, QString>> files;
|
|
QStringList scannedDirs;
|
|
|
|
std::function<void(const QString &root, const QString &path)> 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())
|
|
{
|
|
if(path == root)
|
|
files.append({path, info.absolutePath()});
|
|
else
|
|
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);
|
|
QDir embededDir(":/scripts");
|
|
QStringList scripts = dir.entryList(QDir::Files | QDir::Readable);
|
|
scripts.append(embededDir.entryList(QDir::Files));
|
|
scripts.removeDuplicates();
|
|
_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());
|
|
}
|
|
|
|
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"), _ui->outputPath->text());
|
|
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<QVariant> 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())
|
|
{
|
|
QString script = selectedItems.first()->text();
|
|
if(QDir(_scriptBasePath).exists(script))
|
|
script = _scriptBasePath + script;
|
|
else
|
|
script = ":/scripts/" + script;
|
|
|
|
_engineThread->setParams(script, 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();
|
|
}
|