porymap/src/ui/customscriptseditor.cpp

232 lines
8.4 KiB
C++
Raw Normal View History

2023-09-01 19:00:09 +01:00
#include "customscriptseditor.h"
#include "ui_customscriptseditor.h"
#include "ui_customscriptslistitem.h"
#include "config.h"
#include "editor.h"
#include "shortcut.h"
#include <QDir>
#include <QFileDialog>
// TODO: System for turning scripts on or off
//
// TODO: Better URL colors on dark themes
// TODO: Save window state
CustomScriptsEditor::CustomScriptsEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::CustomScriptsEditor),
baseDir(userConfig.getProjectDir() + QDir::separator())
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
// This property seems to be reset if we don't set it programmatically
ui->list->setDragDropMode(QAbstractItemView::NoDragDrop);
for (auto path : userConfig.getCustomScripts())
this->displayScript(path);
this->importDir = userConfig.getProjectDir();
connect(ui->button_AddNewScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::addNewScript);
connect(ui->button_ReloadScripts, &QAbstractButton::clicked, this, &CustomScriptsEditor::reloadScripts);
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &CustomScriptsEditor::dialogButtonClicked);
this->initShortcuts();
}
CustomScriptsEditor::~CustomScriptsEditor()
{
ui->list->clear();
delete ui;
}
void CustomScriptsEditor::initShortcuts() {
auto *shortcut_remove = new Shortcut({QKeySequence("Del"), QKeySequence("Backspace")}, this, SLOT(removeSelectedScripts()));
shortcut_remove->setObjectName("shortcut_remove");
shortcut_remove->setWhatsThis("Remove Selected Scripts");
// TODO: Prevent ambiguity with MainWindow
auto *shortcut_open = new Shortcut(QKeySequence("Ctrl+O"), this, SLOT(openSelectedScripts()));
shortcut_open->setObjectName("shortcut_open");
shortcut_open->setWhatsThis("Open Selected Scripts");
auto *shortcut_addNew = new Shortcut(QKeySequence(), this, SLOT(addNewScript()));
shortcut_addNew->setObjectName("shortcut_addNew");
shortcut_addNew->setWhatsThis("Add New Script...");
auto *shortcut_reload = new Shortcut(QKeySequence(), this, SLOT(reloadScripts()));
shortcut_reload->setObjectName("shortcut_reload");
shortcut_reload->setWhatsThis("Reload Scripts");
//connect(new QShortcut(QKeySequence("Backspace"), this), &QShortcut::activated, this, &CustomScriptsEditor::removeSelectedScripts);
//connect(new QShortcut(QKeySequence("Ctrl+O"), this), &QShortcut::activated, this, &CustomScriptsEditor::openSelectedScripts);
shortcutsConfig.load();
shortcutsConfig.setDefaultShortcuts(shortcutableObjects());
applyUserShortcuts();
}
QObjectList CustomScriptsEditor::shortcutableObjects() const {
QObjectList shortcutable_objects;
for (auto *action : findChildren<QAction *>())
if (!action->objectName().isEmpty())
shortcutable_objects.append(qobject_cast<QObject *>(action));
for (auto *shortcut : findChildren<Shortcut *>())
if (!shortcut->objectName().isEmpty())
shortcutable_objects.append(qobject_cast<QObject *>(shortcut));
return shortcutable_objects;
}
// TODO: Connect to shorcuts editor
void CustomScriptsEditor::applyUserShortcuts() {
for (auto *action : findChildren<QAction *>())
if (!action->objectName().isEmpty())
action->setShortcuts(shortcutsConfig.userShortcuts(action));
for (auto *shortcut : findChildren<Shortcut *>())
if (!shortcut->objectName().isEmpty())
shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut));
}
void CustomScriptsEditor::displayScript(const QString &filepath) {
auto item = new QListWidgetItem();
auto buttons = new CustomScriptsListItem();
buttons->ui->lineEdit_filepath->setText(filepath);
item->setSizeHint(buttons->sizeHint());
connect(buttons->ui->b_Choose, &QAbstractButton::clicked, [this, item](bool) { this->replaceScript(item); });
connect(buttons->ui->b_Edit, &QAbstractButton::clicked, [this, item](bool) { this->openScript(item); });
connect(buttons->ui->b_Delete, &QAbstractButton::clicked, [this, item](bool) { this->removeScript(item); });
connect(buttons->ui->lineEdit_filepath, &QLineEdit::textEdited, [this](const QString&) { this->hasUnsavedChanges = true; });
// Per the Qt manual, for performance reasons QListWidget::setItemWidget shouldn't be used with non-static items.
// There's an assumption here that users won't have enough scripts for that to be a problem.
ui->list->addItem(item);
ui->list->setItemWidget(item, buttons);
}
QString CustomScriptsEditor::getListItemFilepath(QListWidgetItem * item) const {
auto widget = dynamic_cast<CustomScriptsListItem *>(ui->list->itemWidget(item));
if (!widget) return QString();
QString path = widget->ui->lineEdit_filepath->text();
QFileInfo fileInfo(path);
if (fileInfo.isRelative())
path.prepend(this->baseDir);
return path;
}
void CustomScriptsEditor::setListItemFilepath(QListWidgetItem * item, QString filepath) const {
auto widget = dynamic_cast<CustomScriptsListItem *>(ui->list->itemWidget(item));
if (!widget) return;
if (filepath.startsWith(this->baseDir))
filepath.remove(0, this->baseDir.length());
widget->ui->lineEdit_filepath->setText(filepath);
}
QString CustomScriptsEditor::chooseScript(QString dir) {
return QFileDialog::getOpenFileName(this, "Choose Custom Script File", dir, "JavaScript Files (*.js)");
}
void CustomScriptsEditor::addNewScript() {
QString filepath = this->chooseScript(this->importDir);
if (filepath.isEmpty())
return;
this->importDir = filepath;
if (filepath.startsWith(this->baseDir))
filepath.remove(0, this->baseDir.length());
this->displayScript(filepath);
this->hasUnsavedChanges = true;
}
void CustomScriptsEditor::removeScript(QListWidgetItem * item) {
ui->list->takeItem(ui->list->row(item));
this->hasUnsavedChanges = true;
}
void CustomScriptsEditor::removeSelectedScripts() {
QList<QListWidgetItem *> items = ui->list->selectedItems();
if (items.length() == 0)
return;
for (auto item : items)
this->removeScript(item);
}
void CustomScriptsEditor::replaceScript(QListWidgetItem * item) {
const QString filepath = this->chooseScript(this->getListItemFilepath(item));
if (filepath.isEmpty())
return;
this->setListItemFilepath(item, filepath);
this->hasUnsavedChanges = true;
}
void CustomScriptsEditor::openScript(QListWidgetItem * item) {
const QString path = this->getListItemFilepath(item);
QFileInfo fileInfo(path);
if (!fileInfo.exists() || !fileInfo.isFile()){
QMessageBox::warning(this, "", QString("Failed to open script '%1'").arg(path));
return;
}
Editor::openInTextEditor(path);
}
void CustomScriptsEditor::openSelectedScripts() {
for (auto item : ui->list->selectedItems())
this->openScript(item);
}
void CustomScriptsEditor::reloadScripts() {
if (this->hasUnsavedChanges) {
if (this->prompt("Scripts have been modified, save changes and reload the script engine?", QMessageBox::Yes) == QMessageBox::No)
return;
this->save();
}
emit reloadScriptEngine(); // TODO: Catch this signal
}
void CustomScriptsEditor::save() {
if (!this->hasUnsavedChanges)
return;
// TODO: Set new paths in config
this->hasUnsavedChanges = false;
this->reloadScripts();
}
int CustomScriptsEditor::prompt(const QString &text, QMessageBox::StandardButton defaultButton) {
QMessageBox messageBox(this);
messageBox.setText(text);
messageBox.setIcon(QMessageBox::Question);
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | defaultButton);
messageBox.setDefaultButton(defaultButton);
return messageBox.exec();
}
void CustomScriptsEditor::dialogButtonClicked(QAbstractButton *button) {
if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
this->save();
close(); // All buttons (OK and Cancel) close the window
}
void CustomScriptsEditor::closeEvent(QCloseEvent* event) {
if (this->hasUnsavedChanges) {
int result = this->prompt("Scripts have been modified, save changes?", QMessageBox::Cancel);
if (result == QMessageBox::Cancel) {
event->ignore();
return;
}
if (result == QMessageBox::Yes)
this->save();
}
/*
// TODO
porymapConfig.setProjectSettingsEditorGeometry(
this->saveGeometry(),
this->saveState()
);
*/
}