Browse Source

implement basic presenter c++ logic

pull/2/head
Skycoder42 7 years ago
parent
commit
ef683064ca
  1. 2
      .qmake.conf
  2. 11
      examples/mvvmquick/SampleQuick/SampleView.qml
  3. 3
      examples/mvvmquick/SampleQuick/qml.qrc
  4. 15
      src/imports/mvvmquick/QtMvvmApp.qml
  5. 2
      src/imports/mvvmquick/mvvmquick.pro
  6. 22
      src/imports/mvvmquick/plugins.qmltypes
  7. 138
      src/imports/mvvmquick/qqmlquickpresenter.cpp
  8. 44
      src/imports/mvvmquick/qqmlquickpresenter.h
  9. 19
      src/mvvmquick/quickpresenter.cpp
  10. 1
      src/mvvmquick/quickpresenter.h
  11. 11
      src/mvvmquick/quickpresenter_p.h
  12. 1
      src/mvvmwidgets/widgetspresenter.cpp

2
.qmake.conf

@ -1,7 +1,7 @@
load(qt_build_config)
CONFIG += warning_clean exceptions c++14
CONFIG += samples_in_build
!win32: CONFIG += samples_in_build # TODO fix on win
win32:cross_compile: CONFIG += winrt
DEFINES += QT_DEPRECATED_WARNINGS QT_ASCII_CAST_WARNINGS

11
examples/mvvmquick/SampleQuick/SampleView.qml

@ -0,0 +1,11 @@
import QtQuick 2.10
Rectangle {
property QtObject viewModel: null
anchors.fill: parent
color: "red"
Component.onCompleted: console.log(viewModel)
}

3
examples/mvvmquick/SampleQuick/qml.qrc

@ -2,4 +2,7 @@
<qresource prefix="/">
<file>main.qml</file>
</qresource>
<qresource prefix="/qtmvvm/views">
<file>SampleView.qml</file>
</qresource>
</RCC>

15
src/imports/mvvmquick/QtMvvmApp.qml

@ -1,5 +1,6 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import de.skycoder42.qtmvvm.quick 1.0
ApplicationWindow {
id: _root
@ -7,5 +8,17 @@ ApplicationWindow {
width: 360
height: 520
PresenterProgress {}
PresenterProgress {
z: -10 //keep it low so its hidden after the first view was shown
}
function presentItem(item) {
return true;
}
function presentPopup(item) {
return true;
}
Component.onCompleted: QuickPresenter.qmlPresenter = _root
}

2
src/imports/mvvmquick/mvvmquick.pro

@ -1,4 +1,4 @@
QT += core qml quick mvvmquick
QT += core qml quick mvvmquick mvvmquick-private
CXX_MODULE = mvvmquick
TARGETPATH = de/skycoder42/qtmvvm/quick
TARGET = declarative_mvvmquick

22
src/imports/mvvmquick/plugins.qmltypes

@ -15,5 +15,27 @@ Module {
isCreatable: false
isSingleton: true
exportMetaObjectRevisions: [0]
Property { name: "qmlPresenter"; type: "QObject"; isPointer: true }
Property { name: "viewLoading"; type: "bool"; isReadonly: true }
Property { name: "loadingProgress"; type: "double"; isReadonly: true }
Signal {
name: "qmlPresenterChanged"
Parameter { name: "qmlPresenter"; type: "QObject"; isPointer: true }
}
Signal {
name: "viewLoadingChanged"
Parameter { name: "viewLoading"; type: "bool" }
}
Signal {
name: "loadingProgressChanged"
Parameter { name: "loadingProgress"; type: "double" }
}
Method {
name: "present"
Parameter { name: "viewModel"; type: "QtMvvm::ViewModel"; isPointer: true }
Parameter { name: "params"; type: "QVariantHash" }
Parameter { name: "viewUrl"; type: "QUrl" }
Parameter { name: "parent"; type: "QPointer<QtMvvm::ViewModel>" }
}
}
}

138
src/imports/mvvmquick/qqmlquickpresenter.cpp

