From d795edb62f26cd2af5afe6dd1541e0b4ecbf0b0a Mon Sep 17 00:00:00 2001 From: Skycoder42 Date: Tue, 13 Feb 2018 18:18:21 +0100 Subject: [PATCH] added input dialog --- .travis.yml | 2 +- .../mvvmcore/SampleCore/samplecoreapp.cpp | 6 +- .../mvvmcore/SampleCore/sampleviewmodel.cpp | 18 +++ .../mvvmcore/SampleCore/sampleviewmodel.h | 2 + .../mvvmwidgets/SampleWidgets/sampleview.cpp | 4 + .../mvvmwidgets/SampleWidgets/sampleview.ui | 24 ++++ src/mvvmcore/message.cpp | 23 ++-- src/mvvmcore/message.h | 12 +- src/mvvmwidgets/fontcombobox.cpp | 9 ++ src/mvvmwidgets/fontcombobox_p.h | 25 ++++ src/mvvmwidgets/inputviewfactory.cpp | 85 ++++++++++++ src/mvvmwidgets/inputviewfactory.h | 41 ++++++ src/mvvmwidgets/inputviewfactory_p.h | 19 +++ src/mvvmwidgets/mvvmwidgets.pro | 11 +- src/mvvmwidgets/qpmx.json | 5 + src/mvvmwidgets/selectcombobox.cpp | 62 +++++++++ src/mvvmwidgets/selectcombobox_p.h | 38 +++++ src/mvvmwidgets/widgetspresenter.cpp | 130 +++++++++++++++--- src/mvvmwidgets/widgetspresenter.h | 16 ++- src/mvvmwidgets/widgetspresenter_p.h | 1 + 20 files changed, 486 insertions(+), 47 deletions(-) create mode 100644 src/mvvmwidgets/fontcombobox.cpp create mode 100644 src/mvvmwidgets/fontcombobox_p.h create mode 100644 src/mvvmwidgets/inputviewfactory.cpp create mode 100644 src/mvvmwidgets/inputviewfactory.h create mode 100644 src/mvvmwidgets/inputviewfactory_p.h create mode 100644 src/mvvmwidgets/selectcombobox.cpp create mode 100644 src/mvvmwidgets/selectcombobox_p.h diff --git a/.travis.yml b/.travis.yml index 5704b4a..8326e38 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,7 +48,7 @@ deploy: file_glob: true file: install/opt/build_*_$QT_VER.tar.xz on: - repo: + repo: Skycoder42/QtMvvm tags: true before_cache: diff --git a/examples/mvvmcore/SampleCore/samplecoreapp.cpp b/examples/mvvmcore/SampleCore/samplecoreapp.cpp index b8c76ff..d19effd 100644 --- a/examples/mvvmcore/SampleCore/samplecoreapp.cpp +++ b/examples/mvvmcore/SampleCore/samplecoreapp.cpp @@ -2,10 +2,14 @@ #include "sampleviewmodel.h" #include +#include SampleCoreApp::SampleCoreApp(QObject *parent) : CoreApp(parent) -{} +{ + QCoreApplication::setApplicationVersion(QStringLiteral(QTMVVMCORE_VERSION_STR)); + QCoreApplication::setOrganizationName(QStringLiteral("Skycoder42")); +} void SampleCoreApp::performRegistrations() { diff --git a/examples/mvvmcore/SampleCore/sampleviewmodel.cpp b/examples/mvvmcore/SampleCore/sampleviewmodel.cpp index f1cb321..425de2d 100644 --- a/examples/mvvmcore/SampleCore/sampleviewmodel.cpp +++ b/examples/mvvmcore/SampleCore/sampleviewmodel.cpp @@ -64,6 +64,16 @@ void SampleViewModel::setActive(bool active) emit activeChanged(_active); } +void SampleViewModel::getInput() +{ + QtMvvm::getInput(tr("Random input"), + tr("Enter a number:"), + this, [this](int res, bool ok) { + if(ok) + addEvent(QString::number(res)); + }, 42); +} + void SampleViewModel::getResult() { showForResult(ResCode, { @@ -81,6 +91,14 @@ void SampleViewModel::clearEvents() }); } +void SampleViewModel::about() +{ + QtMvvm::about(tr("QtMvvm sample application"), + QStringLiteral("https://github.com/Skycoder42/QtMvvm"), + tr("BSD 3 Clause"), + QStringLiteral("https://github.com/Skycoder42/QtMvvm/blob/master/LICENSE")); +} + void SampleViewModel::onInit(const QVariantHash ¶ms) { qInfo() << Q_FUNC_INFO << params; diff --git a/examples/mvvmcore/SampleCore/sampleviewmodel.h b/examples/mvvmcore/SampleCore/sampleviewmodel.h index 7561b7f..471d728 100644 --- a/examples/mvvmcore/SampleCore/sampleviewmodel.h +++ b/examples/mvvmcore/SampleCore/sampleviewmodel.h @@ -32,8 +32,10 @@ public Q_SLOTS: void setName(QString name); void setActive(bool active); + void getInput(); void getResult(); void clearEvents(); + void about(); Q_SIGNALS: void nameChanged(QString name); diff --git a/examples/mvvmwidgets/SampleWidgets/sampleview.cpp b/examples/mvvmwidgets/SampleWidgets/sampleview.cpp index 5403390..60ec154 100644 --- a/examples/mvvmwidgets/SampleWidgets/sampleview.cpp +++ b/examples/mvvmwidgets/SampleWidgets/sampleview.cpp @@ -22,6 +22,10 @@ SampleView::SampleView(QtMvvm::ViewModel *viewModel, QWidget *parent) : _viewModel, &SampleViewModel::clearEvents); connect(ui->resultButton, &QPushButton::clicked, _viewModel, &SampleViewModel::getResult); + connect(ui->action_About, &QAction::triggered, + _viewModel, &SampleViewModel::about); + connect(ui->actionUseless_Input, &QAction::triggered, + _viewModel, &SampleViewModel::getInput); } SampleView::~SampleView() diff --git a/examples/mvvmwidgets/SampleWidgets/sampleview.ui b/examples/mvvmwidgets/SampleWidgets/sampleview.ui index a7d3317..7641707 100644 --- a/examples/mvvmwidgets/SampleWidgets/sampleview.ui +++ b/examples/mvvmwidgets/SampleWidgets/sampleview.ui @@ -96,8 +96,32 @@ 23 + + + &Help + + + + + + &Actions + + + + + + + + &About + + + + + Another &Input + + diff --git a/src/mvvmcore/message.cpp b/src/mvvmcore/message.cpp index e39f0a3..8966582 100644 --- a/src/mvvmcore/message.cpp +++ b/src/mvvmcore/message.cpp @@ -381,21 +381,18 @@ MessageResult *QtMvvm::about(const QString &description, const QUrl &websiteUrl, text += pBegin; if(addQtVersion) { auto runtimeVers = qVersion(); - auto compileVers = QT_VERSION_STR; - QString qtVersion; - if(qstrcmp(runtimeVers, compileVers) == 0) - qtVersion = QString::fromUtf8(runtimeVers); - else { - qtVersion = MessageConfig::tr("%1 (Built with %2)") - .arg(QString::fromUtf8(runtimeVers)) - .arg(QString::fromUtf8(runtimeVers)); + QString postFix; + if(qstrcmp(runtimeVers, QT_VERSION_STR) != 0) { + postFix = MessageConfig::tr(" (Built with %1)") + .arg(QStringLiteral(QT_VERSION_STR)); } - text += MessageConfig::tr("Qt-Version: %2") - .arg(qtVersion); + text += MessageConfig::tr("Qt-Version: %1") + .arg(QString::fromUtf8(runtimeVers)) + + postFix; } if(!extraTopInfos.isEmpty()) { auto withBr = addQtVersion; - foreach(auto info, extraTopInfos){ + for(auto info : extraTopInfos) { text += info + (withBr ? br : QString()); withBr = true; } @@ -518,7 +515,7 @@ MessageResult *QtMvvm::getOpenFiles(const QString &title, const QStringList &sup return CoreApp::showDialog(config); } -void QtMvvm::getOpenFiles(QObject *scope, std::function)> onResult, const QString &title, const QStringList &supportedMimeTypes, const QUrl &dir) +void QtMvvm::getOpenFiles(QObject *scope, const std::function)> &onResult, const QString &title, const QStringList &supportedMimeTypes, const QUrl &dir) { auto result = getOpenFiles(title, supportedMimeTypes, dir); if(result) { @@ -529,7 +526,7 @@ void QtMvvm::getOpenFiles(QObject *scope, std::function)> onRe } } -void QtMvvm::getOpenFiles(std::function)> onResult, const QString &title, const QStringList &supportedMimeTypes, const QUrl &dir) +void QtMvvm::getOpenFiles(const std::function)> &onResult, const QString &title, const QStringList &supportedMimeTypes, const QUrl &dir) { getOpenFiles(CoreApp::instance(), onResult, title, supportedMimeTypes, dir); } diff --git a/src/mvvmcore/message.h b/src/mvvmcore/message.h index b9fb6d2..e143e0a 100644 --- a/src/mvvmcore/message.h +++ b/src/mvvmcore/message.h @@ -247,25 +247,25 @@ template inline void getInput(const QString &title, const QString &text, QObject *scope, - const std::function &onResult, + const std::function &onResult, const QVariant &defaultValue = {}, const QVariantMap &viewProperties = {}, const QString &okText = {}, const QString &cancelText = {}) { getInput(title, text, QMetaType::typeName(qMetaTypeId()), scope, [onResult](QVariant v) { - onResult(v.template value()); + onResult(v.template value(), v.isValid()); }, defaultValue, viewProperties, okText, cancelText); } template inline void getInput(const QString &title, const QString &text, - const std::function &onResult, + const std::function &onResult, const QVariant &defaultValue = {}, const QVariantMap &viewProperties = {}, const QString &okText = {}, const QString &cancelText = {}) { getInput(title, text, QMetaType::typeName(qMetaTypeId()), [onResult](QVariant v) { - onResult(v.template value()); + onResult(v.template value(), v.isValid()); }, defaultValue, viewProperties, okText, cancelText); } @@ -296,11 +296,11 @@ Q_MVVMCORE_EXPORT MessageResult *getOpenFiles(const QString &title = {}, const QStringList &supportedMimeTypes = {}, const QUrl &dir = {}); Q_MVVMCORE_EXPORT void getOpenFiles(QObject *scope, - std::function)> onResult, + const std::function)> &onResult, const QString &title = {}, const QStringList &supportedMimeTypes = {}, const QUrl &dir = {}); -Q_MVVMCORE_EXPORT void getOpenFiles(std::function)> onResult, +Q_MVVMCORE_EXPORT void getOpenFiles(const std::function)> &onResult, const QString &title = {}, const QStringList &supportedMimeTypes = {}, const QUrl &dir = {}); diff --git a/src/mvvmwidgets/fontcombobox.cpp b/src/mvvmwidgets/fontcombobox.cpp new file mode 100644 index 0000000..03437a3 --- /dev/null +++ b/src/mvvmwidgets/fontcombobox.cpp @@ -0,0 +1,9 @@ +#include "fontcombobox_p.h" +using namespace QtMvvm; + +FontComboBox::FontComboBox(QWidget *parent) : + QFontComboBox(parent) +{ + connect(this, &FontComboBox::currentFontChangedImp, + this, &FontComboBox::currentFontChanged); +} diff --git a/src/mvvmwidgets/fontcombobox_p.h b/src/mvvmwidgets/fontcombobox_p.h new file mode 100644 index 0000000..3f9f639 --- /dev/null +++ b/src/mvvmwidgets/fontcombobox_p.h @@ -0,0 +1,25 @@ +#ifndef QTMVVM_FONTCOMBOBOX_P_H +#define QTMVVM_FONTCOMBOBOX_P_H + +#include + +#include "qtmvvmwidgets_global.h" + +namespace QtMvvm { + +class FontComboBox : public QFontComboBox +{ + Q_OBJECT + + Q_PROPERTY(QFont currentFont READ currentFont WRITE setCurrentFont NOTIFY currentFontChangedImp USER true) + +public: + explicit FontComboBox(QWidget *parent = nullptr); + +Q_SIGNALS: + void currentFontChangedImp(const QFont &font); +}; + +} + +#endif // QTMVVM_FONTCOMBOBOX_P_H diff --git a/src/mvvmwidgets/inputviewfactory.cpp b/src/mvvmwidgets/inputviewfactory.cpp new file mode 100644 index 0000000..ec79a57 --- /dev/null +++ b/src/mvvmwidgets/inputviewfactory.cpp @@ -0,0 +1,85 @@ +#include "inputviewfactory.h" +#include "inputviewfactory_p.h" +#include + +#include +#include +#include +#include +#include + +#include "fontcombobox_p.h" +#include "selectcombobox_p.h" + +#include + +using namespace QtMvvm; + +InputViewFactory::InputViewFactory() : + d(new InputViewFactoryPrivate()) +{} + +InputViewFactory::~InputViewFactory() {} + +QWidget *InputViewFactory::createInput(const QByteArray &type, QWidget *parent, const QVariantMap &viewProperties) +{ + QWidget *widget = nullptr; + if(d->simpleWidgets.contains(type)) + widget = d->simpleWidgets.value(type)(parent); + else if(type == QMetaType::typeName(QMetaType::Bool)) + widget = new QCheckBox(parent); + else if(type == QMetaType::typeName(QMetaType::QString) || type == "string") { + auto edit = new QLineEdit(parent); + if(viewProperties.contains(QStringLiteral("regexp"))) { + QRegularExpression regex(viewProperties.value(QStringLiteral("regexp")).toString()); + regex.setPatternOptions(static_cast( + viewProperties.value(QStringLiteral("patternOptions"), + static_cast(regex.patternOptions())) + .toInt())); + edit->setValidator(new QRegularExpressionValidator(regex, edit)); + } + widget = edit; + } else if(type == QMetaType::typeName(QMetaType::Int)) + widget = new QSpinBox(parent); + else if(type == QMetaType::typeName(QMetaType::Double) || type == "number") + widget = new QDoubleSpinBox(parent); + else if(type == QMetaType::typeName(QMetaType::QDate)) + widget = new QDateEdit(parent); + else if(type == QMetaType::typeName(QMetaType::QTime)) + widget = new QTimeEdit(parent); + else if(type == QMetaType::typeName(QMetaType::QDateTime) || type == "date") + widget = new QDateTimeEdit(parent); + else if(type == QMetaType::typeName(QMetaType::QFont)) + widget = new FontComboBox(parent); + else if(type == QMetaType::typeName(QMetaType::QKeySequence)) + widget = new QKeySequenceEdit(parent); + else if(type == QMetaType::typeName(QMetaType::QUrl) || type == "url") { + auto edit = new QLineEdit(parent); + auto validator = new QUrlValidator(edit); + if(viewProperties.contains(QStringLiteral("allowedSchemes"))) + validator->setAllowedSchemes(viewProperties.value(QStringLiteral("allowedSchemes")).toStringList()); + edit->setValidator(validator); + widget = edit; + } else if(type == "selection" || type == "list") + widget = new SelectComboBox(parent); + else { + logCritical() << "Failed to find any input view for input type:" << type; + return nullptr; + } + + for(auto it = viewProperties.constBegin(); it != viewProperties.constEnd(); it++) + widget->setProperty(qUtf8Printable(it.key()), it.value()); + return widget; +} + +void InputViewFactory::addSimpleWidget(const QByteArray &type, const std::function &creator) +{ + Q_ASSERT_X(creator, Q_FUNC_INFO, "The passed creation function must be valid"); + d->simpleWidgets.insert(type, creator); +} + +// ------------- Private Implementation ------------- + +InputViewFactoryPrivate::InputViewFactoryPrivate() : + simpleWidgets() +{} diff --git a/src/mvvmwidgets/inputviewfactory.h b/src/mvvmwidgets/inputviewfactory.h new file mode 100644 index 0000000..7324bc9 --- /dev/null +++ b/src/mvvmwidgets/inputviewfactory.h @@ -0,0 +1,41 @@ +#ifndef QTMVVM_INPUTVIEWFACTORY_H +#define QTMVVM_INPUTVIEWFACTORY_H + +#include + +#include + +#include + +#include "QtMvvmWidgets/qtmvvmwidgets_global.h" + +namespace QtMvvm { + +class InputViewFactoryPrivate; +class InputViewFactory +{ +public: + InputViewFactory(); + virtual ~InputViewFactory(); + + virtual QWidget *createInput(const QByteArray &type, QWidget *parent, const QVariantMap &viewProperties); + + virtual void addSimpleWidget(const QByteArray &type, const std::function &creator); + template + void addSimpleWidget(); + +private: + QScopedPointer d; +}; + +template +void InputViewFactory::addSimpleWidget() +{ + addSimpleWidget(QMetaType::typeName(qMetaTypeId()), [](QWidget *parent){ + return new TWidget(parent); + }); +} + +} + +#endif // QTMVVM_INPUTVIEWFACTORY_H diff --git a/src/mvvmwidgets/inputviewfactory_p.h b/src/mvvmwidgets/inputviewfactory_p.h new file mode 100644 index 0000000..866a4b1 --- /dev/null +++ b/src/mvvmwidgets/inputviewfactory_p.h @@ -0,0 +1,19 @@ +#ifndef QTMVVM_INPUTVIEWFACTORY_P_H +#define QTMVVM_INPUTVIEWFACTORY_P_H + +#include "qtmvvmwidgets_global.h" +#include "inputviewfactory.h" + +namespace QtMvvm { + +class InputViewFactoryPrivate +{ +public: + InputViewFactoryPrivate(); + + QHash> simpleWidgets; +}; + +} + +#endif // QTMVVM_INPUTVIEWFACTORY_P_H diff --git a/src/mvvmwidgets/mvvmwidgets.pro b/src/mvvmwidgets/mvvmwidgets.pro index 041f594..49da072 100644 --- a/src/mvvmwidgets/mvvmwidgets.pro +++ b/src/mvvmwidgets/mvvmwidgets.pro @@ -6,10 +6,17 @@ HEADERS += \ qtmvvmwidgets_global.h \ widgetspresenter.h \ ipresentingview.h \ - widgetspresenter_p.h + widgetspresenter_p.h \ + inputviewfactory.h \ + inputviewfactory_p.h \ + fontcombobox_p.h \ + selectcombobox_p.h SOURCES += \ - widgetspresenter.cpp + widgetspresenter.cpp \ + inputviewfactory.cpp \ + fontcombobox.cpp \ + selectcombobox.cpp TRANSLATIONS += \ translations/qtmvvmwidgets_de.ts \ diff --git a/src/mvvmwidgets/qpmx.json b/src/mvvmwidgets/qpmx.json index e24fdd3..a817646 100644 --- a/src/mvvmwidgets/qpmx.json +++ b/src/mvvmwidgets/qpmx.json @@ -4,6 +4,11 @@ "package": "de.skycoder42.dialog-master", "provider": "qpm", "version": "1.3.2" + }, + { + "package": "de.skycoder42.qurlvalidator", + "provider": "qpm", + "version": "1.1.0" } ], "license": { diff --git a/src/mvvmwidgets/selectcombobox.cpp b/src/mvvmwidgets/selectcombobox.cpp new file mode 100644 index 0000000..3a7d8b4 --- /dev/null +++ b/src/mvvmwidgets/selectcombobox.cpp @@ -0,0 +1,62 @@ +#include "selectcombobox_p.h" +using namespace QtMvvm; + +SelectComboBox::SelectComboBox(QWidget *parent) : + QComboBox(parent) +{ + connect(this, &SelectComboBox::currentTextChanged, + this, &SelectComboBox::currentValueChanged); + connect(this, &SelectComboBox::editTextChanged, + this, &SelectComboBox::currentValueChanged); +} + +QVariant SelectComboBox::currentValue() const +{ + if(currentText() != itemText(currentIndex())) + return currentText(); + else + return currentData(); +} + +QVariantList SelectComboBox::listElements() const +{ + QVariantList res; + for(auto i = 0; i < count(); i++) { + auto key = itemText(i); + auto value = itemData(i); + if(key == value) + res.append(key); + else { + QVariantMap map; + map.insert(QStringLiteral("name"), key); + map.insert(QStringLiteral("value"), value); + res.append(map); + } + } + return res; +} + +void SelectComboBox::setCurrentValue(const QVariant &data) +{ + auto index = findData(data); + if(index != -1) + setCurrentIndex(index); + else + setCurrentText(data.toString()); +} + +void SelectComboBox::setListElements(const QVariantList &listElements) +{ + clear(); + for(auto item : listElements) { + if(item.type() == QVariant::String) + addItem(item.toString(), item); + else { + auto iData = item.toMap(); + addItem(iData.value(QStringLiteral("name")).toString(), + iData.value(QStringLiteral("value"))); + } + } + emit listElementsChanged(listElements); +} + diff --git a/src/mvvmwidgets/selectcombobox_p.h b/src/mvvmwidgets/selectcombobox_p.h new file mode 100644 index 0000000..d43123b --- /dev/null +++ b/src/mvvmwidgets/selectcombobox_p.h @@ -0,0 +1,38 @@ +#ifndef QTMVVM_SELECTCOMBOBOX_P_H +#define QTMVVM_SELECTCOMBOBOX_P_H + +#include + +#include + +#include "qtmvvmwidgets_global.h" + +namespace QtMvvm { + +class SelectComboBox : public QComboBox +{ + Q_OBJECT + + Q_PROPERTY(QVariant currentValue READ currentValue WRITE setCurrentValue NOTIFY currentValueChanged USER true) + Q_PROPERTY(QVariantList listElements READ listElements WRITE setListElements NOTIFY listElementsChanged) + + QVariantMap m_listElements; + +public: + explicit SelectComboBox(QWidget *parent = nullptr); + + QVariant currentValue() const; + QVariantList listElements() const; + +public Q_SLOTS: + void setCurrentValue(const QVariant &data); + void setListElements(const QVariantList &listElements); + +Q_SIGNALS: + void currentValueChanged(); + void listElementsChanged(QVariantList listElements); +}; + +} + +#endif // QTMVVM_SELECTCOMBOBOX_P_H diff --git a/src/mvvmwidgets/widgetspresenter.cpp b/src/mvvmwidgets/widgetspresenter.cpp index 7f92cf0..e68b5ae 100644 --- a/src/mvvmwidgets/widgetspresenter.cpp +++ b/src/mvvmwidgets/widgetspresenter.cpp @@ -2,8 +2,7 @@ #include "widgetspresenter_p.h" #include "ipresentingview.h" -#include -#include +#include #include #include @@ -12,6 +11,12 @@ #include #include #include +#include +#include +#include + +#include +#include #include @@ -92,6 +97,16 @@ void WidgetsPresenter::showDialog(const MessageConfig &config, MessageResult *re presentOtherDialog(config, result); } +InputViewFactory *WidgetsPresenter::inputViewFactory() const +{ + return d->inputViewFactory.data(); +} + +void WidgetsPresenter::setInputViewFactory(InputViewFactory *inputViewFactory) +{ + d->inputViewFactory.reset(inputViewFactory); +} + const QMetaObject *WidgetsPresenter::findWidgetMetaObject(const QMetaObject *viewModelMetaObject) { auto currentMeta = viewModelMetaObject; @@ -180,21 +195,27 @@ void WidgetsPresenter::showForeground(QWidget *view) const view->activateWindow(); } -void WidgetsPresenter::presentMessageBox(const MessageConfig &config, MessageResult *result) +void WidgetsPresenter::presentMessageBox(const MessageConfig &config, QPointer result) { + auto qtHelp = false; DialogMaster::MessageBoxInfo info; //set the icon based of the type - if(config.type() == MessageConfig::SubTypeInformation) + if(config.subType() == MessageConfig::SubTypeInformation) info = DialogMaster::createInformation(); - else if(config.type() == MessageConfig::SubTypeWarning) + else if(config.subType() == MessageConfig::SubTypeWarning) info = DialogMaster::createWarning(); - else if(config.type() == MessageConfig::SubTypeCritical) + else if(config.subType() == MessageConfig::SubTypeCritical) info = DialogMaster::createCritical(); - else if(config.type() == MessageConfig::SubTypeQuestion) + else if(config.subType() == MessageConfig::SubTypeQuestion) info = DialogMaster::createQuestion(); - else if(config.type() == MessageConfig::SubTypeAbout) { + else if(config.subType() == MessageConfig::SubTypeAbout) { info = DialogMaster::createInformation(); - info.icon = QGuiApplication::windowIcon(); + info.windowTitle = tr("About"); + auto mIcon = QGuiApplication::windowIcon(); + if(!mIcon.isNull()) + info.icon = mIcon; + qtHelp = config.viewProperties().value(QStringLiteral("addQtVersion"), true).toBool(); + qtHelp = config.viewProperties().value(QStringLiteral("showQtHelp"), qtHelp).toBool();//TODO document too } info.title = config.title(); @@ -203,9 +224,13 @@ void WidgetsPresenter::presentMessageBox(const MessageConfig &config, MessageRes auto btns = config.buttonTexts(); for(auto it = btns.constBegin(); it != btns.constEnd(); it++) info.buttonTexts.insert(static_cast(it.key()), it.value()); + if(qtHelp) { + info.buttons |= QMessageBox::Help; + info.buttonTexts.insert(QMessageBox::Help, tr("About &Qt")); + } //special properties - bool checked = false; + QSharedPointer checked; auto props = config.viewProperties(); //TODO document all these if(!props.value(QStringLiteral("modal"), false).toBool()) info.parent = QApplication::activeWindow(); @@ -215,31 +240,95 @@ void WidgetsPresenter::presentMessageBox(const MessageConfig &config, MessageRes info.details = props.value(QStringLiteral("details")).toString(); if(props.contains(QStringLiteral("checkable"))) { if(props.value(QStringLiteral("checkable")).toBool()) { - checked = config.defaultValue().toBool(); - info.checked = &checked; + checked = QSharedPointer::create(config.defaultValue().toBool()); + info.checked = checked.data(); if(props.contains(QStringLiteral("checkString"))) info.checkString = props.value(QStringLiteral("checkString")).toString(); } } - //show the msgbox - int res = DialogMaster::messageBox(info); - if(info.checked) - result->setResult(checked); - result->complete(static_cast(res)); + //create and show the msgbox + auto msgBox = DialogMaster::createMessageBox(info); + connect(msgBox, &QMessageBox::finished, + result, [qtHelp, checked, result](int resCode){ + if(result) { + if(checked) + result->setResult(*checked); + result->complete(static_cast(resCode)); + if(qtHelp && resCode == QMessageBox::Help) + QApplication::aboutQt(); + } + }); + msgBox->open(); } -void WidgetsPresenter::presentInputDialog(const MessageConfig &config, MessageResult *result) +void WidgetsPresenter::presentInputDialog(const MessageConfig &config, QPointer result) { + auto input = d->inputViewFactory->createInput(config.subType(), nullptr, config.viewProperties()); + if(!input) + return; + + QWidget *parent = nullptr; + if(!config.viewProperties().value(QStringLiteral("modal"), false).toBool()) + parent = QApplication::activeWindow(); + auto dialog = new QDialog(parent); + dialog->setAttribute(Qt::WA_DeleteOnClose); + auto layout = new QVBoxLayout(dialog); + dialog->setLayout(layout); + + //set title and text + auto text = config.text(); + if(text.isNull()) + text = config.title(); + else + dialog->setWindowTitle(config.title());//TODO as header better? + if(!text.isNull()) { + auto label = new QLabel(text, dialog); + layout->addWidget(label); + } + + //add the input + input->setParent(dialog); + auto property = input->metaObject()->userProperty(); + property.write(input, config.defaultValue()); + layout->addWidget(input); + + //add the buttons + auto btnBox = new QDialogButtonBox(dialog); + btnBox->setStandardButtons(static_cast(static_cast(config.buttons()))); //is ok, as the buttons are the same + auto btns = config.buttonTexts(); + for(auto it = btns.constBegin(); it != btns.constEnd(); it++){ + auto sBtn = static_cast(it.key()); + btnBox->addButton(sBtn); + btnBox->button(sBtn)->setText(it.value()); + } + layout->addWidget(btnBox); + + //connect stuff + QObject::connect(btnBox, &QDialogButtonBox::clicked, + dialog, [dialog, btnBox](QAbstractButton *btn){ + dialog->done(btnBox->standardButton(btn)); + }); + QObject::connect(dialog, &QDialog::finished, + dialog, [dialog, input, property, result](int resCode){ + if(result) { + result->complete(static_cast(resCode), + property.read(input)); + } + }); + //finalize and show + dialog->adjustSize(); + DialogMaster::masterDialog(dialog); + dialog->open(); } -void WidgetsPresenter::presentFileDialog(const MessageConfig &config, MessageResult *result) +void WidgetsPresenter::presentFileDialog(const MessageConfig &config, QPointer result) { } -void WidgetsPresenter::presentOtherDialog(const MessageConfig &config, MessageResult *result) +void WidgetsPresenter::presentOtherDialog(const MessageConfig &config, QPointer result) { Q_UNUSED(result) throw PresenterException(QByteArrayLiteral("Unable to find a method that is able to show a dialog of type") + @@ -249,6 +338,7 @@ void WidgetsPresenter::presentOtherDialog(const MessageConfig &config, MessageRe // ------------- Private Implementation ------------- WidgetsPresenterPrivate::WidgetsPresenterPrivate() : + inputViewFactory(new InputViewFactory()), implicitMappings(), explicitMappings() {} diff --git a/src/mvvmwidgets/widgetspresenter.h b/src/mvvmwidgets/widgetspresenter.h index 436db3b..1262c77 100644 --- a/src/mvvmwidgets/widgetspresenter.h +++ b/src/mvvmwidgets/widgetspresenter.h @@ -10,6 +10,7 @@ #include #include "QtMvvmWidgets/qtmvvmwidgets_global.h" +#include "QtMvvmWidgets/inputviewfactory.h" namespace QtMvvm { @@ -19,6 +20,8 @@ class Q_MVVMWIDGETS_EXPORT WidgetsPresenter : public QObject, public IPresenter Q_OBJECT Q_INTERFACES(QtMvvm::IPresenter) + Q_PROPERTY(InputViewFactory* inputViewFactory READ inputViewFactory WRITE setInputViewFactory) + public: explicit WidgetsPresenter(QObject *parent = nullptr); ~WidgetsPresenter(); @@ -37,6 +40,11 @@ public: void present(ViewModel *viewModel, const QVariantHash ¶ms, QPointer parent) override; void showDialog(const MessageConfig &config, MessageResult *result) override; + InputViewFactory* inputViewFactory() const; + +public Q_SLOTS: + void setInputViewFactory(InputViewFactory* inputViewFactory); + protected: virtual const QMetaObject *findWidgetMetaObject(const QMetaObject *viewModelMetaObject); virtual bool tryPresent(QWidget *view, QWidget *parentView); @@ -44,10 +52,10 @@ protected: virtual void showForeground(QWidget *view) const; - virtual void presentMessageBox(const MessageConfig &config, MessageResult *result); - virtual void presentInputDialog(const MessageConfig &config, MessageResult *result); - virtual void presentFileDialog(const MessageConfig &config, MessageResult *result); - virtual void presentOtherDialog(const MessageConfig &config, MessageResult *result); + virtual void presentMessageBox(const MessageConfig &config, QPointer result); + virtual void presentInputDialog(const MessageConfig &config, QPointer result); + virtual void presentFileDialog(const MessageConfig &config, QPointer result); + virtual void presentOtherDialog(const MessageConfig &config, QPointer result); private: QScopedPointer d; diff --git a/src/mvvmwidgets/widgetspresenter_p.h b/src/mvvmwidgets/widgetspresenter_p.h index 1dc957e..3987591 100644 --- a/src/mvvmwidgets/widgetspresenter_p.h +++ b/src/mvvmwidgets/widgetspresenter_p.h @@ -16,6 +16,7 @@ public: static WidgetsPresenter *currentPresenter(); + QScopedPointer inputViewFactory; QSet implicitMappings; QHash explicitMappings; };