Skycoder42
7 years ago
12 changed files with 257 additions and 12 deletions
@ -0,0 +1,11 @@ |
|||
import QtQuick 2.10 |
|||
|
|||
Rectangle { |
|||
property QtObject viewModel: null |
|||
|
|||
anchors.fill: parent |
|||
|
|||
color: "red" |
|||
|
|||
Component.onCompleted: console.log(viewModel) |
|||
} |
@ -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 ¶ms, 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 ¶ms, 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(); |
|||
} |
|||
|
Loading…
Reference in new issue