@ -1,6 +1,138 @@
#include "qqmlquickpresenter.h"
#include <QtQml/QtQml>
#include <QtQuick/QQuickItem>
#include <QtMvvmQuick/private/quickpresenter_p.h>
using namespace QtMvvm;
QQmlQuickPresenter::QQmlQuickPresenter(QObject *parent) :
QObject(parent)
{}
QQmlQuickPresenter::QQmlQuickPresenter(QQmlEngine *engine) :
QObject(engine),
_engine(engine),
_latestComponent(),
_componentCache(),
_loadCache()
{
QuickPresenterPrivate::setQmlPresenter(this);
}
bool QQmlQuickPresenter::isViewLoading() const
{
return _latestComponent;
}
qreal QQmlQuickPresenter::loadingProgress() const
{
return _latestComponent ? _latestComponent->progress() : -1.0;
}
void QQmlQuickPresenter::present(ViewModel *viewModel, const QVariantHash &params, const QUrl &viewUrl, QPointer<ViewModel> parent)
{
auto component = _componentCache.object(viewUrl);
if(component)
addObject(component, viewModel, params, parent);
else {
//create component (and replace latest)
if(_latestComponent) {
disconnect(_latestComponent, &QQmlComponent::progressChanged,
this, &QQmlQuickPresenter::loadingProgressChanged);
}
_latestComponent = new QQmlComponent(_engine, this);
_loadCache.insert(_latestComponent, std::make_tuple(viewModel, params, parent));
//setup ui status
emit viewLoadingChanged(true);
emit loadingProgressChanged(0.0);
connect(_latestComponent, &QQmlComponent::progressChanged,
this, &QQmlQuickPresenter::loadingProgressChanged);
connect(_latestComponent, &QQmlComponent::statusChanged,
this, &QQmlQuickPresenter::statusChanged);
_latestComponent->loadUrl(viewUrl, QQmlComponent::Asynchronous);
}
}
void QQmlQuickPresenter::statusChanged(QQmlComponent::Status status)
{
auto component = qobject_cast<QQmlComponent*>(sender());
if(!component)
return;
switch(status) {
case QQmlComponent::Ready:
{
_componentCache.insert(component->url(), component);
auto loadInfo = _loadCache.value(component);
disconnect(component, &QQmlComponent::progressChanged,
this, &QQmlQuickPresenter::loadingProgressChanged);
addObject(component, std::get<0>(loadInfo), std::get<1>(loadInfo), std::get<2>(loadInfo));
break;
}
case QQmlComponent::Error:
qmlWarning(this, component->errors()) << "Failed to load component";
component->deleteLater();
break;
default:
return;
}
_loadCache.remove(component);
if(_latestComponent == component) {
_latestComponent = nullptr;
emit viewLoadingChanged(false);
}
}
void QQmlQuickPresenter::addObject(QQmlComponent *component, ViewModel *viewModel, const QVariantHash &params, QPointer<ViewModel> parent)
{
if(!_qmlPresenter) {
qCritical() << "No QML-Presenter registered! Unable to present control of type"
<< viewModel->metaObject()->className();
return;
}
//create the view item, set initial stuff and them complete creation
auto item = component->beginCreate(_engine->rootContext());
if(!item) {
qmlWarning(this) << "Unable to create quick view from the loaded component"
<< component->url();
return;
}
item->setProperty("viewModel", QVariant::fromValue(viewModel));
viewModel->setParent(item);
viewModel->onInit(params);
component->completeCreate();
auto presented = false;
if(parent && parent->parent())
presented = tryPresent(parent->parent(), item);
if(!presented)
presented = tryPresent(_qmlPresenter, item);
if(presented)
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
else {
qmlWarning(this) << "Failed to present item for viewModel of type"
<< viewModel->metaObject()->className();
item->deleteLater();
}
}
bool QQmlQuickPresenter::tryPresent(QObject *qmlPresenter, QObject *viewObject)
{
auto meta = qmlPresenter->metaObject();
auto index = -1;
if(viewObject->inherits("QQuickItem"))
index = meta->indexOfMethod("presentItem(QVariant)");
if(viewObject->inherits("QQuickPopup"))
index = meta->indexOfMethod("presentPopup(QVariant)");
QVariant presented = false;
if(index != -1) {
meta->method(index).invoke(qmlPresenter, Qt::DirectConnection,
Q_RETURN_ARG(QVariant, presented),
Q_ARG(QVariant, QVariant::fromValue(viewObject)));
}
return presented.toBool();
}

44
src/imports/mvvmquick/qqmlquickpresenter.h

