Move process configuration to separate class and widget

This commit is contained in:
WarmUpTill 2023-02-22 17:15:11 +01:00 committed by WarmUpTill
parent 59ecf43c5f
commit b77f8717fe
5 changed files with 380 additions and 257 deletions

View File

@ -191,6 +191,8 @@ target_sources(
src/macro-core/macro-condition-recording.hpp
src/macro-core/macro-condition-replay-buffer.cpp
src/macro-core/macro-condition-replay-buffer.hpp
src/macro-core/macro-condition-run.cpp
src/macro-core/macro-condition-run.hpp
src/macro-core/macro-condition-scene-order.cpp
src/macro-core/macro-condition-scene-order.hpp
src/macro-core/macro-condition-scene-transform.cpp
@ -252,6 +254,8 @@ target_sources(
src/utils/macro-list.hpp
src/utils/name-dialog.cpp
src/utils/name-dialog.hpp
src/utils/process-config.cpp
src/utils/process-config.hpp
src/utils/regex-config.cpp
src/utils/regex-config.hpp
src/utils/resizing-text-edit.cpp

View File

@ -1,10 +1,8 @@
#include "macro-action-run.hpp"
#include "advanced-scene-switcher.hpp"
#include "name-dialog.hpp"
#include "utility.hpp"
#include <QProcess>
#include <QFileDialog>
#include <QDesktopServices>
const std::string MacroActionRun::id = "run";
@ -15,137 +13,53 @@ bool MacroActionRun::_registered = MacroActionFactory::Register(
bool MacroActionRun::PerformAction()
{
if (!QProcess::startDetached(
QString::fromStdString(_path), _args,
QString::fromStdString(_workingDirectory)) &&
_args.empty()) {
bool procStarted = QProcess::startDetached(
QString::fromStdString(_procConfig.Path()), _procConfig.Args(),
QString::fromStdString(_procConfig.WorkingDir()));
if (!procStarted && _procConfig.Args().empty()) {
vblog(LOG_INFO, "run \"%s\" using QDesktopServices",
_path.c_str());
QDesktopServices::openUrl(
QUrl::fromLocalFile(QString::fromStdString(_path)));
_procConfig.Path().c_str());
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(_procConfig.Path())));
}
return true;
}
void MacroActionRun::LogAction() const
{
vblog(LOG_INFO, "run \"%s\"", _path.c_str());
vblog(LOG_INFO, "run \"%s\"", _procConfig.Path().c_str());
}
bool MacroActionRun::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
obs_data_set_string(obj, "path", _path.c_str());
obs_data_set_string(obj, "workingDirectory", _workingDirectory.c_str());
obs_data_array_t *args = obs_data_array_create();
for (auto &arg : _args) {
obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "arg",
arg.toStdString().c_str());
obs_data_array_push_back(args, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "args", args);
obs_data_array_release(args);
_procConfig.Save(obj);
return true;
}
bool MacroActionRun::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_path = obs_data_get_string(obj, "path");
_workingDirectory = obs_data_get_string(obj, "workingDirectory");
obs_data_array_t *args = obs_data_get_array(obj, "args");
size_t count = obs_data_array_count(args);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(args, i);
_args << QString::fromStdString(
obs_data_get_string(array_obj, "arg"));
obs_data_release(array_obj);
}
obs_data_array_release(args);
_procConfig.Load(obj);
return true;
}
std::string MacroActionRun::GetShortDesc() const
{
return _path;
return _procConfig.Path();
}
MacroActionRunEdit::MacroActionRunEdit(
QWidget *parent, std::shared_ptr<MacroActionRun> entryData)
: QWidget(parent),
_filePath(new FileSelection()),
_argList(new QListWidget()),
_addArg(new QPushButton()),
_removeArg(new QPushButton()),
_argUp(new QPushButton()),
_argDown(new QPushButton()),
_workingDirectory(new FileSelection(FileSelection::Type::FOLDER))
: QWidget(parent), _procConfig(new ProcessConfigEdit(this))
{
_addArg->setMaximumWidth(22);
_addArg->setProperty("themeID",
QVariant(QString::fromUtf8("addIconSmall")));
_addArg->setFlat(true);
_removeArg->setMaximumWidth(22);
_removeArg->setProperty("themeID",
QVariant(QString::fromUtf8("removeIconSmall")));
_removeArg->setFlat(true);
_argUp->setMaximumWidth(22);
_argUp->setProperty("themeID",
QVariant(QString::fromUtf8("upArrowIconSmall")));
_argUp->setFlat(true);
_argDown->setMaximumWidth(22);
_argDown->setProperty(
"themeID", QVariant(QString::fromUtf8("downArrowIconSmall")));
_argDown->setFlat(true);
QWidget::connect(_procConfig,
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
SLOT(ProcessConfigChanged(const ProcessConfig &)));
QWidget::connect(_filePath, SIGNAL(PathChanged(const QString &)), this,
SLOT(PathChanged(const QString &)));
QWidget::connect(_addArg, SIGNAL(clicked()), this, SLOT(AddArg()));
QWidget::connect(_removeArg, SIGNAL(clicked()), this,
SLOT(RemoveArg()));
QWidget::connect(_argUp, SIGNAL(clicked()), this, SLOT(ArgUp()));
QWidget::connect(_argDown, SIGNAL(clicked()), this, SLOT(ArgDown()));
QWidget::connect(_argList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
this, SLOT(ArgItemClicked(QListWidgetItem *)));
QWidget::connect(_workingDirectory,
SIGNAL(PathChanged(const QString &)), this,
SLOT(WorkingDirectoryChanged(const QString &)));
auto *entryLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{filePath}}", _filePath},
{"{{workingDirectory}}", _workingDirectory},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.action.run.entry"),
entryLayout, widgetPlaceholders, false);
auto argButtonLayout = new QHBoxLayout;
argButtonLayout->addWidget(_addArg);
argButtonLayout->addWidget(_removeArg);
QFrame *line = new QFrame();
line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken);
argButtonLayout->addWidget(line);
argButtonLayout->addWidget(_argUp);
argButtonLayout->addWidget(_argDown);
argButtonLayout->addStretch();
auto workingDirectoryLayout = new QHBoxLayout;
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.action.run.entry.workingDirectory"),
workingDirectoryLayout, widgetPlaceholders, false);
auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
mainLayout->addWidget(new QLabel(
obs_module_text("AdvSceneSwitcher.action.run.arguments")));
mainLayout->addWidget(_argList);
mainLayout->addLayout(argButtonLayout);
mainLayout->addLayout(workingDirectoryLayout);
setLayout(mainLayout);
auto *layout = new QVBoxLayout;
layout->addWidget(_procConfig);
setLayout(layout);
_entryData = entryData;
UpdateEntryData();
@ -157,142 +71,19 @@ void MacroActionRunEdit::UpdateEntryData()
if (!_entryData) {
return;
}
_filePath->SetPath(QString::fromStdString(_entryData->_path));
for (auto &arg : _entryData->_args) {
QListWidgetItem *item = new QListWidgetItem(arg, _argList);
item->setData(Qt::UserRole, arg);
}
_workingDirectory->SetPath(
QString::fromStdString(_entryData->_workingDirectory));
SetArgListSize();
_procConfig->SetProcessConfig(_entryData->_procConfig);
}
void MacroActionRunEdit::PathChanged(const QString &text)
void MacroActionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_path = text.toUtf8().constData();
_entryData->_procConfig = conf;
adjustSize();
updateGeometry();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroActionRunEdit::AddArg()
{
if (_loading || !_entryData) {
return;
}
std::string name;
bool accepted = AdvSSNameDialog::AskForName(
this,
obs_module_text("AdvSceneSwitcher.action.run.addArgument"),
obs_module_text(
"AdvSceneSwitcher.action.run.addArgumentDescription"),
name, "", 170, false);
if (!accepted || name.empty()) {
return;
}
auto arg = QString::fromStdString(name);
QVariant v = QVariant::fromValue(arg);
QListWidgetItem *item = new QListWidgetItem(arg, _argList);
item->setData(Qt::UserRole, arg);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_args << arg;
SetArgListSize();
}
void MacroActionRunEdit::RemoveArg()
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
int idx = _argList->currentRow();
if (idx == -1) {
return;
}
_entryData->_args.removeAt(idx);
QListWidgetItem *item = _argList->currentItem();
if (!item) {
return;
}
delete item;
SetArgListSize();
}
void MacroActionRunEdit::ArgUp()
{
if (_loading || !_entryData) {
return;
}
int idx = _argList->currentRow();
if (idx != -1 && idx != 0) {
_argList->insertItem(idx - 1, _argList->takeItem(idx));
_argList->setCurrentRow(idx - 1);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_args.move(idx, idx - 1);
}
}
void MacroActionRunEdit::ArgDown()
{
int idx = _argList->currentRow();
if (idx != -1 && idx != _argList->count() - 1) {
_argList->insertItem(idx + 1, _argList->takeItem(idx));
_argList->setCurrentRow(idx + 1);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_args.move(idx, idx + 1);
}
}
void MacroActionRunEdit::ArgItemClicked(QListWidgetItem *item)
{
if (_loading || !_entryData) {
return;
}
std::string name;
bool accepted = AdvSSNameDialog::AskForName(
this,
obs_module_text("AdvSceneSwitcher.action.run.addArgument"),
obs_module_text(
"AdvSceneSwitcher.action.run.addArgumentDescription"),
name, item->text(), 170, false);
if (!accepted || name.empty()) {
return;
}
auto arg = QString::fromStdString(name);
QVariant v = QVariant::fromValue(arg);
item->setText(arg);
item->setData(Qt::UserRole, arg);
int idx = _argList->currentRow();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_args[idx] = arg;
}
void MacroActionRunEdit::WorkingDirectoryChanged(const QString &path)
{
if (_loading || !_entryData) {
return;
}
_entryData->_workingDirectory = path.toStdString();
}
void MacroActionRunEdit::SetArgListSize()
{
setHeightToContentHeight(_argList);
adjustSize();
}

