/* * Copyright 2016-2017 gtalent2@gmail.com * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include "wizard.hpp" namespace nostalgia { namespace studio { using std::function; WizardSelect::WizardSelect() { m_listWidget = new QListWidget(this); auto layout = new QVBoxLayout(this); layout->addWidget(m_listWidget); setLayout(layout); connect(m_listWidget, &QListWidget::currentRowChanged, this, &WizardSelect::itemSelected); connect(m_listWidget, &QListWidget::itemSelectionChanged, [this]() { m_complete = true; emit completeChanged(); } ); connect(m_listWidget, &QListWidget::doubleClicked, [this]() { wizard()->next(); } ); } void WizardSelect::initializePage() { emit completeChanged(); } void WizardSelect::addOption(QString name, function()> makePage) { m_options[name] = makePage; m_listWidget->addItem(name); } bool WizardSelect::isComplete() const { return m_complete; } void WizardSelect::itemSelected(int row) { if (row > -1) { auto w = wizard(); if (nextId() > -1) { w->removePage(nextId()); } auto selected = m_listWidget->currentItem()->text(); if (m_options.contains(selected)) { for (auto p : m_options[selected]()) { w->addPage(p); } // for some reason the continue button only appears correctly after remove runs w->removePage(w->addPage(new QWizardPage())); } } } WizardConclusionPage::WizardConclusionPage(QString msg, QVector fields) { m_baseMsg = msg; m_fields = fields; setLayout(new QVBoxLayout(this)); } WizardConclusionPage::~WizardConclusionPage() { } void WizardConclusionPage::initializePage() { QString msg = m_baseMsg; for (auto field : m_fields) { msg = msg.arg(this->field(field).toString()); } auto text = new QLabel(msg, this); if (m_text) { layout()->replaceWidget(m_text, text); delete m_text; } else { layout()->addWidget(text); } m_text = text; } void WizardFormPage::Field::setDisplayText(QString text) { auto le = dynamic_cast(this->valueControl); auto cb = dynamic_cast(this->valueControl); if (le) { le->setText(text); } else if (cb) { cb->setCurrentText(text); } } QString WizardFormPage::Field::getDisplayText() { auto le = dynamic_cast(this->valueControl); auto cb = dynamic_cast(this->valueControl); if (le) { return le->text(); } else if (cb) { return cb->currentText(); } else { return ""; } } WizardFormPage::WizardFormPage() { m_layout = new QGridLayout(this); m_layout->setColumnMinimumWidth(0, 20); this->setLayout(m_layout); } WizardFormPage::~WizardFormPage() { for (auto l : m_subLayout) { delete l; } } int WizardFormPage::accept() { return 0; } void WizardFormPage::initializePage() { for (auto it = m_fields.begin(); it != m_fields.end(); it++) { auto key = it.key(); auto defaultVal = it.value().defaultValue; m_fields[key].setDisplayText(defaultVal); } } bool WizardFormPage::validatePage() { bool retval = true; // check validators for (auto f : m_fields) { if (f.validator != nullptr) { if (f.validator(f.getDisplayText()) != 0) { retval = false; break; } } } // clear error if (retval) { showValidationError(""); } return retval; } void WizardFormPage::addComboBox(QString displayName, QString fieldName, QVector options) { auto lbl = new QLabel(displayName, this); auto cb = new QComboBox(this); lbl->setBuddy(cb); m_layout->addWidget(lbl, m_currentLine, 0); m_layout->addWidget(cb, m_currentLine, 1); auto field = &m_fields[fieldName]; field->valueControl = cb; registerField(fieldName, cb); for (auto o : options) { cb->addItem(o); } connect(cb, &QComboBox::currentTextChanged, [this, fieldName, cb, field](QString txt) { if (field->value == "" && txt != "") { m_validFields++; } else if (field->value != "" && txt == "") { m_validFields--; } field->value = txt; emit completeChanged(); } ); m_currentLine++; } void WizardFormPage::addLineEdit(QString displayName, QString fieldName, QString defaultVal, function validator) { auto lbl = new QLabel(displayName, this); auto le = new QLineEdit(this); lbl->setBuddy(le); m_layout->addWidget(lbl, m_currentLine, 0); m_layout->addWidget(le, m_currentLine, 1); auto field = &m_fields[fieldName]; field->defaultValue = defaultVal; field->valueControl = le; field->validator = validator; registerField(fieldName, le); connect(le, &QLineEdit::textChanged, [this, fieldName, le, field](QString txt) { if (field->value == "" && txt != "") { m_validFields++; } else if (field->value != "" && txt == "") { m_validFields--; } field->value = txt; emit completeChanged(); } ); m_currentLine++; } void WizardFormPage::addPathBrowse(QString displayName, QString fieldName, QString defaultVal, QFileDialog::FileMode fileMode, QString fileExtensions) { auto layout = new QHBoxLayout(); auto lbl = new QLabel(displayName, this); auto le = new QLineEdit("", this); auto btn = new QPushButton("Browse...", this); lbl->setBuddy(le); layout->addWidget(le); layout->addWidget(btn); m_layout->addWidget(lbl, m_currentLine, 0); m_layout->addLayout(layout, m_currentLine, 1); m_subLayout.push_back(layout); m_fields[fieldName].defaultValue = defaultVal; m_fields[fieldName].valueControl = le; m_fields[fieldName].validator = [this, fileMode](QString path) { if (fileMode == QFileDialog::Directory) { if (!QDir(path).exists()) { showValidationError(tr("Specified directory path does not exist.")); return 1; } else { return 0; } } else if (fileMode == QFileDialog::ExistingFile) { if (!QFile(path).exists()) { showValidationError(tr("Specified directory path does not exist.")); return 1; } else { return 0; } } else { return 2; } }; registerField(fieldName, le); connect(le, &QLineEdit::textChanged, [this, fieldName, le](QString txt) { if (m_fields[fieldName].value == "" && txt != "") { m_validFields++; } else if (m_fields[fieldName].value != "" && txt == "") { m_validFields--; } m_fields[fieldName].value = txt; emit completeChanged(); } ); connect(btn, &QPushButton::clicked, [this, defaultVal, le, fileMode, fileExtensions]() { auto dir = defaultVal; if (dir == "") { dir = QDir::homePath(); } if (fileMode == QFileDialog::Directory) { auto p = QFileDialog::getExistingDirectory(this, tr("Select Directory..."), dir); if (p != "") { le->setText(p); } } else if (fileMode == QFileDialog::ExistingFile) { auto p = QFileDialog::getOpenFileName(this, tr("Select File..."), dir, fileExtensions); if (p != "") { le->setText(p); } } } ); m_currentLine++; } void WizardFormPage::showValidationError(QString msg) { // create label if it is null if (!m_errorMsg) { m_errorMsg = new QLabel(this); m_layout->addWidget(m_errorMsg, m_currentLine, 0, m_currentLine, 2); // set text color auto pal = m_errorMsg->palette(); pal.setColor(m_errorMsg->backgroundRole(), Qt::red); pal.setColor(m_errorMsg->foregroundRole(), Qt::red); m_errorMsg->setPalette(pal); } // set message if (msg != "") { m_errorMsg->setText(tr("Error: ") + msg); } else { m_errorMsg->setText(""); } } Wizard::Wizard(QString windowTitle, QWidget *parent): QWizard(parent) { setWindowTitle(windowTitle); setModal(true); } void Wizard::setAccept(std::function acceptFunc) { m_acceptFunc = acceptFunc; } void Wizard::accept() { auto page = dynamic_cast(currentPage()); if (page == nullptr || page->accept() == 0) { QDialog::accept(); } else if(m_acceptFunc != nullptr && m_acceptFunc() == 0) { QDialog::accept(); } } } }