@ -1,7 +1,17 @@
#ifndef QTMVVM_QQMLQUICKPRESENTER_H
#define QTMVVM_QQMLQUICKPRESENTER_H
#include <QObject>
#include <tuple>
#include <QtCore/QObject>
#include <QtCore/QCache>
#include <QtCore/QVariant>
#include <QtCore/QPointer>
#include <QtCore/QUrl>
#include <QtQml/QQmlComponent>
#include <QtMvvmCore/ViewModel>
namespace QtMvvm {
@ -9,8 +19,38 @@ class QQmlQuickPresenter : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* qmlPresenter MEMBER _qmlPresenter NOTIFY qmlPresenterChanged)
Q_PROPERTY(bool viewLoading READ isViewLoading NOTIFY viewLoadingChanged)
Q_PROPERTY(qreal loadingProgress READ loadingProgress NOTIFY loadingProgressChanged)
public:
explicit QQmlQuickPresenter(QObject *parent = nullptr);
explicit QQmlQuickPresenter(QQmlEngine *engine);
bool isViewLoading() const;
qreal loadingProgress() const;
public Q_SLOTS:
void present(QtMvvm::ViewModel *viewModel, const QVariantHash &params, const QUrl &viewUrl, QPointer<QtMvvm::ViewModel> parent);
Q_SIGNALS:
void qmlPresenterChanged(QObject* qmlPresenter);
void viewLoadingChanged(bool viewLoading);
void loadingProgressChanged(qreal loadingProgress);
private Q_SLOTS:
void statusChanged(QQmlComponent::Status status);
private:
typedef std::tuple<ViewModel*, QVariantHash, QPointer<ViewModel>> PresentTuple;
QQmlEngine *_engine;
QPointer<QObject> _qmlPresenter;
QPointer<QQmlComponent> _latestComponent;
QCache<QUrl, QQmlComponent> _componentCache;
QHash<QQmlComponent*, PresentTuple> _loadCache;
void addObject(QQmlComponent *component, ViewModel *viewModel, const QVariantHash &params, QPointer<ViewModel> parent);
bool tryPresent(QObject *qmlPresenter, QObject *viewObject);
};
}

19
src/mvvmquick/quickpresenter.cpp

@ -29,7 +29,18 @@ void QuickPresenter::registerViewExplicitly(const QMetaObject *viewModelType, co
void QuickPresenter::present(QtMvvm::ViewModel *viewModel, const QVariantHash &params, QPointer<QtMvvm::ViewModel> parent)
{
qDebug(Q_FUNC_INFO);
auto url = findViewUrl(viewModel->metaObject());
if(!url.isValid())
throw PresenterException(QByteArrayLiteral("No Url to a QML View found for ") + viewModel->metaObject()->className());
if(d->qmlPresenter) {
QMetaObject::invokeMethod(d->qmlPresenter, "present",
Q_ARG(QtMvvm::ViewModel*, viewModel),
Q_ARG(QVariantHash, params),
Q_ARG(QUrl, url),
Q_ARG(QPointer<QtMvvm::ViewModel>, parent));
} else
throw PresenterException("QML presenter not ready - cannot present yet");
}
void QuickPresenter::showDialog(const QtMvvm::MessageConfig &config, QtMvvm::MessageResult *result)
@ -61,7 +72,6 @@ QUrl QuickPresenter::findViewUrl(const QMetaObject *viewModelType)
if(dir.startsWith(QStringLiteral(":"))) {
resUrl.setScheme(QStringLiteral("qrc"));
resUrl.setPath(iterator.filePath().mid(1)); //skip the beginning colon
logDebug() << "TEST:" << QUrl::fromLocalFile(iterator.filePath());
} else
resUrl = QUrl::fromLocalFile(iterator.filePath());
logDebug() << "Found URL for viewmodel"
@ -99,3 +109,8 @@ QuickPresenter *QuickPresenterPrivate::currentPresenter()
#endif
return presenter;
}
void QuickPresenterPrivate::setQmlPresenter(QObject *presenter)
{
currentPresenter()->d->qmlPresenter = presenter;
}

1
src/mvvmquick/quickpresenter.h

@ -37,6 +37,7 @@ protected:
virtual QUrl findViewUrl(const QMetaObject *viewModelType);
private:
friend class QtMvvm::QuickPresenterPrivate;
QScopedPointer<QuickPresenterPrivate> d;
};

11
src/mvvmquick/quickpresenter_p.h

@ -2,21 +2,28 @@
#define QTMVVM_QUICKPRESENTER_P_H
#include <QtCore/QHash>
#include <QtCore/QPointer>
#include "qtmvvmquick_global.h"
#include "quickpresenter.h"
namespace QtMvvm {
class QuickPresenterPrivate
class Q_MVVMQUICK_EXPORT QuickPresenterPrivate
{
friend class QtMvvm::QuickPresenter;
public:
QuickPresenterPrivate();
static QuickPresenter *currentPresenter();
static void setQmlPresenter(QObject *presenter);
private:
QHash<const QMetaObject *, QUrl> explicitMappings;
QStringList searchDirs;
static QuickPresenter *currentPresenter();
QPointer<QObject> qmlPresenter;
};
}

1
src/mvvmwidgets/widgetspresenter.cpp

@ -15,6 +15,7 @@
#include <QtWidgets/QDialogButtonBox>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QLabel>
#include <QtMvvmCore/private/coreapp_p.h>
#include <QtMvvmCore/private/qtmvvm_logging_p.h>

Loading…
Cancel
Save