View File

@ -1,11 +1,6 @@
#pragma once
#include "macro-action-edit.hpp"
#include "file-selection.hpp"
#include <QLineEdit>
#include <QPushButton>
#include <QListWidget>
#include <QStringList>
#include "process-config.hpp"
class MacroActionRun : public MacroAction {
public:
@ -21,9 +16,7 @@ public:
return std::make_shared<MacroActionRun>(m);
}
std::string _path = obs_module_text("AdvSceneSwitcher.enterPath");
std::string _workingDirectory = "";
QStringList _args;
ProcessConfig _procConfig;
private:
static bool _registered;
@ -46,13 +39,7 @@ public:
}
private slots:
void PathChanged(const QString &text);
void AddArg();
void RemoveArg();
void ArgUp();
void ArgDown();
void ArgItemClicked(QListWidgetItem *);
void WorkingDirectoryChanged(const QString &text);
void ProcessConfigChanged(const ProcessConfig &);
signals:
void HeaderInfoChanged(const QString &);
@ -60,14 +47,6 @@ protected:
std::shared_ptr<MacroActionRun> _entryData;
private:
void SetArgListSize();
FileSelection *_filePath;
QListWidget *_argList;
QPushButton *_addArg;
QPushButton *_removeArg;
QPushButton *_argUp;
QPushButton *_argDown;
FileSelection *_workingDirectory;
ProcessConfigEdit *_procConfig;
bool _loading = true;
};

