File indexing completed on 2024-05-19 05:42:18
0001 // ct_lvtqtc_inputdialog.cpp -*-C++-*- 0002 0003 /* 0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0005 // SPDX-License-Identifier: Apache-2.0 0006 // 0007 // Licensed under the Apache License, Version 2.0 (the "License"); 0008 // you may not use this file except in compliance with the License. 0009 // You may obtain a copy of the License at 0010 // 0011 // http://www.apache.org/licenses/LICENSE-2.0 0012 // 0013 // Unless required by applicable law or agreed to in writing, software 0014 // distributed under the License is distributed on an "AS IS" BASIS, 0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0016 // See the License for the specific language governing permissions and 0017 // limitations under the License. 0018 */ 0019 0020 #include <ct_lvtqtc_inputdialog.h> 0021 0022 #include <QComboBox> 0023 #include <QDialogButtonBox> 0024 #include <QFormLayout> 0025 #include <QLineEdit> 0026 #include <QShowEvent> 0027 #include <QSpinBox> 0028 0029 using namespace Codethink::lvtqtc; 0030 0031 struct InputDialog::Private { 0032 std::map<QByteArray, QWidget *> entities; 0033 QFormLayout *mainLayout = nullptr; 0034 QDialogButtonBox *buttonBox = nullptr; 0035 QWidget *firstWidget = nullptr; 0036 bool finishedBuild = false; 0037 bool justShown = false; 0038 std::function<bool(void)> doExec; 0039 }; 0040 0041 InputDialog::InputDialog(const QString& title, QWidget *parent): 0042 QDialog(parent), d(std::make_unique<InputDialog::Private>()) 0043 { 0044 setWindowFlags(Qt::Tool | Qt::CustomizeWindowHint | Qt::WindowTitleHint); 0045 0046 d->mainLayout = new QFormLayout(); 0047 setWindowTitle(title); 0048 0049 d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0050 connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 0051 connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0052 } 0053 0054 InputDialog::~InputDialog() = default; 0055 0056 void InputDialog::prepareFields(const std::vector<std::pair<QByteArray, QString>>& fields) 0057 { 0058 for (const auto& [fieldId, labelText] : fields) { 0059 addTextField(fieldId, labelText); 0060 } 0061 finish(); 0062 } 0063 0064 void InputDialog::setTextFieldValue(const QByteArray& fieldId, const QString& value) 0065 { 0066 auto *lineEdit = qobject_cast<QLineEdit *>(d->entities.at(fieldId)); 0067 lineEdit->setText(value); 0068 } 0069 0070 void InputDialog::addTextField(const QByteArray& fieldId, const QString& labelText) 0071 { 0072 auto *textField = new QLineEdit(); 0073 0074 // HACK: Qt is always selecting the text, it doesn't matter how I 0075 // ask it to deselect. this is needed so the user doesn't remove 0076 // the parent name on a mistype. 0077 connect(textField, &QLineEdit::selectionChanged, this, [this, textField] { 0078 if (d->justShown) { 0079 textField->deselect(); 0080 d->justShown = false; 0081 } 0082 }); 0083 0084 textField->setObjectName(fieldId); 0085 registerField(fieldId, labelText, textField); 0086 } 0087 0088 void InputDialog::addComboBoxField(const QByteArray& fieldId, 0089 const QString& labelText, 0090 const std::vector<QString>& options) 0091 { 0092 auto *combobox = new QComboBox(); 0093 combobox->setObjectName(fieldId); 0094 for (const auto& v : options) { 0095 combobox->addItem(v); 0096 } 0097 registerField(fieldId, labelText, combobox); 0098 } 0099 0100 void InputDialog::addSpinBoxField(const QByteArray& fieldId, 0101 const QString& labelText, 0102 std::pair<int, int> minMax, 0103 int value) 0104 { 0105 auto *spinbox = new QSpinBox(); 0106 spinbox->setObjectName(fieldId); 0107 spinbox->setMinimum(minMax.first); 0108 spinbox->setMaximum(minMax.second); 0109 spinbox->setValue(value); 0110 registerField(fieldId, labelText, spinbox); 0111 } 0112 0113 void InputDialog::finish() 0114 { 0115 assert(!d->finishedBuild && "finish() called twice"); 0116 d->mainLayout->addWidget(d->buttonBox); 0117 d->finishedBuild = true; 0118 0119 setLayout(d->mainLayout); 0120 adjustSize(); 0121 setFixedSize(size()); 0122 } 0123 0124 void InputDialog::registerField(const QByteArray& fieldId, const QString& labelText, QWidget *widget) 0125 { 0126 assert(!d->finishedBuild && "Cannot add more fields after finish() was called"); 0127 0128 auto *labelWidget = new QLabel(labelText); 0129 d->mainLayout->addWidget(labelWidget); 0130 d->mainLayout->addWidget(widget); 0131 d->entities[fieldId] = widget; 0132 if (!d->firstWidget) { 0133 d->firstWidget = widget; 0134 } 0135 } 0136 0137 std::any InputDialog::fieldValue(const QByteArray& fieldId) const 0138 { 0139 assert(d->entities.count(fieldId) != 0); 0140 0141 auto className = std::string(d->entities[fieldId]->metaObject()->className()); 0142 if (className == "QLineEdit") { 0143 return std::make_any<QString>(qobject_cast<QLineEdit *>(d->entities[fieldId])->text()); 0144 } 0145 if (className == "QComboBox") { 0146 return std::make_any<QString>(qobject_cast<QComboBox *>(d->entities[fieldId])->currentText()); 0147 } 0148 if (className == "QSpinBox") { 0149 return std::make_any<int>(qobject_cast<QSpinBox *>(d->entities[fieldId])->value()); 0150 } 0151 0152 assert(false && "Unkwnown data type"); 0153 return ""; 0154 } 0155 0156 void InputDialog::showEvent(QShowEvent *ev) 0157 { 0158 QDialog::showEvent(ev); 0159 d->justShown = true; 0160 if (d->firstWidget) { 0161 d->firstWidget->setFocus(Qt::MouseFocusReason); 0162 if (auto *lineEdit = qobject_cast<QLineEdit *>(d->firstWidget)) { 0163 lineEdit->deselect(); 0164 } 0165 } 0166 } 0167 0168 void InputDialog::overrideExec(std::function<bool(void)> exec) 0169 { 0170 d->doExec = std::move(exec); 0171 } 0172 0173 int InputDialog::exec() 0174 { 0175 if (d->doExec) { 0176 return d->doExec(); 0177 } 0178 return QDialog::exec(); 0179 }