728 lines
15 KiB
C++
728 lines
15 KiB
C++
#include "SettingsWidgets.hxx"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QCheckBox>
|
|
#include <QLabel>
|
|
#include <QComboBox>
|
|
#include <QSpinBox>
|
|
#include <QSettings>
|
|
#include <QLineEdit>
|
|
#include <QDebug>
|
|
#include <QPushButton>
|
|
#include <QFileDialog>
|
|
#include <QQmlEngine>
|
|
#include <QQmlContext>
|
|
#include <QDateTimeEdit>
|
|
#include <QPainter>
|
|
#include <QRegularExpressionValidator>
|
|
|
|
#include "LaunchConfig.hxx"
|
|
#include "SettingsSection.hxx"
|
|
|
|
const int MARGIN_HINT = 4;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
QString SettingsControl::label() const
|
|
{
|
|
return QString();
|
|
}
|
|
|
|
QString SettingsControl::description() const
|
|
{
|
|
if (m_description) {
|
|
return m_description->text();
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
QStringList SettingsControl::keywords() const
|
|
{
|
|
return m_keywords;
|
|
}
|
|
|
|
QString SettingsControl::option() const
|
|
{
|
|
return m_option;
|
|
}
|
|
|
|
bool SettingsControl::setSearchTerm(QString search)
|
|
{
|
|
bool inSearch = false;
|
|
// only show matches when search string is at least three characters,
|
|
// to avoid many hits when the user starts typing
|
|
if (search.length() > 2) {
|
|
Q_FOREACH(QString k, m_keywords) {
|
|
if (k.indexOf(search, 0, Qt::CaseInsensitive) >= 0) {
|
|
inSearch = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
setProperty("search-result", inSearch);
|
|
update();
|
|
return inSearch;
|
|
}
|
|
|
|
bool SettingsControl::qmlVisible() const
|
|
{
|
|
return m_localVisible;
|
|
}
|
|
|
|
void SettingsControl::setAdvanced(bool advanced)
|
|
{
|
|
if (m_advanced == advanced)
|
|
return;
|
|
|
|
m_advanced = advanced;
|
|
emit advancedChanged(advanced);
|
|
}
|
|
|
|
void SettingsControl::setDescription(QString desc)
|
|
{
|
|
if (m_description) {
|
|
m_description->setText(desc);
|
|
}
|
|
emit descriptionChanged();
|
|
}
|
|
|
|
void SettingsControl::apply(LaunchConfig *lconfig) const
|
|
{
|
|
Q_UNUSED(lconfig)
|
|
}
|
|
|
|
void SettingsControl::setKeywords(QStringList keywords)
|
|
{
|
|
if (m_keywords == keywords)
|
|
return;
|
|
|
|
m_keywords = keywords;
|
|
emit keywordsChanged(keywords);
|
|
}
|
|
|
|
void SettingsControl::setOption(QString option)
|
|
{
|
|
if (m_option == option)
|
|
return;
|
|
|
|
m_option = option;
|
|
emit optionChanged(option);
|
|
}
|
|
|
|
void SettingsControl::setQmlVisible(bool visible)
|
|
{
|
|
if (m_localVisible == visible)
|
|
return;
|
|
|
|
m_localVisible = visible;
|
|
SettingsSection* section = qobject_cast<SettingsSection*>(parent());
|
|
updateWidgetVisibility(section->showAdvanced());
|
|
emit qmlVisibleChanged(visible);
|
|
}
|
|
|
|
SettingsControl::SettingsControl(QWidget *pr) :
|
|
QWidget(pr)
|
|
{
|
|
}
|
|
|
|
void SettingsControl::createDescription()
|
|
{
|
|
m_description = new QLabel(this);
|
|
m_description->setWordWrap(true);
|
|
QFont f = m_description->font();
|
|
f.setPointSize(f.pointSize() - 2);
|
|
m_description->setFont(f);
|
|
}
|
|
|
|
QString SettingsControl::qmlName() const
|
|
{
|
|
QQmlContext* context = QQmlEngine::contextForObject(this);
|
|
QString s = context->nameForObject(const_cast<SettingsControl*>(this));
|
|
return s;
|
|
}
|
|
|
|
void SettingsControl::paintEvent(QPaintEvent *pe)
|
|
{
|
|
QWidget::paintEvent(pe);
|
|
|
|
if (property("search-result").toBool()) {
|
|
QPainter painter(this);
|
|
painter.setRenderHints(QPainter::Antialiasing);
|
|
QPen pen(QColor("#7f7f7fff"), 1);
|
|
painter.setPen(pen);
|
|
painter.setBrush(QColor("#2f7f7fff"));
|
|
painter.drawRoundedRect(rect(), 8, 8);
|
|
}
|
|
}
|
|
|
|
void SettingsControl::updateWidgetVisibility(bool showAdvanced)
|
|
{
|
|
if (advanced()) {
|
|
setVisible(m_localVisible & showAdvanced);
|
|
} else if (property("simple").toBool()) {
|
|
setVisible(m_localVisible & !showAdvanced);
|
|
} else {
|
|
setVisible(m_localVisible);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
SettingsCheckbox::SettingsCheckbox(QWidget* parent) :
|
|
SettingsControl(parent)
|
|
{
|
|
QVBoxLayout* vbox = new QVBoxLayout(this);
|
|
vbox->setMargin(MARGIN_HINT);
|
|
setLayout(vbox);
|
|
m_check = new QCheckBox(this);
|
|
vbox->addWidget(m_check);
|
|
createDescription();
|
|
vbox->addWidget(m_description);
|
|
connect(m_check, &QCheckBox::toggled, this, &SettingsCheckbox::checkedChanged);
|
|
}
|
|
|
|
QString SettingsCheckbox::label() const
|
|
{
|
|
return m_check->text();
|
|
}
|
|
|
|
bool SettingsCheckbox::isChecked() const
|
|
{
|
|
return m_check->isChecked();
|
|
}
|
|
|
|
void SettingsCheckbox::setChecked(bool checked)
|
|
{
|
|
if (checked == isChecked()) {
|
|
return;
|
|
}
|
|
|
|
m_check->setChecked(checked);
|
|
emit checkedChanged(checked);
|
|
}
|
|
|
|
void SettingsCheckbox::setLabel(QString label)
|
|
{
|
|
m_check->setText(label);
|
|
}
|
|
|
|
void SettingsCheckbox::apply(LaunchConfig* lconfig) const
|
|
{
|
|
if (option().isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
lconfig->setEnableDisableOption(option(), isChecked());
|
|
}
|
|
|
|
void SettingsCheckbox::saveState(QSettings &settings) const
|
|
{
|
|
settings.setValue(qmlName(), isChecked());
|
|
}
|
|
|
|
void SettingsCheckbox::restoreState(QSettings &settings)
|
|
{
|
|
setChecked(settings.value(qmlName(), isChecked()).toBool());
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
SettingsComboBox::SettingsComboBox(QWidget *pr) :
|
|
SettingsControl(pr)
|
|
{
|
|
QVBoxLayout* vbox = new QVBoxLayout(this);
|
|
setLayout(vbox);
|
|
vbox->setMargin(MARGIN_HINT);
|
|
|
|
QHBoxLayout* hbox = new QHBoxLayout;
|
|
hbox->setMargin(MARGIN_HINT);
|
|
|
|
vbox->addLayout(hbox);
|
|
m_combo = new QComboBox(this);
|
|
|
|
m_label = new QLabel(this);
|
|
hbox->addWidget(m_label);
|
|
hbox->addWidget(m_combo);
|
|
hbox->addStretch(1);
|
|
|
|
createDescription();
|
|
vbox->addWidget(m_description);
|
|
|
|
connect(m_combo, SIGNAL(currentIndexChanged(int)),
|
|
this, SIGNAL(selectedIndexChanged(int)));
|
|
}
|
|
|
|
QStringList SettingsComboBox::choices() const
|
|
{
|
|
QStringList result;
|
|
for (int i=0; i < m_combo->count(); ++i) {
|
|
result.append(m_combo->itemText(i));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int SettingsComboBox::selectedIndex() const
|
|
{
|
|
return m_combo->currentIndex();
|
|
}
|
|
|
|
void SettingsComboBox::saveState(QSettings &settings) const
|
|
{
|
|
// if selected index is custom, need to save something else?
|
|
if (selectedIndex() == m_defaultIndex) {
|
|
settings.remove(qmlName());
|
|
} else {
|
|
settings.setValue(qmlName(), selectedIndex());
|
|
}
|
|
}
|
|
|
|
void SettingsComboBox::restoreState(QSettings &settings)
|
|
{
|
|
QString id = qmlName();
|
|
setSelectedIndex(settings.value(id, m_defaultIndex).toInt());
|
|
}
|
|
|
|
void SettingsComboBox::setChoices(QStringList aChoices)
|
|
{
|
|
if (choices() == aChoices)
|
|
return;
|
|
|
|
m_combo->clear();
|
|
Q_FOREACH (QString choice, aChoices) {
|
|
m_combo->addItem(choice);
|
|
}
|
|
|
|
emit choicesChanged(aChoices);
|
|
}
|
|
|
|
void SettingsComboBox::setSelectedIndex(int selectedIndex)
|
|
{
|
|
if (m_combo->currentIndex() == selectedIndex)
|
|
return;
|
|
|
|
m_combo->setCurrentIndex(selectedIndex);
|
|
emit selectedIndexChanged(selectedIndex);
|
|
}
|
|
|
|
void SettingsComboBox::setLabel(QString label)
|
|
{
|
|
m_label->setText(label);
|
|
emit labelChanged();
|
|
}
|
|
|
|
|
|
QAbstractItemModel *SettingsComboBox::model() const
|
|
{
|
|
return m_combo->model();
|
|
}
|
|
|
|
int SettingsComboBox::defaultIndex() const
|
|
{
|
|
return m_defaultIndex;
|
|
}
|
|
|
|
void SettingsComboBox::setModel(QAbstractItemModel *model)
|
|
{
|
|
if (model == m_combo->model()) {
|
|
return;
|
|
}
|
|
|
|
m_combo->setModel(model);
|
|
emit modelChanged(model);
|
|
}
|
|
|
|
void SettingsComboBox::setDefaultIndex(int defaultIndex)
|
|
{
|
|
if (m_defaultIndex == defaultIndex)
|
|
return;
|
|
|
|
m_defaultIndex = defaultIndex;
|
|
emit defaultIndexChanged(defaultIndex);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
SettingsIntSpinbox::SettingsIntSpinbox(QWidget *pr) :
|
|
SettingsControl(pr)
|
|
{
|
|
QVBoxLayout* vbox = new QVBoxLayout(this);
|
|
vbox->setMargin(MARGIN_HINT);
|
|
setLayout(vbox);
|
|
|
|
QHBoxLayout* hbox = new QHBoxLayout;
|
|
hbox->setMargin(MARGIN_HINT);
|
|
|
|
vbox->addLayout(hbox);
|
|
m_spin = new QSpinBox(this);
|
|
|
|
m_label = new QLabel(this);
|
|
hbox->addWidget(m_label);
|
|
hbox->addWidget(m_spin);
|
|
hbox->addStretch(1);
|
|
|
|
createDescription();
|
|
vbox->addWidget(m_description);
|
|
|
|
connect(m_spin, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
|
|
}
|
|
|
|
int SettingsIntSpinbox::value() const
|
|
{
|
|
return m_spin->value();
|
|
}
|
|
|
|
int SettingsIntSpinbox::min() const
|
|
{
|
|
return m_spin->minimum();
|
|
}
|
|
|
|
int SettingsIntSpinbox::max() const
|
|
{
|
|
return m_spin->maximum();
|
|
}
|
|
|
|
void SettingsIntSpinbox::apply(LaunchConfig *lconfig) const
|
|
{
|
|
if (option().isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
lconfig->setArg(option(), QString::number(value()));
|
|
}
|
|
|
|
void SettingsIntSpinbox::saveState(QSettings &settings) const
|
|
{
|
|
settings.setValue(qmlName(), value());
|
|
}
|
|
|
|
void SettingsIntSpinbox::restoreState(QSettings &settings)
|
|
{
|
|
setValue(settings.value(qmlName(), value()).toInt());
|
|
}
|
|
|
|
void SettingsIntSpinbox::setValue(int aValue)
|
|
{
|
|
if (value() == aValue)
|
|
return;
|
|
|
|
m_spin->setValue(aValue);
|
|
emit valueChanged(aValue);
|
|
}
|
|
|
|
void SettingsIntSpinbox::setMin(int aMin)
|
|
{
|
|
if (min() == aMin)
|
|
return;
|
|
|
|
m_spin->setMinimum(aMin);
|
|
emit minChanged(aMin);
|
|
}
|
|
|
|
void SettingsIntSpinbox::setMax(int aMax)
|
|
{
|
|
if (max() == aMax)
|
|
return;
|
|
|
|
m_spin->setMaximum(aMax);
|
|
emit maxChanged(aMax);
|
|
}
|
|
|
|
void SettingsIntSpinbox::setLabel(QString label)
|
|
{
|
|
m_label->setText(label);
|
|
emit labelChanged();
|
|
}
|
|
|
|
SettingsText::SettingsText(QWidget *pr) :
|
|
SettingsControl(pr)
|
|
{
|
|
QVBoxLayout* vbox = new QVBoxLayout(this);
|
|
vbox->setMargin(MARGIN_HINT);
|
|
setLayout(vbox);
|
|
|
|
QHBoxLayout* hbox = new QHBoxLayout;
|
|
hbox->setMargin(MARGIN_HINT);
|
|
vbox->addLayout(hbox);
|
|
m_edit = new QLineEdit(this);
|
|
|
|
m_label = new QLabel(this);
|
|
hbox->addWidget(m_label);
|
|
hbox->addWidget(m_edit, 1);
|
|
// hbox->addStretch(1);
|
|
|
|
createDescription();
|
|
vbox->addWidget(m_description);
|
|
|
|
connect(m_edit, &QLineEdit::textChanged, this, &SettingsText::valueChanged);
|
|
}
|
|
|
|
QString SettingsText::value() const
|
|
{
|
|
return m_edit->text();
|
|
}
|
|
|
|
void SettingsText::apply(LaunchConfig *lconfig) const
|
|
{
|
|
if (option().isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
lconfig->setArg(option(), value());
|
|
}
|
|
|
|
void SettingsText::saveState(QSettings &settings) const
|
|
{
|
|
settings.setValue(qmlName(), value());
|
|
}
|
|
|
|
void SettingsText::restoreState(QSettings &settings)
|
|
{
|
|
setValue(settings.value(qmlName(), value()).toString());
|
|
}
|
|
|
|
void SettingsText::setLabel(QString label)
|
|
{
|
|
m_label->setText(label);
|
|
}
|
|
|
|
void SettingsText::setValue(QString newVal)
|
|
{
|
|
if (value() == newVal)
|
|
return;
|
|
|
|
m_edit->setText(newVal);
|
|
emit valueChanged(newVal);
|
|
}
|
|
|
|
QString SettingsText::placeholder() const
|
|
{
|
|
return m_edit->placeholderText();
|
|
}
|
|
|
|
QString SettingsText::validation() const
|
|
{
|
|
return m_validation;
|
|
}
|
|
|
|
void SettingsText::setPlaceholder(QString hold)
|
|
{
|
|
if (placeholder() == hold)
|
|
return;
|
|
|
|
m_edit->setPlaceholderText(hold);
|
|
emit placeholderChanged(hold);
|
|
}
|
|
|
|
void SettingsText::setValidation(QString validation)
|
|
{
|
|
if (m_validation == validation)
|
|
return;
|
|
|
|
m_validation = validation;
|
|
|
|
QRegularExpression re(m_validation);
|
|
if (!re.isValid()) {
|
|
qWarning() << "invalid validation expression:" << re.errorString();
|
|
m_validation.clear();
|
|
validation.clear();
|
|
m_edit->setValidator(nullptr);
|
|
} else {
|
|
m_edit->setValidator(new QRegularExpressionValidator(re, this));
|
|
}
|
|
|
|
emit validationChanged(validation);
|
|
}
|
|
|
|
SettingsPath::SettingsPath(QWidget *pr) :
|
|
SettingsControl(pr)
|
|
{
|
|
QVBoxLayout* vbox = new QVBoxLayout(this);
|
|
vbox->setMargin(MARGIN_HINT);
|
|
setLayout(vbox);
|
|
|
|
QHBoxLayout* hbox = new QHBoxLayout;
|
|
hbox->setMargin(MARGIN_HINT);
|
|
vbox->addLayout(hbox);
|
|
|
|
m_changeButton = new QPushButton(tr("Change"), this);
|
|
connect(m_changeButton, &QPushButton::clicked, this, &SettingsPath::choosePath);
|
|
|
|
m_defaultButton = new QPushButton(tr("Default"), this);
|
|
connect(m_defaultButton, &QPushButton::clicked, this, &SettingsPath::restoreDefaultPath);
|
|
|
|
m_label = new QLabel(this);
|
|
hbox->addWidget(m_label, 1);
|
|
hbox->addWidget(m_changeButton);
|
|
hbox->addWidget(m_defaultButton);
|
|
|
|
createDescription();
|
|
vbox->addWidget(m_description);
|
|
}
|
|
|
|
QString SettingsPath::path() const
|
|
{
|
|
return m_path;
|
|
}
|
|
|
|
void SettingsPath::setPath(QString path)
|
|
{
|
|
if (m_path == path)
|
|
return;
|
|
|
|
m_path = path;
|
|
emit pathChanged(path);
|
|
updateLabel();
|
|
}
|
|
|
|
void SettingsPath::setLabel(QString label)
|
|
{
|
|
m_labelPrefix = label;
|
|
updateLabel();
|
|
}
|
|
|
|
void SettingsPath::apply(LaunchConfig *lconfig) const
|
|
{
|
|
if (m_option.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
if (m_path.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
lconfig->setArg(option(), path());
|
|
}
|
|
|
|
void SettingsPath::setDefaultPath(QString path)
|
|
{
|
|
if (m_defaultPath == path)
|
|
return;
|
|
|
|
m_defaultPath = path;
|
|
m_defaultButton->setVisible(!m_defaultPath.isEmpty());
|
|
emit defaultPathChanged(path);
|
|
updateLabel();
|
|
}
|
|
|
|
void SettingsPath::setChooseDirectory(bool chooseDirectory)
|
|
{
|
|
if (m_chooseDirectory == chooseDirectory)
|
|
return;
|
|
|
|
m_chooseDirectory = chooseDirectory;
|
|
emit chooseDirectoryChanged(chooseDirectory);
|
|
}
|
|
|
|
void SettingsPath::choosePath()
|
|
{
|
|
QString path;
|
|
if (m_chooseDirectory) {
|
|
path = QFileDialog::getExistingDirectory(this,
|
|
m_dialogPrompt,
|
|
m_path);
|
|
} else {
|
|
// if we're going to use this, add filter support
|
|
path = QFileDialog::getOpenFileName(this, m_dialogPrompt, m_path);
|
|
}
|
|
|
|
if (path.isEmpty()) {
|
|
return; // user cancelled
|
|
}
|
|
setPath(path);
|
|
}
|
|
|
|
void SettingsPath::restoreDefaultPath()
|
|
{
|
|
setPath(QString());
|
|
}
|
|
|
|
void SettingsPath::setDialogPrompt(QString dialogPrompt)
|
|
{
|
|
if (m_dialogPrompt == dialogPrompt)
|
|
return;
|
|
|
|
m_dialogPrompt = dialogPrompt;
|
|
emit dialogPromptChanged(dialogPrompt);
|
|
}
|
|
|
|
void SettingsPath::setOption(QString option)
|
|
{
|
|
if (m_option == option)
|
|
return;
|
|
|
|
m_option = option;
|
|
emit optionChanged(option);
|
|
}
|
|
|
|
void SettingsPath::updateLabel()
|
|
{
|
|
const bool isDefault = (m_path.isEmpty());
|
|
QString s = isDefault ? tr("%1: %2 (default)") : tr("%1: %2");
|
|
QString path = isDefault ? defaultPath() : m_path;
|
|
m_label->setText(s.arg(m_labelPrefix).arg(path));
|
|
m_defaultButton->setEnabled(!isDefault);
|
|
}
|
|
|
|
void SettingsPath::saveState(QSettings &settings) const
|
|
{
|
|
settings.setValue(qmlName(), m_path);
|
|
}
|
|
|
|
void SettingsPath::restoreState(QSettings &settings)
|
|
{
|
|
QString s = settings.value(qmlName(), QString()).toString();
|
|
setPath(s);
|
|
}
|
|
|
|
SettingsDateTime::SettingsDateTime(QWidget *pr) :
|
|
SettingsControl(pr)
|
|
{
|
|
QVBoxLayout* vbox = new QVBoxLayout(this);
|
|
vbox->setMargin(MARGIN_HINT);
|
|
setLayout(vbox);
|
|
|
|
QHBoxLayout* hbox = new QHBoxLayout;
|
|
hbox->setMargin(MARGIN_HINT);
|
|
vbox->addLayout(hbox);
|
|
|
|
m_edit = new QDateTimeEdit;
|
|
m_label = new QLabel(this);
|
|
hbox->addWidget(m_label);
|
|
hbox->addWidget(m_edit);
|
|
hbox->addStretch(1);
|
|
|
|
createDescription();
|
|
vbox->addWidget(m_description);
|
|
}
|
|
|
|
void SettingsDateTime::saveState(QSettings &settings) const
|
|
{
|
|
settings.setValue(qmlName(), value());
|
|
}
|
|
|
|
void SettingsDateTime::restoreState(QSettings &settings)
|
|
{
|
|
m_edit->setDateTime(settings.value(qmlName()).toDateTime());
|
|
}
|
|
|
|
void SettingsDateTime::setLabel(QString label)
|
|
{
|
|
m_label->setText(label);
|
|
}
|
|
|
|
QDateTime SettingsDateTime::value() const
|
|
{
|
|
return m_edit->dateTime();
|
|
}
|
|
|
|
void SettingsDateTime::setValue(QDateTime value)
|
|
{
|
|
if (m_edit->dateTime() == value) {
|
|
|
|
}
|
|
|
|
emit valueChanged(value);
|
|
}
|
|
|