View File

@ -0,0 +1,286 @@
#include "process-config.hpp"
#include "name-dialog.hpp"
#include "utility.hpp"
#include <QProcess>
#include <QFileDialog>
bool ProcessConfig::Save(obs_data_t *obj) const
{
auto data = obs_data_create();
obs_data_set_string(data, "path", _path.c_str());
obs_data_set_string(data, "workingDirectory",
_workingDirectory.c_str());
obs_data_array_t *args = obs_data_array_create();
for (auto &arg : _args) {
obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "arg",
arg.toStdString().c_str());
obs_data_array_push_back(args, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(data, "args", args);
obs_data_array_release(args);
obs_data_set_obj(obj, "processConfig", data);
obs_data_release(data);
return true;
}
bool ProcessConfig::Load(obs_data_t *obj)
{
// TODO: Remove this fallback in a future version
if (!obs_data_has_user_value(obj, "processConfig")) {
_path = obs_data_get_string(obj, "path");
_workingDirectory =
obs_data_get_string(obj, "workingDirectory");
obs_data_array_t *args = obs_data_get_array(obj, "args");
size_t count = obs_data_array_count(args);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(args, i);
_args << QString::fromStdString(
obs_data_get_string(array_obj, "arg"));
obs_data_release(array_obj);
}
obs_data_array_release(args);
return true;
}
auto data = obs_data_get_obj(obj, "processConfig");
_path = obs_data_get_string(data, "path");
_workingDirectory = obs_data_get_string(data, "workingDirectory");
obs_data_array_t *args = obs_data_get_array(data, "args");
size_t count = obs_data_array_count(args);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(args, i);
_args << QString::fromStdString(
obs_data_get_string(array_obj, "arg"));
obs_data_release(array_obj);
}
obs_data_array_release(args);
obs_data_release(data);
return true;
}
ProcessConfigEdit::ProcessConfigEdit(QWidget *parent)
: QWidget(parent),
_filePath(new FileSelection()),
_showAdvancedSettings(new QPushButton(
obs_module_text("AdvSceneSwitcher.process.showAdvanced"))),
_advancedSettingsLayout(new QVBoxLayout()),
_argList(new QListWidget()),
_addArg(new QPushButton()),
_removeArg(new QPushButton()),
_argUp(new QPushButton()),
_argDown(new QPushButton()),
_workingDirectory(new FileSelection(FileSelection::Type::FOLDER))
{
_advancedSettingsLayout->setContentsMargins(0, 0, 0, 0);
_addArg->setMaximumWidth(22);
_addArg->setProperty("themeID",
QVariant(QString::fromUtf8("addIconSmall")));
_addArg->setFlat(true);
_removeArg->setMaximumWidth(22);
_removeArg->setProperty("themeID",
QVariant(QString::fromUtf8("removeIconSmall")));
_removeArg->setFlat(true);
_argUp->setMaximumWidth(22);
_argUp->setProperty("themeID",
QVariant(QString::fromUtf8("upArrowIconSmall")));
_argUp->setFlat(true);
_argDown->setMaximumWidth(22);
_argDown->setProperty(
"themeID", QVariant(QString::fromUtf8("downArrowIconSmall")));
_argDown->setFlat(true);
QWidget::connect(_filePath, SIGNAL(PathChanged(const QString &)), this,
SLOT(PathChanged(const QString &)));
QWidget::connect(_showAdvancedSettings, SIGNAL(clicked()), this,
SLOT(ShowAdvancedSettingsClicked()));
QWidget::connect(_addArg, SIGNAL(clicked()), this, SLOT(AddArg()));
QWidget::connect(_removeArg, SIGNAL(clicked()), this,
SLOT(RemoveArg()));
QWidget::connect(_argUp, SIGNAL(clicked()), this, SLOT(ArgUp()));
QWidget::connect(_argDown, SIGNAL(clicked()), this, SLOT(ArgDown()));
QWidget::connect(_argList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
this, SLOT(ArgItemClicked(QListWidgetItem *)));
QWidget::connect(_workingDirectory,
SIGNAL(PathChanged(const QString &)), this,
SLOT(WorkingDirectoryChanged(const QString &)));
auto *entryLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{filePath}}", _filePath},
{"{{workingDirectory}}", _workingDirectory},
{"{{advancedSettings}}", _showAdvancedSettings},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.process.entry"),
entryLayout, widgetPlaceholders, false);
auto argButtonLayout = new QHBoxLayout;
argButtonLayout->addWidget(_addArg);
argButtonLayout->addWidget(_removeArg);
QFrame *line = new QFrame();
line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken);
argButtonLayout->addWidget(line);
argButtonLayout->addWidget(_argUp);
argButtonLayout->addWidget(_argDown);
argButtonLayout->addStretch();
auto workingDirectoryLayout = new QHBoxLayout;
placeWidgets(obs_module_text(
"AdvSceneSwitcher.process.entry.workingDirectory"),
workingDirectoryLayout, widgetPlaceholders, false);
_advancedSettingsLayout->addWidget(new QLabel(
obs_module_text("AdvSceneSwitcher.process.arguments")));
_advancedSettingsLayout->addWidget(_argList);
_advancedSettingsLayout->addLayout(argButtonLayout);
_advancedSettingsLayout->addLayout(workingDirectoryLayout);
auto *mainLayout = new QVBoxLayout;
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addLayout(entryLayout);
mainLayout->addLayout(_advancedSettingsLayout);
setLayout(mainLayout);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
}
void ProcessConfigEdit::SetProcessConfig(const ProcessConfig &conf)
{
_conf = conf;
_filePath->SetPath(QString::fromStdString(conf._path));
for (const auto &arg : conf._args) {
QListWidgetItem *item = new QListWidgetItem(arg, _argList);
item->setData(Qt::UserRole, arg);
}
_workingDirectory->SetPath(
QString::fromStdString(conf._workingDirectory));
SetArgListSize();
ShowAdvancedSettings(!_conf._args.empty() ||
!_conf._workingDirectory.empty());
}
void ProcessConfigEdit::PathChanged(const QString &text)
{
_conf._path = text.toStdString();
emit ConfigChanged(_conf);
}
void ProcessConfigEdit::ShowAdvancedSettingsClicked()
{
ShowAdvancedSettings(true);
emit ConfigChanged(_conf); // Just to make sure resizing is handled
}
void ProcessConfigEdit::AddArg()
{
std::string name;
bool accepted = AdvSSNameDialog::AskForName(
this, obs_module_text("AdvSceneSwitcher.process.addArgument"),
obs_module_text(
"AdvSceneSwitcher.process.addArgumentDescription"),
name, "", 170, false);
if (!accepted || name.empty()) {
return;
}
auto arg = QString::fromStdString(name);
QVariant v = QVariant::fromValue(arg);
QListWidgetItem *item = new QListWidgetItem(arg, _argList);
item->setData(Qt::UserRole, arg);
_conf._args << arg;
SetArgListSize();
emit ConfigChanged(_conf);
}
void ProcessConfigEdit::RemoveArg()
{
int idx = _argList->currentRow();
if (idx == -1) {
return;
}
_conf._args.removeAt(idx);
QListWidgetItem *item = _argList->currentItem();
if (!item) {
return;
}
delete item;
SetArgListSize();
emit ConfigChanged(_conf);
}
void ProcessConfigEdit::ArgUp()
{
int idx = _argList->currentRow();
if (idx != -1 && idx != 0) {
_argList->insertItem(idx - 1, _argList->takeItem(idx));
_argList->setCurrentRow(idx - 1);
_conf._args.move(idx, idx - 1);
}
emit ConfigChanged(_conf);
}
void ProcessConfigEdit::ArgDown()
{
int idx = _argList->currentRow();
if (idx != -1 && idx != _argList->count() - 1) {
_argList->insertItem(idx + 1, _argList->takeItem(idx));
_argList->setCurrentRow(idx + 1);
_conf._args.move(idx, idx + 1);
}
emit ConfigChanged(_conf);
}
void ProcessConfigEdit::ArgItemClicked(QListWidgetItem *item)
{
std::string name;
bool accepted = AdvSSNameDialog::AskForName(
this, obs_module_text("AdvSceneSwitcher.process.addArgument"),
obs_module_text(
"AdvSceneSwitcher.process.addArgumentDescription"),
name, item->text(), 170, false);
if (!accepted || name.empty()) {
return;
}
auto arg = QString::fromStdString(name);
QVariant v = QVariant::fromValue(arg);
item->setText(arg);
item->setData(Qt::UserRole, arg);
int idx = _argList->currentRow();
_conf._args[idx] = arg;
emit ConfigChanged(_conf);
}
void ProcessConfigEdit::WorkingDirectoryChanged(const QString &path)
{
_conf._workingDirectory = path.toStdString();
emit ConfigChanged(_conf);
}
void ProcessConfigEdit::SetArgListSize()
{
setHeightToContentHeight(_argList);
adjustSize();
updateGeometry();
}
void ProcessConfigEdit::ShowAdvancedSettings(bool showAdvancedSettings)
{
setLayoutVisible(_advancedSettingsLayout, showAdvancedSettings);
_showAdvancedSettings->setVisible(!showAdvancedSettings);
adjustSize();
updateGeometry();
}

