#include "core/ConfigStore.h"
#include "ui/SchemeDialogs.h"
#include <QAbstractButton>
#include <QDialogButtonBox>
#include <QFrame>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QMessageBox>
#include <QPushButton>
#include <QVBoxLayout>
namespace whittle {
namespace {
constexpr char kHeadStyle[] = "color: #999999; font-size: 8pt;";
constexpr char kRuleStyle[] = "color: #cccccc; background-color: #cccccc;";
constexpr char kSheet[] =
"QDialog { background: #F4F4F4; }"
"QPushButton { border: 1px solid #c1c1c1; border-radius: 4px;"
" padding: 0 12px; min-height: 24px; max-height: 24px;"
" background: #F9F9F9; color: #000000; }"
"QPushButton:hover { background: #F1F1F1; }"
"QPushButton:pressed { background: #F4F4F4; }"
"QLineEdit { border: 1px solid #c1c1c1; border-radius: 4px;"
" padding: 6px; background: #FAFAFA; color: #222222; }"
"QListWidget { border: 1px solid #c1c1c1; border-radius: 4px;"
" background: #FAFAFA; color: #222222; outline: none; }"
"QListWidget::item { padding: 3px 6px; border: none; }"
"QListWidget::item:selected { padding: 3px 6px; border: none;"
" background: #E5E5E5; color: #222222; }";
constexpr int kHeadGap = 4;
constexpr int kBlockGap = 8;
constexpr int kActionGap = 6;
QWidget* sectionHeader(const QString& title) {
auto* w = new QWidget;
auto* h = new QHBoxLayout(w);
h->setContentsMargins(0, 0, 0, 0);
h->setSpacing(8);
auto* label = new QLabel(title);
label->setStyleSheet(QLatin1String(kHeadStyle));
label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
h->addWidget(label);
auto* hr = new QFrame;
hr->setFrameShape(QFrame::HLine);
hr->setFrameShadow(QFrame::Plain);
hr->setStyleSheet(QLatin1String(kRuleStyle));
hr->setFixedHeight(1);
hr->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
h->addWidget(hr, 1);
return w;
}
QMessageBox::StandardButton askYesNo(QWidget* parent, const QString& title,
const QString& text) {
QMessageBox box(QMessageBox::Question, title, text,
QMessageBox::Yes | QMessageBox::No, parent);
box.setDefaultButton(QMessageBox::No);
for (QAbstractButton* b : box.buttons()) b->setIcon(QIcon());
box.exec();
return box.standardButton(box.clickedButton());
}
}
SaveSchemeDialog::SaveSchemeDialog(const QStringList& existing, bool allowSave,
QWidget* parent)
: QDialog(parent), m_existing(existing), m_allowSave(allowSave) {
setWindowTitle(tr("Schemes"));
setModal(true);
resize(333, 280);
setStyleSheet(QLatin1String(kSheet));
auto* v = new QVBoxLayout(this);
v->setContentsMargins(16, 14, 16, 14);
v->setSpacing(0);
m_edit = new QLineEdit;
m_edit->setEnabled(allowSave);
m_edit->setPlaceholderText(allowSave ? tr("Moniker")
: tr("Nothing to save!"));
v->addWidget(m_edit);
v->addSpacing(kBlockGap);
m_list = new QListWidget;
m_list->addItems(existing);
v->addWidget(m_list, 1);
v->addSpacing(kActionGap);
m_del = new QPushButton(tr("Delete"));
m_del->setEnabled(false);
auto* buttons = new QDialogButtonBox(
QDialogButtonBox::Save | QDialogButtonBox::Cancel);
for (QAbstractButton* b : buttons->buttons()) b->setIcon(QIcon());
m_ok = buttons->button(QDialogButtonBox::Save);
m_ok->setEnabled(false);
int btnW = 0;
for (QAbstractButton* b : buttons->buttons()) {
btnW = qMax(btnW, b->sizeHint().width());
if (auto* p = qobject_cast<QPushButton*>(b)) p->setAutoDefault(false);
}
m_del->setMinimumWidth(btnW);
auto* buttonRow = new QHBoxLayout;
buttonRow->setContentsMargins(0, 0, 0, 0);
buttonRow->addWidget(m_del);
buttonRow->addStretch();
buttonRow->addWidget(buttons);
v->addLayout(buttonRow);
connect(m_edit, &QLineEdit::textChanged, this, &SaveSchemeDialog::validate);
connect(m_list, &QListWidget::itemClicked, this, [this](QListWidgetItem* i) {
if (m_allowSave && i) m_edit->setText(i->text());
});
connect(m_list, &QListWidget::currentRowChanged,
this, [this](int row) { m_del->setEnabled(row >= 0); });
connect(m_del, &QPushButton::clicked, this, &SaveSchemeDialog::onDelete);
connect(buttons, &QDialogButtonBox::accepted, this, &SaveSchemeDialog::tryAccept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
void SaveSchemeDialog::validate() {
m_ok->setEnabled(m_allowSave && !m_edit->text().trimmed().isEmpty());
}
void SaveSchemeDialog::onDelete() {
auto* item = m_list->currentItem();
if (!item) return;
const QString name = item->text();
const auto btn = askYesNo(this, tr("Delete"), tr("Delete \"%1\"?").arg(name));
if (btn != QMessageBox::Yes) return;
if (!ConfigStore::deleteScheme(name)) {
QMessageBox::warning(this, tr("Delete"),
tr("Could not delete \"%1\".").arg(name));
return;
}
delete m_list->takeItem(m_list->row(item));
m_existing.removeAll(name);
m_listChanged = true;
m_del->setEnabled(m_list->currentRow() >= 0);
}
void SaveSchemeDialog::tryAccept() {
const QString name = schemeName();
if (name.isEmpty()) return;
if (m_existing.contains(name)) {
const auto btn = askYesNo(this, tr("Over-Write?"),
tr("\"%1\" already exists.").arg(name));
if (btn != QMessageBox::Yes) return;
}
accept();
}
QString SaveSchemeDialog::schemeName() const {
return m_edit->text().trimmed();
}
}