diff --git a/examples/mvvmquick/SampleQuick/ResultView.qml b/examples/mvvmquick/SampleQuick/ResultView.qml new file mode 100644 index 0000000..dc2331d --- /dev/null +++ b/examples/mvvmquick/SampleQuick/ResultView.qml @@ -0,0 +1,42 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import de.skycoder42.QtMvvm.Core 1.0 +import de.skycoder42.QtMvvm.Quick 1.0 +import de.skycoder42.quickextras 2.0 +import de.skycoder42.QtMvvm.Sample 1.0 + +AlertDialog { + id: resultDialog + + property ResultViewModel viewModel: null + + title: qsTr("Enter something") + + ColumnLayout { + anchors.fill: parent + + Label { + text: qsTr("Enter a result to be reported as event to the main view:") + wrapMode: Text.WordWrap + Layout.fillWidth: true + } + + TextField { + id: resultEdit + Layout.fillWidth: true + selectByMouse: true + + MvvmBinding { + viewModel: resultDialog.viewModel + viewModelProperty: "result" + view: resultEdit + viewProperty: "text" + } + } + } + + standardButtons: Dialog.Ok | Dialog.Cancel + + onAccepted: viewModel.done() +} diff --git a/examples/mvvmquick/SampleQuick/SampleQuick.pro b/examples/mvvmquick/SampleQuick/SampleQuick.pro index 43522aa..a17ba19 100644 --- a/examples/mvvmquick/SampleQuick/SampleQuick.pro +++ b/examples/mvvmquick/SampleQuick/SampleQuick.pro @@ -73,3 +73,6 @@ samples_in_build { HEADERS += \ quickeventservice.h + +!ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.) +else: include($$OUT_PWD/qpmx_generated.pri) diff --git a/examples/mvvmquick/SampleQuick/SampleView.qml b/examples/mvvmquick/SampleQuick/SampleView.qml index 5f0d7b2..c401142 100644 --- a/examples/mvvmquick/SampleQuick/SampleView.qml +++ b/examples/mvvmquick/SampleQuick/SampleView.qml @@ -1,11 +1,114 @@ import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import de.skycoder42.QtMvvm.Core 1.0 +import de.skycoder42.QtMvvm.Quick 1.0 +import de.skycoder42.quickextras 2.0 +import de.skycoder42.QtMvvm.Sample 1.0 -Rectangle { - property QtObject viewModel: null +Page { + id: sampleView + property SampleViewModel viewModel: null - anchors.fill: parent + header: ActionBar { + showMenuButton: false + title: qsTr("Sample") - color: "red" + moreMenu: Menu { + Action { + text: qsTr("Another &Input") + onTriggered: viewModel.getInput() + } + Action { + text: qsTr("Add &Files") + onTriggered: viewModel.getFiles() + } - Component.onCompleted: console.log(viewModel) + MenuSeparator {} + + Action { + text: qsTr("&About") + onTriggered: viewModel.about() + } + } + } + + PresenterProgress {} + + Pane { + anchors.fill: parent + + GridLayout { + columns: 2 + anchors.fill: parent + + Label { + text: qsTr("Name:") + } + + TextField { + id: nameEdit + Layout.fillWidth: true + selectByMouse: true + + MvvmBinding { + viewModel: sampleView.viewModel + view: nameEdit + viewModelProperty: "name" + viewProperty: "text" + } + } + + Label { + text: qsTr("Active:") + } + + Switch { + id: activeSwitch + Layout.alignment: Qt.AlignLeft + + MvvmBinding { + viewModel: sampleView.viewModel + view: activeSwitch + viewModelProperty: "active" + viewProperty: "checked" + } + } + + Label { + text: qsTr("Events:") + } + + RowLayout { + Layout.fillWidth: true + + Button { + text: qsTr("&Clear") + onClicked: viewModel.clearEvents() + } + + Button { + text: qsTr("Get &Result") + onClicked: viewModel.getResult() + } + } + + ListView { + id: lView + Layout.columnSpan: 2 + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + + ScrollBar.vertical: ScrollBar {} + + model: viewModel.eventsModel + + delegate: ItemDelegate { + width: parent.width + text: viewModel.eventsModel.data(viewModel.eventsModel.index(index, 0)) //because "display" is not accessible + } + } + } + } } diff --git a/examples/mvvmquick/SampleQuick/main.cpp b/examples/mvvmquick/SampleQuick/main.cpp index fa3f809..2b895ad 100644 --- a/examples/mvvmquick/SampleQuick/main.cpp +++ b/examples/mvvmquick/SampleQuick/main.cpp @@ -3,9 +3,14 @@ #include #include +#include + #include #include +#include +#include + #include "quickeventservice.h" QTMVVM_REGISTER_CORE_APP(SampleCoreApp) @@ -19,12 +24,16 @@ int main(int argc, char *argv[]) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); + qmlRegisterUncreatableType("de.skycoder42.QtMvvm.Sample", 1, 0, "SampleViewModel", QStringLiteral("ViewModels cannot be created")); + qmlRegisterUncreatableType("de.skycoder42.QtMvvm.Sample", 1, 0, "ResultViewModel", QStringLiteral("ViewModels cannot be created")); + QtMvvm::QuickPresenter::registerAsPresenter(); QtMvvm::ServiceRegistry::instance()->registerObject(); QtMvvm::ServiceRegistry::instance()->registerInterface(); QQmlApplicationEngine engine; + QuickExtras::setupEngine(&engine); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; diff --git a/examples/mvvmquick/SampleQuick/qml.qrc b/examples/mvvmquick/SampleQuick/qml.qrc index 361a83c..76838f7 100644 --- a/examples/mvvmquick/SampleQuick/qml.qrc +++ b/examples/mvvmquick/SampleQuick/qml.qrc @@ -4,5 +4,6 @@ SampleView.qml + ResultView.qml diff --git a/examples/mvvmquick/SampleQuick/qpmx.json b/examples/mvvmquick/SampleQuick/qpmx.json new file mode 100644 index 0000000..625b104 --- /dev/null +++ b/examples/mvvmquick/SampleQuick/qpmx.json @@ -0,0 +1,20 @@ +{ + "dependencies": [ + { + "package": "de.skycoder42.quickextras", + "provider": "qpm", + "version": "2.1.0" + } + ], + "license": { + "file": "", + "name": "" + }, + "prcFile": "", + "priFile": "", + "priIncludes": [ + ], + "publishers": { + }, + "source": false +} diff --git a/src/imports/mvvmcore/plugins.qmltypes b/src/imports/mvvmcore/plugins.qmltypes index c6d8234..aef4d35 100644 --- a/src/imports/mvvmcore/plugins.qmltypes +++ b/src/imports/mvvmcore/plugins.qmltypes @@ -11,7 +11,7 @@ Module { Component { name: "QtMvvm::QQmlMvvmBinding" prototype: "QObject" - exports: ["de.skycoder42.QtMvvm.Core/Binding 1.0"] + exports: ["de.skycoder42.QtMvvm.Core/MvvmBinding 1.0"] exportMetaObjectRevisions: [0] Enum { name: "BindingDirection" @@ -336,4 +336,24 @@ Module { Parameter { name: "onResult"; type: "QJSValue" } } } + Component { + name: "QtMvvm::ViewModel" + prototype: "QObject" + exports: ["de.skycoder42.QtMvvm.Core/ViewModel 1.0"] + isCreatable: false + exportMetaObjectRevisions: [0] + Signal { + name: "resultReady" + Parameter { name: "result"; type: "QVariant" } + } + Method { + name: "onInit" + Parameter { name: "params"; type: "QVariantHash" } + } + Method { + name: "onResult" + Parameter { name: "requestCode"; type: "uint" } + Parameter { name: "result"; type: "QVariant" } + } + } } diff --git a/src/imports/mvvmcore/qtmvvmcore_plugin.cpp b/src/imports/mvvmcore/qtmvvmcore_plugin.cpp index 0ba593d..68b2fbf 100644 --- a/src/imports/mvvmcore/qtmvvmcore_plugin.cpp +++ b/src/imports/mvvmcore/qtmvvmcore_plugin.cpp @@ -2,6 +2,8 @@ #include +#include + #include "qqmlmvvmbinding.h" #include "qqmlmvvmmessage.h" @@ -19,7 +21,8 @@ void QtMvvmCoreDeclarativeModule::registerTypes(const char *uri) Q_ASSERT(qstrcmp(uri, "de.skycoder42.QtMvvm.Core") == 0); //Version 1.0 - qmlRegisterType(uri, 1, 0, "Binding"); + qmlRegisterUncreatableType(uri, 1, 0, "ViewModel", tr("ViewModels cannot be created from QML")); + qmlRegisterType(uri, 1, 0, "MvvmBinding"); qmlRegisterSingletonType(uri, 1, 0, "Message", createMessageSingleton); // Check to make shure no module update is forgotten diff --git a/src/imports/mvvmquick/PopupPresenter.qml b/src/imports/mvvmquick/PopupPresenter.qml new file mode 100644 index 0000000..c276615 --- /dev/null +++ b/src/imports/mvvmquick/PopupPresenter.qml @@ -0,0 +1,30 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +QtObject { + id: _popPresenter + + property var popups: [] + + function presentPopup(root, popup) { + popup.parent = root; + popup.closed.connect(function() { + var index = popups.indexOf(popup); + if(index > -1) { + popup.destroy(); + popups.splice(index, 1); + } + }); + popup.open(); + popups.push(popup); + return true; + } + + function closeAction() { + if(popups.length > 0) { + popups[popups.length - 1].close(); + return true; + } else + return false; + } +} diff --git a/src/imports/mvvmquick/PresentingStackView.qml b/src/imports/mvvmquick/PresentingStackView.qml index 7246807..7e3e31b 100644 --- a/src/imports/mvvmquick/PresentingStackView.qml +++ b/src/imports/mvvmquick/PresentingStackView.qml @@ -14,6 +14,12 @@ StackView { return false; } + function safePop(item, operation) { + var resItem = pop(item, operation) + if(resItem) + resItem.destroy(); + } + function closeAction() { if(typeof _presenterStack.currentItem.closeAction == "function") { if(_presenterStack.currentItem.closeAction()) @@ -23,7 +29,7 @@ StackView { if(_presenterStack.depth <= 1) return false; else { - if(_presenterStack.pop()) + if(_presenterStack.safePop()) return true; else return false; diff --git a/src/imports/mvvmquick/QtMvvmApp.qml b/src/imports/mvvmquick/QtMvvmApp.qml index 450db54..b846a80 100644 --- a/src/imports/mvvmquick/QtMvvmApp.qml +++ b/src/imports/mvvmquick/QtMvvmApp.qml @@ -9,20 +9,29 @@ ApplicationWindow { height: 520 PresenterProgress { - z: -10 //keep it low so its hidden after the first view was shown + id: _rootProgress + z: _rootStack.empty ? 10 : -10 + } + + PopupPresenter { + id: _rootPopup } PresentingStackView { - id: mainStack + id: _rootStack anchors.fill: parent } + function presentDrawerContent(item) { + return false + } + function presentItem(item) { - return mainStack.presentItem(item); + return _rootStack.presentItem(item); } - function presentPopup(item) { - return true; + function presentPopup(popup) { + return _rootPopup.presentPopup(contentItem, popup); } Component.onCompleted: QuickPresenter.qmlPresenter = _root @@ -30,15 +39,10 @@ ApplicationWindow { onClosing: { var closed = false;//messageBox.closeAction(); -// if(!closed) { -// if(popups.length > 0) { -// popups[popups.length - 1].close(); -// closed = true; -// } -// } - if(!closed) - closed = mainStack.closeAction(); + closed = _rootPopup.closeAction(); + if(!closed) + closed = _rootStack.closeAction(); close.accepted = !closed; } diff --git a/src/imports/mvvmquick/mvvmquick.pro b/src/imports/mvvmquick/mvvmquick.pro index 803a6fe..3fae484 100644 --- a/src/imports/mvvmquick/mvvmquick.pro +++ b/src/imports/mvvmquick/mvvmquick.pro @@ -17,7 +17,8 @@ SOURCES += \ QML_FILES += \ QtMvvmApp.qml \ PresentingStackView.qml \ - PresenterProgress.qml + PresenterProgress.qml \ + PopupPresenter.qml OTHER_FILES += qmldir diff --git a/src/imports/mvvmquick/plugins.qmltypes b/src/imports/mvvmquick/plugins.qmltypes index 4b27dd1..db07cb3 100644 --- a/src/imports/mvvmquick/plugins.qmltypes +++ b/src/imports/mvvmquick/plugins.qmltypes @@ -15,6 +15,7 @@ Module { isCreatable: false isSingleton: true exportMetaObjectRevisions: [0] + Property { name: "currentStyle"; type: "string"; isReadonly: true } Property { name: "qmlPresenter"; type: "QObject"; isPointer: true } Property { name: "viewLoading"; type: "bool"; isReadonly: true } Property { name: "loadingProgress"; type: "double"; isReadonly: true } diff --git a/src/imports/mvvmquick/qmldir b/src/imports/mvvmquick/qmldir index 2c6eb77..8299951 100644 --- a/src/imports/mvvmquick/qmldir +++ b/src/imports/mvvmquick/qmldir @@ -3,6 +3,8 @@ plugin declarative_mvvmquick classname QtMvvmQuickDeclarativeModule typeinfo plugins.qmltypes -QtMvvmApp 1.0 QtMvvmApp.qml PresenterProgress 1.0 PresenterProgress.qml PresentingStackView 1.0 PresentingStackView.qml +PopupPresenter 1.0 PopupPresenter.qml + +QtMvvmApp 1.0 QtMvvmApp.qml diff --git a/src/imports/mvvmquick/qqmlquickpresenter.cpp b/src/imports/mvvmquick/qqmlquickpresenter.cpp index 17c9793..e13adf4 100644 --- a/src/imports/mvvmquick/qqmlquickpresenter.cpp +++ b/src/imports/mvvmquick/qqmlquickpresenter.cpp @@ -4,6 +4,8 @@ #include +#include + #include using namespace QtMvvm; @@ -18,6 +20,11 @@ QQmlQuickPresenter::QQmlQuickPresenter(QQmlEngine *engine) : QuickPresenterPrivate::setQmlPresenter(this); } +QString QQmlQuickPresenter::currentStyle() const +{ + return QQuickStyle::name(); +} + bool QQmlQuickPresenter::isViewLoading() const { return _latestComponent; diff --git a/src/imports/mvvmquick/qqmlquickpresenter.h b/src/imports/mvvmquick/qqmlquickpresenter.h index d271c37..025d9f8 100644 --- a/src/imports/mvvmquick/qqmlquickpresenter.h +++ b/src/imports/mvvmquick/qqmlquickpresenter.h @@ -19,6 +19,8 @@ class QQmlQuickPresenter : public QObject { Q_OBJECT + Q_PROPERTY(QString currentStyle READ currentStyle CONSTANT) + Q_PROPERTY(QObject* qmlPresenter MEMBER _qmlPresenter NOTIFY qmlPresenterChanged) Q_PROPERTY(bool viewLoading READ isViewLoading NOTIFY viewLoadingChanged) Q_PROPERTY(qreal loadingProgress READ loadingProgress NOTIFY loadingProgressChanged) @@ -26,6 +28,8 @@ class QQmlQuickPresenter : public QObject public: explicit QQmlQuickPresenter(QQmlEngine *engine); + QString currentStyle() const; + bool isViewLoading() const; qreal loadingProgress() const;