View File

@ -0,0 +1,63 @@
#pragma once
#include "file-selection.hpp"
#include <obs-data.h>
#include <obs-module.h>
#include <QPushButton>
#include <QListWidget>
#include <QStringList>
#include <QVBoxLayout>
class ProcessConfig {
public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string Path() const { return _path; }
std::string WorkingDir() const { return _workingDirectory; }
QStringList Args() const { return _args; }
private:
std::string _path = obs_module_text("AdvSceneSwitcher.enterPath");
std::string _workingDirectory = "";
QStringList _args;
friend class ProcessConfigEdit;
};
class ProcessConfigEdit : public QWidget {
Q_OBJECT
public:
ProcessConfigEdit(QWidget *parent);
void SetProcessConfig(const ProcessConfig &);
private slots:
void PathChanged(const QString &);
void ShowAdvancedSettingsClicked();
void AddArg();
void RemoveArg();
void ArgUp();
void ArgDown();
void ArgItemClicked(QListWidgetItem *);
void WorkingDirectoryChanged(const QString &);
signals:
void ConfigChanged(const ProcessConfig &);
private:
void SetArgListSize();
void ShowAdvancedSettings(bool);
ProcessConfig _conf;
FileSelection *_filePath;
QPushButton *_showAdvancedSettings;
QVBoxLayout *_advancedSettingsLayout;
QListWidget *_argList;
QPushButton *_addArg;
QPushButton *_removeArg;
QPushButton *_argUp;
QPushButton *_argDown;
FileSelection *_workingDirectory;
};