Migration of QtMvvm from github
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

201 lines
5.0 KiB

#include "qqmlviewplaceholder.h"
#include <QtCore/QMetaMethod>
#include <QtQml/QQmlInfo>
#include <QtQml/QQmlProperty>
#include <QtMvvmCore/CoreApp>
using namespace QtMvvm;
QQmlViewPlaceholder::QQmlViewPlaceholder(QQuickItem *parent) :
QQuickItem{parent}
{
// auto presenting
connect(this, &QQmlViewPlaceholder::viewModelTypeChanged,
this, &QQmlViewPlaceholder::presentIfReady);
connect(this, &QQmlViewPlaceholder::autoPresentChanged,
this, &QQmlViewPlaceholder::presentIfReady);
// size changes
connect(this, &QQmlViewPlaceholder::widthChanged,
this, &QQmlViewPlaceholder::resizeView);
connect(this, &QQmlViewPlaceholder::heightChanged,
this, &QQmlViewPlaceholder::resizeView);
connect(this, &QQmlViewPlaceholder::autoResizeViewChanged,
this, &QQmlViewPlaceholder::resizeView);
}
bool QQmlViewPlaceholder::presentItem(const QVariant &item)
{
// check if the parameter is valid
auto quickItem = item.value<QQuickItem*>();
if(!quickItem) {
qmlWarning(this) << "presentItem called with invalid item of type " << item.typeName();
return false;
}
// handle already existing view case
if(_loadedView) {
if(_replaceViews) { // quick discard without reenableing all children
_loadedView->setVisible(false);
_loadedView->deleteLater();
_loadedView = nullptr;
} else {
qmlWarning(this) << R"(A view has already been presented. Discard it first via "discardView" or set "replaceViews" to true)";
return false;
}
}
// add
_loadedView = quickItem;
quickItem->setParent(this);
quickItem->setParentItem(this);
resizeView();
quickItem->setVisible(true);
// hide all children
for(auto child : childItems()) {
if(child != _loadedView)
child->setVisible(false);
}
emit loadedViewChanged(_loadedView);
return true;
}
bool QQmlViewPlaceholder::closeAction()
{
if(!_loadedView)
return false;
// call close on the view
auto vMetaObject = _loadedView->metaObject();
auto cMethodIndex = vMetaObject->indexOfMethod("closeAction()");
if(cMethodIndex != -1) {
auto cMethod = vMetaObject->method(cMethodIndex);
QVariant ok = false;
cMethod.invoke(_loadedView, Q_RETURN_ARG(QVariant, ok));
if(ok.toBool())
return true;
}
// close the view itself (if wished)
if(_closeViewOnAction) {
discardView();
return true;
}
// otherwise: nothing closed
return false;
}
void QQmlViewPlaceholder::setParentViewModel(ViewModel *parentViewModel)
{
// first: clear the auto-connected viewmodel, if required
if(_clearParentVmCon && _parentVmCon)
disconnect(_parentVmCon);
// then: set property as usual
if(_parentViewModel == parentViewModel)
return;
_parentViewModel = parentViewModel;
emit parentViewModelChanged(_parentViewModel);
// check the vm parent for a presenter method
auto view = qobject_cast<QQuickItem*>(_parentViewModel->parent());
if(view) {
if(view->metaObject()->indexOfMethod("presentItem(QVariant)") == -1)
qmlWarning(this) << R"(Parent item of "parentViewModel" does not have a "presentItem" method. Check the ViewPlaceholder documentation!)";
} else
qmlWarning(this) << R"(Parent item of "parentViewModel" is not an Item)";
presentIfReady();
}
QQuickItem *QQmlViewPlaceholder::loadedView() const
{
return _loadedView;
}
void QQmlViewPlaceholder::componentComplete()
{
// auto-set the vm if not already set
if(!_parentViewModel)
getParentViewModel();
// last step: call base implementation, then present
QQuickItem::componentComplete();
_isReady = true;
presentIfReady();
}
void QQmlViewPlaceholder::presentView()
{
CoreApp::show(qUtf8Printable(_viewModelType), _showParams, _parentViewModel);
}
void QQmlViewPlaceholder::discardView()
{
// hide view
_loadedView->setVisible(false);
// show all children again
for(auto child : childItems()) {
if(child != _loadedView)
child->setVisible(true);
}
// now delete it
_loadedView->deleteLater();
_loadedView = nullptr;
emit loadedViewChanged(nullptr);
}
void QQmlViewPlaceholder::parentItemVmChanged(ViewModel *viewModel)
{
// set vm without clearing the connection
_clearParentVmCon = false;
setParentViewModel(viewModel);
_clearParentVmCon = true;
}
void QQmlViewPlaceholder::presentIfReady()
{
if(_isReady &&
_autoPresent &&
!_loadedView &&
_parentViewModel &&
!_viewModelType.isEmpty())
presentView();
}
void QQmlViewPlaceholder::resizeView()
{
if(_loadedView && _autoResizeView) {
_loadedView->setWidth(width());
_loadedView->setHeight(height());
}
}
void QQmlViewPlaceholder::getParentViewModel()
{
auto pItem = parentItem();
if(!pItem)
return;
QQmlProperty vmProp{pItem, QStringLiteral("viewModel")};
if(!vmProp.isValid())
return;
// set the vm from the property
auto vm = vmProp.read().value<ViewModel*>();
if(vm)
setParentViewModel(vm); // no warning here - might be ok for lazy presented vms
// connect to further changes, via helper slot
auto cSlotIndex = metaObject()->indexOfSlot("parentItemVmChanged(QtMvvm::ViewModel*)");
Q_ASSERT(cSlotIndex != -1);
if(_parentVmCon)
disconnect(_parentVmCon);
_parentVmCon = connect(pItem, vmProp.property().notifySignal(),
this, metaObject()->method(cSlotIndex));
}