#include "macro-action-run.hpp" #include "advanced-scene-switcher.hpp" #include "name-dialog.hpp" #include "utility.hpp" #include #include #include const std::string MacroActionRun::id = "run"; bool MacroActionRun::_registered = MacroActionFactory::Register( MacroActionRun::id, {MacroActionRun::Create, MacroActionRunEdit::Create, "AdvSceneSwitcher.action.run"}); bool MacroActionRun::PerformAction() { if (!QProcess::startDetached( QString::fromStdString(_path), _args, QString::fromStdString(_workingDirectory)) && _args.empty()) { vblog(LOG_INFO, "run \"%s\" using QDesktopServices", _path.c_str()); QDesktopServices::openUrl( QUrl::fromLocalFile(QString::fromStdString(_path))); } return true; } void MacroActionRun::LogAction() { vblog(LOG_INFO, "run \"%s\"", _path.c_str()); } bool MacroActionRun::Save(obs_data_t *obj) { 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); 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); return true; } std::string MacroActionRun::GetShortDesc() { return _path; } MacroActionRunEdit::MacroActionRunEdit( QWidget *parent, std::shared_ptr 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)) { _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(_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 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); _entryData = entryData; UpdateEntryData(); _loading = false; } 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(); } void MacroActionRunEdit::PathChanged(const QString &text) { if (_loading || !_entryData) { return; } std::lock_guard lock(switcher->m); _entryData->_path = text.toUtf8().constData(); 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 lock(switcher->m); _entryData->_args << arg; SetArgListSize(); } void MacroActionRunEdit::RemoveArg() { if (_loading || !_entryData) { return; } std::lock_guard 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 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 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 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(); }