diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-03-26 01:00:06 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-03-26 01:00:06 +0100 |
commit | fbd86c6a24ee4999d724f9aaccf1941d02538187 (patch) | |
tree | ce734921c9804eff76498b77e24742c71b1aafff /src | |
parent | a8cc4f2b51722380a30fae0009205db917feb7a9 (diff) | |
parent | 0dab320fb42ba2ac855baf05972c3420c11d002e (diff) |
Merge remote-tracking branch 'origin/5.13' into dev
Change-Id: Iaaf9749a812c21c065ded0374ce0aa07de7752cf
Diffstat (limited to 'src')
25 files changed, 388 insertions, 211 deletions
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp index 5bd96af582..5d2684b510 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp @@ -106,16 +106,9 @@ static void closeAllWindows() bool QQmlPreviewHandler::eventFilter(QObject *obj, QEvent *event) { - if (event->type() == QEvent::Show) { - if (QWindow *window = qobject_cast<QQuickWindow*>(obj)) { - m_lastPosition.initLastSavedWindowPosition(window); - } - } - if (m_currentWindow && (event->type() == QEvent::Move || event->type() == QEvent::Resize) && + if (m_currentWindow && (event->type() == QEvent::Move) && qobject_cast<QQuickWindow*>(obj) == m_currentWindow) { - // we always start with factor 1 so calculate and save the origin as it would be not scaled - m_lastPosition.setPosition(m_currentWindow->framePosition() * - QHighDpiScaling::factor(m_currentWindow)); + m_lastPosition.takePosition(m_currentWindow); } return QObject::eventFilter(obj, event); @@ -196,49 +189,38 @@ void QQmlPreviewHandler::rerun() void QQmlPreviewHandler::zoom(qreal newFactor) { + m_zoomFactor = newFactor; + QTimer::singleShot(0, this, &QQmlPreviewHandler::doZoom); +} + +void QQmlPreviewHandler::doZoom() +{ if (!m_currentWindow) return; - if (qFuzzyIsNull(newFactor)) { + if (qFuzzyIsNull(m_zoomFactor)) { emit error(QString::fromLatin1("Zooming with factor: %1 will result in nothing " \ - "so it will be ignored.").arg(newFactor)); + "so it will be ignored.").arg(m_zoomFactor)); return; } - QString errorMessage; - bool resetZoom = false; - if (newFactor < 0) { + bool resetZoom = false; + if (m_zoomFactor < 0) { resetZoom = true; - newFactor = 1.0; + m_zoomFactor = 1.0; } - // On single-window devices we allow any scale factor as the window will adapt to the screen. - if (m_supportsMultipleWindows) { - const QSize newAvailableScreenSize = QQmlPreviewPosition::currentScreenSize(m_currentWindow) - * QHighDpiScaling::factor(m_currentWindow) / newFactor; - if (m_currentWindow->size().width() > newAvailableScreenSize.width()) { - errorMessage = QString::fromLatin1( - "Zooming with factor: " - "%1 will result in a too wide preview.").arg(newFactor); - } - if (m_currentWindow->size().height() > newAvailableScreenSize.height()) { - errorMessage = QString::fromLatin1( - "Zooming with factor: " - "%1 will result in a too heigh preview.").arg(newFactor); - } - } + m_currentWindow->setGeometry(m_currentWindow->geometry()); - if (errorMessage.isEmpty()) { - const QPoint newToOriginMappedPosition = m_currentWindow->position() * - QHighDpiScaling::factor(m_currentWindow) / newFactor; - m_currentWindow->destroy(); - QHighDpiScaling::setScreenFactor(m_currentWindow->screen(), newFactor); - if (resetZoom) - QHighDpiScaling::updateHighDpiScaling(); - m_currentWindow->setPosition(newToOriginMappedPosition); - m_currentWindow->show(); - } else { - emit error(errorMessage); - } + m_lastPosition.takePosition(m_currentWindow, QQmlPreviewPosition::InitializePosition); + m_currentWindow->destroy(); + + for (QScreen *screen : QGuiApplication::screens()) + QHighDpiScaling::setScreenFactor(screen, m_zoomFactor); + if (resetZoom) + QHighDpiScaling::updateHighDpiScaling(); + + m_currentWindow->show(); + m_lastPosition.initLastSavedWindowPosition(m_currentWindow); } void QQmlPreviewHandler::removeTranslators() diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h index 21ea672580..47491b9d8f 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h @@ -104,6 +104,7 @@ signals: protected: bool eventFilter(QObject *obj, QEvent *event); private: + void doZoom(); void tryCreateObject(); void showObject(QObject *object); void setCurrentWindow(QQuickWindow *window); @@ -121,6 +122,7 @@ private: QVector<QPointer<QObject>> m_createdObjects; QScopedPointer<QQmlComponent> m_component; QPointer<QQuickWindow> m_currentWindow; + qreal m_zoomFactor = 1.0; bool m_supportsMultipleWindows; QQmlPreviewPosition m_lastPosition; diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.cpp index 3edcbac0a9..d4acd24da5 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.cpp @@ -42,14 +42,47 @@ #include <QtGui/qwindow.h> #include <QtGui/qscreen.h> #include <QtGui/qguiapplication.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE -static const QSize availableScreenSize(const QPoint &point) +static QVector<QQmlPreviewPosition::ScreenData> initScreensData() { - if (const QScreen *screen = QGuiApplication::screenAt(point)) - return screen->availableGeometry().size(); - return QSize(); + QVector<QQmlPreviewPosition::ScreenData> screensData; + + for (QScreen *screen : QGuiApplication::screens()) { + QQmlPreviewPosition::ScreenData sd{screen->name(), screen->size()}; + screensData.append(sd); + } + return screensData; +} + +static QScreen *findScreen(const QString &nameOfScreen) +{ + for (QScreen *screen : QGuiApplication::screens()) { + if (screen->name() == nameOfScreen) + return screen; + } + return nullptr; +} + +static QDataStream &operator<<(QDataStream &out, const QQmlPreviewPosition::ScreenData &screenData) +{ + out << screenData.name; + out << screenData.size; + return out; +} + +static QDataStream &operator>>(QDataStream &in, QQmlPreviewPosition::ScreenData &screenData) +{ + in >> screenData.name; + in >> screenData.size; + return in; +} + +bool QQmlPreviewPosition::ScreenData::operator==(const QQmlPreviewPosition::ScreenData &other) const +{ + return other.size == size && other.name == name; } QQmlPreviewPosition::QQmlPreviewPosition() @@ -62,20 +95,36 @@ QQmlPreviewPosition::QQmlPreviewPosition() }); } -void QQmlPreviewPosition::setPosition(const QPoint &point) +QQmlPreviewPosition::~QQmlPreviewPosition() +{ + saveWindowPosition(); +} + +void QQmlPreviewPosition::takePosition(QWindow *window, InitializeState state) { - m_hasPosition = true; - m_lastWindowPosition = point; - m_savePositionTimer.start(); + Q_ASSERT(window); + // only save the position if we already tried to get the last saved position + if (m_initializeState == PositionInitialized) { + m_hasPosition = true; + auto screen = window->screen(); + auto nativePosition = QHighDpiScaling::mapPositionToNative(window->framePosition(), + screen->handle()); + m_lastWindowPosition = {screen->name(), nativePosition}; + + m_savePositionTimer.start(); + } + if (state == InitializePosition) + m_initializeState = InitializePosition; } void QQmlPreviewPosition::saveWindowPosition() { if (m_hasPosition) { + const QByteArray positionAsByteArray = fromPositionToByteArray(m_lastWindowPosition); if (!m_settingsKey.isNull()) - m_settings.setValue(m_settingsKey, m_lastWindowPosition); + m_settings.setValue(m_settingsKey, positionAsByteArray); - m_settings.setValue(QLatin1String("global_lastpostion"), m_lastWindowPosition); + m_settings.setValue(QLatin1String("global_lastpostion"), positionAsByteArray); } } @@ -85,29 +134,86 @@ void QQmlPreviewPosition::loadWindowPositionSettings(const QUrl &url) if (m_settings.contains(m_settingsKey)) { m_hasPosition = true; - m_lastWindowPosition = m_settings.value(m_settingsKey).toPoint(); + readLastPositionFromByteArray(m_settings.value(m_settingsKey).toByteArray()); } } void QQmlPreviewPosition::initLastSavedWindowPosition(QWindow *window) { - if (m_positionedWindows.contains(window)) - return; + Q_ASSERT(window); + m_initializeState = PositionInitialized; + if (m_currentInitScreensData.isEmpty()) + m_currentInitScreensData = initScreensData(); + // if it is the first time we just use the fall back from a last shown qml file if (!m_hasPosition) { - // in case there was nothing saved, we do not want to set anything if (!m_settings.contains(QLatin1String("global_lastpostion"))) return; - m_lastWindowPosition = m_settings.value(QLatin1String("global_lastpostion")).toPoint(); + readLastPositionFromByteArray(m_settings.value(QLatin1String("global_lastpostion")) + .toByteArray()); } - if (QGuiApplication::screenAt(m_lastWindowPosition)) - window->setFramePosition(m_lastWindowPosition); + setPosition(m_lastWindowPosition, window); +} + +QByteArray QQmlPreviewPosition::fromPositionToByteArray( + const QQmlPreviewPosition::Position &position) +{ + QByteArray array; + QDataStream stream(&array, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_5_12); + + const quint16 majorVersion = 1; + const quint16 minorVersion = 0; + + stream << majorVersion + << minorVersion + << m_currentInitScreensData + << position.screenName + << position.nativePosition; + return array; +} + +void QQmlPreviewPosition::readLastPositionFromByteArray(const QByteArray &array) +{ + QDataStream stream(array); + stream.setVersion(QDataStream::Qt_5_12); + + // no version check for 1.0 + //const quint16 currentMajorVersion = 1; + quint16 majorVersion = 0; + quint16 minorVersion = 0; - m_positionedWindows.append(window); + stream >> majorVersion >> minorVersion; + + QVector<ScreenData> initScreensData; + stream >> initScreensData; + + if (m_currentInitScreensData != initScreensData) + return; + + QString nameOfScreen; + stream >> nameOfScreen; + + QScreen *screen = findScreen(nameOfScreen); + if (!screen) + return; + + QPoint nativePosition; + stream >> nativePosition; + if (nativePosition.isNull()) + return; + m_lastWindowPosition = {nameOfScreen, nativePosition}; } -const QSize QQmlPreviewPosition::currentScreenSize(QWindow *window) +void QQmlPreviewPosition::setPosition(const QQmlPreviewPosition::Position &position, + QWindow *window) { - return availableScreenSize(window->position()); + if (position.nativePosition.isNull()) + return; + if (QScreen *screen = findScreen(position.screenName)) { + window->setScreen(screen); + window->setFramePosition(QHighDpiScaling::mapPositionFromNative(position.nativePosition, + screen->handle())); + } } QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.h index 3d4ca9dc67..f403917f8c 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.h +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.h @@ -56,6 +56,8 @@ #include <QtCore/qurl.h> #include <QtCore/qtimer.h> #include <QtCore/qsettings.h> +#include <QtCore/qsize.h> +#include <QtCore/qdatastream.h> QT_BEGIN_NAMESPACE @@ -64,23 +66,46 @@ class QWindow; class QQmlPreviewPosition { public: + class ScreenData { + public: + bool operator==(const QQmlPreviewPosition::ScreenData &other) const; + QString name; + QSize size; + }; + class Position { + public: + QString screenName; + QPoint nativePosition; + }; + enum InitializeState { + InitializePosition, + PositionInitialized + }; + QQmlPreviewPosition(); + ~QQmlPreviewPosition(); - void setPosition(const QPoint &point); - void saveWindowPosition(); - void loadWindowPositionSettings(const QUrl &url); + + void takePosition(QWindow *window, InitializeState state = PositionInitialized); void initLastSavedWindowPosition(QWindow *window); - static const QSize currentScreenSize(QWindow *window); + void loadWindowPositionSettings(const QUrl &url); private: + void setPosition(const QQmlPreviewPosition::Position &position, QWindow *window); + QByteArray fromPositionToByteArray(const Position &position); + void readLastPositionFromByteArray(const QByteArray &array); + void saveWindowPosition(); + bool m_hasPosition = false; - QPoint m_lastWindowPosition; + InitializeState m_initializeState = InitializePosition; QSettings m_settings; QString m_settingsKey; QTimer m_savePositionTimer; + Position m_lastWindowPosition; QVector<QWindow *> m_positionedWindows; -}; + QVector<ScreenData> m_currentInitScreensData; +}; QT_END_NAMESPACE diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index a22dd7aa32..6e077ec44c 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1111,6 +1111,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg QV4::CompiledData::TranslationData translationData; translationData.number = -1; translationData.commentIndex = 0; // empty string + translationData.padding = 0; if (!args || !args->expression) return; // no arguments, stop @@ -1151,6 +1152,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg QV4::CompiledData::TranslationData translationData; translationData.number = -1; translationData.commentIndex = 0; // empty string, but unused + translationData.padding = 0; if (!args || !args->expression) return; // no arguments, stop diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index a2bfd55332..88d3dbe9c5 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1739,59 +1739,46 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re return Reference::fromAccumulator(this); } -static QSOperator::Op operatorForSwappedOperands(QSOperator::Op oper) -{ - switch (oper) { - case QSOperator::StrictEqual: return QSOperator::StrictEqual; - case QSOperator::StrictNotEqual: return QSOperator::StrictNotEqual; - case QSOperator::Equal: return QSOperator::Equal; - case QSOperator::NotEqual: return QSOperator::NotEqual; - case QSOperator::Gt: return QSOperator::Le; - case QSOperator::Ge: return QSOperator::Lt; - case QSOperator::Lt: return QSOperator::Ge; - case QSOperator::Le: return QSOperator::Gt; - default: Q_UNIMPLEMENTED(); return QSOperator::Invalid; - } -} - Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Reference &right) { - if (left.isConstant()) { - oper = operatorForSwappedOperands(oper); - qSwap(left, right); - } + // See if we can generate specialized comparison instructions: + if (oper == QSOperator::Equal || oper == QSOperator::NotEqual) { + // Because == and != are reflexive, we can do the following: + if (left.isConstant() && !right.isConstant()) + qSwap(left, right); // null==a -> a==null - if (right.isConstant() && (oper == QSOperator::Equal || oper == QSOperator::NotEqual)) { - Value c = Value::fromReturnedValue(right.constant); - if (c.isNull() || c.isUndefined()) { - left.loadInAccumulator(); - if (oper == QSOperator::Equal) { - Instruction::CmpEqNull cmp; - bytecodeGenerator->addInstruction(cmp); - addCJump(); - return Reference(); - } else if (oper == QSOperator::NotEqual) { - Instruction::CmpNeNull cmp; - bytecodeGenerator->addInstruction(cmp); - addCJump(); - return Reference(); - } - } else if (c.isInt32()) { - left.loadInAccumulator(); - if (oper == QSOperator::Equal) { - Instruction::CmpEqInt cmp; - cmp.lhs = c.int_32(); - bytecodeGenerator->addInstruction(cmp); - addCJump(); - return Reference(); - } else if (oper == QSOperator::NotEqual) { - Instruction::CmpNeInt cmp; - cmp.lhs = c.int_32(); - bytecodeGenerator->addInstruction(cmp); - addCJump(); - return Reference(); - } + if (right.isConstant()) { + Value c = Value::fromReturnedValue(right.constant); + if (c.isNull() || c.isUndefined()) { + left.loadInAccumulator(); + if (oper == QSOperator::Equal) { + Instruction::CmpEqNull cmp; + bytecodeGenerator->addInstruction(cmp); + addCJump(); + return Reference(); + } else if (oper == QSOperator::NotEqual) { + Instruction::CmpNeNull cmp; + bytecodeGenerator->addInstruction(cmp); + addCJump(); + return Reference(); + } + } else if (c.isInt32()) { + left.loadInAccumulator(); + if (oper == QSOperator::Equal) { + Instruction::CmpEqInt cmp; + cmp.lhs = c.int_32(); + bytecodeGenerator->addInstruction(cmp); + addCJump(); + return Reference(); + } else if (oper == QSOperator::NotEqual) { + Instruction::CmpNeInt cmp; + cmp.lhs = c.int_32(); + bytecodeGenerator->addInstruction(cmp); + addCJump(); + return Reference(); + } + } } } diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index e4cc9c9c5a..f280994d54 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -97,18 +97,25 @@ CompilationUnit::CompilationUnit(const Unit *unitData, const QString &fileName, setUnitData(unitData, nullptr, fileName, finalUrlString); } -#ifndef V4_BOOTSTRAP CompilationUnit::~CompilationUnit() { +#ifndef V4_BOOTSTRAP unlink(); +#endif if (data) { if (data->qmlUnit() != qmlData) free(const_cast<QmlUnit *>(qmlData)); qmlData = nullptr; +#ifndef V4_BOOTSTRAP if (!(data->flags & QV4::CompiledData::Unit::StaticData)) free(const_cast<Unit *>(data)); +#else + // Unconditionally free the memory. In the dev tools we create units that have + // the flag set and will be saved to disk, so intended to persist later. + free(const_cast<Unit *>(data)); +#endif } data = nullptr; #if Q_BYTE_ORDER == Q_BIG_ENDIAN @@ -119,6 +126,7 @@ CompilationUnit::~CompilationUnit() delete [] imports; imports = nullptr; } +#ifndef V4_BOOTSTRAP QString CompilationUnit::localCacheFilePath(const QUrl &url) { diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index fe3e6bad6e..4cfd2d86e8 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -1095,11 +1095,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit final : public CompilationUnitBase const QmlUnit *qmlData = nullptr; public: CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString()); -#ifdef V4_BOOTSTRAP - ~CompilationUnit() {} -#else ~CompilationUnit(); -#endif void addref() { diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 97b955632d..a2c8e3916f 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -79,6 +79,53 @@ void Heap::QQmlContextWrapper::destroy() Object::destroy(); } +static OptionalReturnedValue searchContextProperties(QV4::ExecutionEngine *v4, QQmlContextData *context, String *name, + bool *hasProperty, Value *base, QV4::Lookup *lookup, + QV4::Lookup *originalLookup, QQmlEnginePrivate *ep) +{ + const QV4::IdentifierHash &properties = context->propertyNames(); + if (properties.count() == 0) + return OptionalReturnedValue(); + + const int propertyIdx = properties.value(name); + + if (propertyIdx == -1) + return OptionalReturnedValue(); + + if (propertyIdx < context->idValueCount) { + if (hasProperty) + *hasProperty = true; + + if (lookup) { + lookup->qmlContextIdObjectLookup.objectId = propertyIdx; + lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupIdObject; + return OptionalReturnedValue(lookup->qmlContextPropertyGetter(lookup, v4, base)); + } else if (originalLookup) { + originalLookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupInParentContextHierarchy; + } + + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); + return OptionalReturnedValue(QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx])); + } + + QQmlContextPrivate *cp = context->asQQmlContextPrivate(); + + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); + + const QVariant &value = cp->propertyValues.at(propertyIdx); + if (hasProperty) + *hasProperty = true; + if (value.userType() == qMetaTypeId<QList<QObject*> >()) { + QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), + QQmlContextPrivate::context_count, + QQmlContextPrivate::context_at); + return OptionalReturnedValue(QmlListWrapper::create(v4, prop, qMetaTypeId<QQmlListProperty<QObject> >())); + } + return OptionalReturnedValue(v4->fromVariant(cp->propertyValues.at(propertyIdx))); +} + ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, bool *hasProperty, Value *base, Lookup *lookup) { if (!id.isString()) @@ -224,47 +271,8 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r } while (context) { - // Search context properties - const QV4::IdentifierHash &properties = context->propertyNames(); - if (properties.count()) { - int propertyIdx = properties.value(name); - - if (propertyIdx != -1) { - - if (propertyIdx < context->idValueCount) { - if (hasProperty) - *hasProperty = true; - - if (lookup) { - lookup->qmlContextIdObjectLookup.objectId = propertyIdx; - lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupIdObject; - return lookup->qmlContextPropertyGetter(lookup, v4, base); - } - - if (ep->propertyCapture) - ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); - return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]); - } else { - - QQmlContextPrivate *cp = context->asQQmlContextPrivate(); - - if (ep->propertyCapture) - ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); - - const QVariant &value = cp->propertyValues.at(propertyIdx); - if (hasProperty) - *hasProperty = true; - if (value.userType() == qMetaTypeId<QList<QObject*> >()) { - QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), - QQmlContextPrivate::context_count, - QQmlContextPrivate::context_at); - return QmlListWrapper::create(v4, prop, qMetaTypeId<QQmlListProperty<QObject> >()); - } else { - return scope.engine->fromVariant(cp->propertyValues.at(propertyIdx)); - } - } - } - } + if (auto property = searchContextProperties(v4, context, name, hasProperty, base, lookup, originalLookup, ep)) + return *property; // Search scope object if (scopeObject) { @@ -311,17 +319,21 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r if (base) *base = QV4::QObjectWrapper::wrap(v4, context->contextObject); - if (lookup && propertyData) { - QQmlData *ddata = QQmlData::get(context->contextObject, false); - if (ddata && ddata->propertyCache) { - ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); - const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); - lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = propertyData; - lookup->qmlContextPropertyGetter = contextGetterFunction; + if (propertyData) { + if (lookup) { + QQmlData *ddata = QQmlData::get(context->contextObject, false); + if (ddata && ddata->propertyCache) { + ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); + const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); + lookup->qobjectLookup.ic = That->internalClass(); + lookup->qobjectLookup.staticQObject = nullptr; + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = propertyData; + lookup->qmlContextPropertyGetter = contextGetterFunction; + } + } else if (originalLookup) { + originalLookup->qmlContextPropertyGetter = lookupInParentContextHierarchy; } } @@ -576,6 +588,55 @@ ReturnedValue QQmlContextWrapper::lookupInGlobalObject(Lookup *l, ExecutionEngin return result; } +ReturnedValue QQmlContextWrapper::lookupInParentContextHierarchy(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Scope scope(engine); + Scoped<QmlContext> qmlContext(scope, engine->qmlContext()); + if (!qmlContext) + return QV4::Encode::undefined(); + + QQmlContextData *context = qmlContext->qmlContext(); + if (!context) + return QV4::Encode::undefined(); + + QQmlContextData *expressionContext = context; + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine()); + + PropertyKey id =engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit-> + runtimeStrings[l->nameIndex]); + ScopedString name(scope, id.asStringOrSymbol()); + + ScopedValue result(scope); + + for (context = context->parent; context; context = context->parent) { + if (auto property = searchContextProperties(engine, context, name, nullptr, base, nullptr, nullptr, ep)) + return *property; + + // Search context object + if (context->contextObject) { + bool hasProp = false; + result = QV4::QObjectWrapper::getQmlProperty(engine, context, context->contextObject, + name, QV4::QObjectWrapper::CheckRevision, &hasProp); + if (hasProp) { + if (base) + *base = QV4::QObjectWrapper::wrap(engine, context->contextObject); + + return result->asReturnedValue(); + } + } + } + + bool hasProp = false; + result = engine->globalObject->get(name, &hasProp); + if (hasProp) + return result->asReturnedValue(); + + expressionContext->unresolvedNames = true; + + return Encode::undefined(); +} + void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml) { Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 6375294375..4c8287ef2f 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -111,6 +111,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object static ReturnedValue lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base); + static ReturnedValue lookupInParentContextHierarchy(Lookup *l, ExecutionEngine *engine, Value *base); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 8ae51a795f..0c947b541b 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -249,7 +249,7 @@ #include <QtCore/qlist.h> #include <QtCore/qstring.h> -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { @@ -486,7 +486,7 @@ protected: using namespace QQmlJS; -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE void Parser::reallocateStack() { @@ -4476,12 +4476,12 @@ ExportSpecifier: IdentifierName T_AS IdentifierName; return false; } -QT_QML_END_NAMESPACE +QT_END_NAMESPACE ./ /: -QT_QML_END_NAMESPACE +QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 54a1200493..e5817ab763 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -41,7 +41,7 @@ #include "qqmljsastvisitor_p.h" -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { @@ -1474,6 +1474,6 @@ LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast() } } // namespace QQmlJS::AST -QT_QML_END_NAMESPACE +QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index e84c62af2f..b81553776d 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -57,7 +57,7 @@ #include <QtCore/qstring.h> -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE #define QQMLJS_DECLARE_AST_NODE(name) \ enum { K = Kind_##name }; @@ -3395,6 +3395,6 @@ public: -QT_QML_END_NAMESPACE +QT_END_NAMESPACE #endif diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index 7795e0ce71..e9caa918d5 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -56,7 +56,7 @@ // We mean it. // -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { @@ -181,6 +181,6 @@ class UiEnumMemberList; } } // namespace AST -QT_QML_END_NAMESPACE +QT_END_NAMESPACE #endif diff --git a/src/qml/parser/qqmljsastvisitor.cpp b/src/qml/parser/qqmljsastvisitor.cpp index 666623eecc..5ecac36423 100644 --- a/src/qml/parser/qqmljsastvisitor.cpp +++ b/src/qml/parser/qqmljsastvisitor.cpp @@ -39,7 +39,7 @@ #include "qqmljsastvisitor_p.h" -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { @@ -53,4 +53,4 @@ Visitor::~Visitor() } } // namespace QQmlJS::AST -QT_QML_END_NAMESPACE +QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 9c69f88e0c..9115449a46 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -54,7 +54,7 @@ #include "qqmljsastfwd_p.h" #include "qqmljsglobal_p.h" -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { @@ -412,6 +412,6 @@ protected: } } // namespace AST -QT_QML_END_NAMESPACE +QT_END_NAMESPACE #endif // QQMLJSASTVISITOR_P_H diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp index 97ce6ebea3..bb27f3992e 100644 --- a/src/qml/parser/qqmljsengine_p.cpp +++ b/src/qml/parser/qqmljsengine_p.cpp @@ -44,7 +44,7 @@ #include <QtCore/qhash.h> #include <QtCore/qdebug.h> -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { @@ -155,4 +155,4 @@ QStringRef Engine::newStringRef(const QChar *chars, int size) } // end of namespace QQmlJS -QT_QML_END_NAMESPACE +QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h index 07b5026eb9..b7f7da9478 100644 --- a/src/qml/parser/qqmljsengine_p.h +++ b/src/qml/parser/qqmljsengine_p.h @@ -58,7 +58,7 @@ #include <QtCore/qstring.h> #include <QtCore/qset.h> -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { @@ -150,6 +150,6 @@ double integerFromString(const char *buf, int size, int radix); } // end of namespace QQmlJS -QT_QML_END_NAMESPACE +QT_END_NAMESPACE #endif // QQMLJSENGINE_P_H diff --git a/src/qml/parser/qqmljsglobal_p.h b/src/qml/parser/qqmljsglobal_p.h index 0e195994b4..bf8155c6ec 100644 --- a/src/qml/parser/qqmljsglobal_p.h +++ b/src/qml/parser/qqmljsglobal_p.h @@ -53,8 +53,6 @@ #include <QtCore/qglobal.h> #ifdef QT_CREATOR -# define QT_QML_BEGIN_NAMESPACE -# define QT_QML_END_NAMESPACE # ifdef QDECLARATIVEJS_BUILD_DIR # define QML_PARSER_EXPORT Q_DECL_EXPORT @@ -65,8 +63,6 @@ # endif // QQMLJS_BUILD_DIR #else // !QT_CREATOR -# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE -# define QT_QML_END_NAMESPACE QT_END_NAMESPACE # ifndef QT_STATIC # if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) // QmlDevTools is a static library diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h index b0a4951ece..96b3709162 100644 --- a/src/qml/parser/qqmljskeywords_p.h +++ b/src/qml/parser/qqmljskeywords_p.h @@ -53,7 +53,7 @@ #include "qqmljslexer_p.h" -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { @@ -918,6 +918,6 @@ int Lexer::classify(const QChar *s, int n, int parseModeFlags) { } // namespace QQmlJS -QT_QML_END_NAMESPACE +QT_END_NAMESPACE #endif // QQMLJSKEYWORDS_P_H diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h index 03f33f6e06..51152bfd6e 100644 --- a/src/qml/parser/qqmljslexer_p.h +++ b/src/qml/parser/qqmljslexer_p.h @@ -57,7 +57,7 @@ #include <QtCore/qstring.h> #include <QtCore/qstack.h> -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { @@ -257,6 +257,6 @@ private: } // end of namespace QQmlJS -QT_QML_END_NAMESPACE +QT_END_NAMESPACE #endif // LEXER_H diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h index bcd6d8672b..e7b1f46414 100644 --- a/src/qml/parser/qqmljsmemorypool_p.h +++ b/src/qml/parser/qqmljsmemorypool_p.h @@ -59,7 +59,7 @@ #include <cstring> -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { @@ -251,6 +251,6 @@ public: } // namespace QQmlJS -QT_QML_END_NAMESPACE +QT_END_NAMESPACE #endif diff --git a/src/qml/parser/qqmljssourcelocation_p.h b/src/qml/parser/qqmljssourcelocation_p.h index dc307ba168..d76e701d49 100644 --- a/src/qml/parser/qqmljssourcelocation_p.h +++ b/src/qml/parser/qqmljssourcelocation_p.h @@ -55,7 +55,7 @@ // We mean it. // -QT_QML_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE namespace QQmlJS { namespace AST { @@ -82,6 +82,6 @@ public: } } // namespace AST -QT_QML_END_NAMESPACE +QT_END_NAMESPACE #endif diff --git a/src/qmltest/doc/src/qtquicktest-index.qdoc b/src/qmltest/doc/src/qtquicktest-index.qdoc index 4c0124689b..668d6c1417 100644 --- a/src/qmltest/doc/src/qtquicktest-index.qdoc +++ b/src/qmltest/doc/src/qtquicktest-index.qdoc @@ -149,11 +149,13 @@ \header \li Name \li Purpose + \li Since \row \li \c {void applicationAvailable()} \li Called right after the QApplication object was instantiated. - Use this function to setup everything that is not related - to QML directly. + Use this function to perform setup that does not require a + \l QQmlEngine instance. + \li Qt 5.12 \row \li \c {void qmlEngineAvailable(QQmlEngine *)} \li Called when the QML engine is available. @@ -161,10 +163,17 @@ \l {QQmlEngine::addPluginPath}{plugin paths}, and \l {QQmlFileSelector::setExtraSelectors}{extra file selectors} will have been set on the engine by this point. + + This function can be used to \l {Choosing the Correct Integration + Method Between C++ and QML}{register QML types} and + \l {QQmlEngine::addImportPath()}{add import paths}, + amongst other things. + \li Qt 5.11 \row \li \c {void cleanupTestCase()} \li Called right after the test execution has finished. Use this function to clean up before everything will start to be destructed. + \li Qt 5.12 \endtable Each function will be called once for each \c {tst_*.qml} file, so any diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index 9a73726797..9cddf61543 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -575,6 +575,13 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch qmlFileSelector->setExtraSelectors(fileSelectors); } + // Do this down here so that import paths, plugin paths, file selectors, etc. are available + // in case the user needs access to them. Do it _before_ the TestCaseCollector parses the + // QML files though, because it attempts to import modules, which might not be available + // if qmlRegisterType()/QQmlEngine::addImportPath() are called in qmlEngineAvailable(). + if (setup) + maybeInvokeSetupMethod(setup, "qmlEngineAvailable(QQmlEngine*)", Q_ARG(QQmlEngine*, &engine)); + TestCaseCollector testCaseCollector(fi, &engine); if (!testCaseCollector.errors().isEmpty()) { for (const QQmlError &error : testCaseCollector.errors()) @@ -606,11 +613,6 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch view.rootContext()->setContextProperty (QLatin1String("qtest"), QTestRootObject::instance()); // Deprecated. Use QTestRootObject from Qt.test.qtestroot instead - // Do this down here so that import paths, plugin paths, - // file selectors, etc. are available in case the user needs access to them. - if (setup) - maybeInvokeSetupMethod(setup, "qmlEngineAvailable(QQmlEngine*)", Q_ARG(QQmlEngine*, view.engine())); - view.setObjectName(fi.baseName()); view.setTitle(view.objectName()); QTestRootObject::instance()->init(); |