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