diff options
Diffstat (limited to 'src/quick')
141 files changed, 5148 insertions, 1996 deletions
diff --git a/src/quick/designer/designer.pri b/src/quick/designer/designer.pri index 9f3f7e8be6..eb2141134d 100644 --- a/src/quick/designer/designer.pri +++ b/src/quick/designer/designer.pri @@ -1,4 +1,21 @@ -HEADERS += designer/designersupport.h \ - designer/designerwindowmanager_p.h -SOURCES += designer/designersupport.cpp \ - designer/designerwindowmanager.cpp +HEADERS += \ + designer/qquickdesignercustomobjectdata_p.h \ + designer/qquickdesignersupportitems_p.h \ + designer/qquickdesignerwindowmanager_p.h \ + designer/qquickdesignersupportstates_p.h \ + designer/qquickdesignersupportpropertychanges_p.h \ + designer/qquickdesignersupportproperties_p.h \ + designer/qquickdesignersupportmetainfo_p.h \ + designer/qqmldesignermetaobject_p.h \ + designer/qquickdesignersupport_p.h + +SOURCES += \ + designer/qquickdesignercustomobjectdata.cpp \ + designer/qquickdesignersupport.cpp \ + designer/qquickdesignersupportitems.cpp \ + designer/qquickdesignersupportmetainfo.cpp \ + designer/qquickdesignersupportproperties.cpp \ + designer/qquickdesignersupportpropertychanges.cpp \ + designer/qquickdesignersupportstates.cpp \ + designer/qquickdesignerwindowmanager.cpp \ + designer/qqmldesignermetaobject.cpp diff --git a/src/quick/designer/qqmldesignermetaobject.cpp b/src/quick/designer/qqmldesignermetaobject.cpp new file mode 100644 index 0000000000..4273c0fbc2 --- /dev/null +++ b/src/quick/designer/qqmldesignermetaobject.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmldesignermetaobject_p.h" + +#include <QSharedPointer> +#include <QMetaProperty> +#include <qnumeric.h> +#include <QDebug> + +#include <private/qqmlengine_p.h> +#include <private/qqmlpropertycache_p.h> + +QT_BEGIN_NAMESPACE + +static QHash<QDynamicMetaObjectData *, bool> nodeInstanceMetaObjectList; +static void (*notifyPropertyChangeCallBack)(QObject*, const QQuickDesignerSupport::PropertyName &propertyName) = 0; + +struct MetaPropertyData { + inline QPair<QVariant, bool> &getDataRef(int idx) { + while (m_data.count() <= idx) + m_data << QPair<QVariant, bool>(QVariant(), false); + return m_data[idx]; + } + + inline QVariant &getData(int idx) { + QPair<QVariant, bool> &prop = getDataRef(idx); + if (!prop.second) { + prop.first = QVariant(); + prop.second = true; + } + return prop.first; + } + + inline bool hasData(int idx) const { + if (idx >= m_data.count()) + return false; + return m_data[idx].second; + } + + inline int count() { return m_data.count(); } + + QVector<QPair<QVariant, bool> > m_data; +}; + +static bool constructedMetaData(const QQmlVMEMetaData* data) +{ + return data->varPropertyCount == 0 + && data->propertyCount == 0 + && data->aliasCount == 0 + && data->signalCount == 0 + && data->methodCount == 0; +} + +static QQmlVMEMetaData* fakeMetaData() +{ + QQmlVMEMetaData* data = new QQmlVMEMetaData; + data->varPropertyCount = 0; + data->propertyCount = 0; + data->aliasCount = 0; + data->signalCount = 0; + data->methodCount = 0; + + return data; +} + +static const QQmlVMEMetaData* vMEMetaDataForObject(QObject *object) +{ + QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object); + if (metaObject) + return metaObject->metaData; + + return fakeMetaData(); +} + +static QQmlPropertyCache *cacheForObject(QObject *object, QQmlEngine *engine) +{ + QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object); + if (metaObject) + return metaObject->cache; + + return QQmlEnginePrivate::get(engine)->cache(object); +} + +QQmlDesignerMetaObject* QQmlDesignerMetaObject::getNodeInstanceMetaObject(QObject *object, QQmlEngine *engine) +{ + //Avoid setting up multiple MetaObjects on the same QObject + QObjectPrivate *op = QObjectPrivate::get(object); + QDynamicMetaObjectData *parent = op->metaObject; + if (nodeInstanceMetaObjectList.contains(parent)) + return static_cast<QQmlDesignerMetaObject *>(parent); + + // we just create one and the ownership goes automatically to the object in nodeinstance see init method + return new QQmlDesignerMetaObject(object, engine); +} + +void QQmlDesignerMetaObject::init(QObject *object, QQmlEngine *engine) +{ + //Creating QQmlOpenMetaObjectType + m_type = new QQmlOpenMetaObjectType(metaObjectParent(), engine); + m_type->addref(); + //Assigning type to this + copyTypeMetaObject(); + + //Assign this to object + QObjectPrivate *op = QObjectPrivate::get(object); + op->metaObject = this; + + //create cache + cache = m_cache = QQmlEnginePrivate::get(engine)->cache(this); + cache->addref(); + + //If our parent is not a VMEMetaObject we just se the flag to false again + if (constructedMetaData(metaData)) + QQmlData::get(object)->hasVMEMetaObject = false; + + nodeInstanceMetaObjectList.insert(this, true); + hasAssignedMetaObjectData = true; +} + +QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine) + : QQmlVMEMetaObject(object, cacheForObject(object, engine), vMEMetaDataForObject(object)), + m_context(engine->contextForObject(object)), + m_data(new MetaPropertyData), + m_cache(0) +{ + init(object, engine); + + QQmlData *ddata = QQmlData::get(object, false); + + //Assign cache to object + if (ddata && ddata->propertyCache) { + cache->setParent(ddata->propertyCache); + cache->invalidate(engine, this); + ddata->propertyCache = m_cache; + } + +} + +QQmlDesignerMetaObject::~QQmlDesignerMetaObject() +{ + if (cache->count() > 1) // qml is crashing because the property cache is not removed from the engine + cache->release(); + else + m_type->release(); + + nodeInstanceMetaObjectList.remove(this); +} + +void QQmlDesignerMetaObject::createNewDynamicProperty(const QString &name) +{ + int id = m_type->createProperty(name.toUtf8()); + copyTypeMetaObject(); + setValue(id, QVariant()); + Q_ASSERT(id >= 0); + Q_UNUSED(id); + + //Updating cache + QQmlPropertyCache *oldParent = m_cache->parent(); + QQmlEnginePrivate::get(m_context->engine())->cache(this)->invalidate(m_context->engine(), this); + m_cache->setParent(oldParent); + + QQmlProperty property(myObject(), name, m_context); + Q_ASSERT(property.isValid()); +} + +void QQmlDesignerMetaObject::setValue(int id, const QVariant &value) +{ + QPair<QVariant, bool> &prop = m_data->getDataRef(id); + prop.first = propertyWriteValue(id, value); + prop.second = true; + QMetaObject::activate(myObject(), id + m_type->signalOffset(), 0); +} + +QVariant QQmlDesignerMetaObject::propertyWriteValue(int, const QVariant &value) +{ + return value; +} + +const QAbstractDynamicMetaObject *QQmlDesignerMetaObject::dynamicMetaObjectParent() const +{ + if (QQmlVMEMetaObject::parent.isT1()) + return QQmlVMEMetaObject::parent.asT1()->toDynamicMetaObject(QQmlVMEMetaObject::object); + else + return 0; +} + +const QMetaObject *QQmlDesignerMetaObject::metaObjectParent() const +{ + if (QQmlVMEMetaObject::parent.isT1()) + return QQmlVMEMetaObject::parent.asT1()->toDynamicMetaObject(QQmlVMEMetaObject::object); + + return QQmlVMEMetaObject::parent.asT2(); +} + +int QQmlDesignerMetaObject::propertyOffset() const +{ + return cache->propertyOffset(); +} + +int QQmlDesignerMetaObject::openMetaCall(QMetaObject::Call call, int id, void **a) +{ + if ((call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) + && id >= m_type->propertyOffset()) { + int propId = id - m_type->propertyOffset(); + if (call == QMetaObject::ReadProperty) { + //propertyRead(propId); + *reinterpret_cast<QVariant *>(a[0]) = m_data->getData(propId); + } else if (call == QMetaObject::WriteProperty) { + if (propId <= m_data->count() || m_data->m_data[propId].first != *reinterpret_cast<QVariant *>(a[0])) { + //propertyWrite(propId); + QPair<QVariant, bool> &prop = m_data->getDataRef(propId); + prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])); + prop.second = true; + //propertyWritten(propId); + activate(myObject(), m_type->signalOffset() + propId, 0); + } + } + return -1; + } else { + QAbstractDynamicMetaObject *directParent = parent(); + if (directParent) + return directParent->metaCall(call, id, a); + else + return myObject()->qt_metacall(call, id, a); + } +} + +int QQmlDesignerMetaObject::metaCall(QMetaObject::Call call, int id, void **a) +{ + int metaCallReturnValue = -1; + + const QMetaProperty propertyById = QQmlVMEMetaObject::property(id); + + if (call == QMetaObject::WriteProperty + && propertyById.userType() == QMetaType::QVariant + && reinterpret_cast<QVariant *>(a[0])->type() == QVariant::Double + && qIsNaN(reinterpret_cast<QVariant *>(a[0])->toDouble())) { + return -1; + } + + if (call == QMetaObject::WriteProperty + && propertyById.userType() == QMetaType::Double + && qIsNaN(*reinterpret_cast<double*>(a[0]))) { + return -1; + } + + if (call == QMetaObject::WriteProperty + && propertyById.userType() == QMetaType::Float + && qIsNaN(*reinterpret_cast<float*>(a[0]))) { + return -1; + } + + QVariant oldValue; + + if (call == QMetaObject::WriteProperty && !propertyById.hasNotifySignal()) + { + oldValue = propertyById.read(myObject()); + } + + QAbstractDynamicMetaObject *directParent = parent(); + if (directParent && id < directParent->propertyOffset()) { + metaCallReturnValue = directParent->metaCall(call, id, a); + } else { + openMetaCall(call, id, a); + } + + + if (call == QMetaObject::WriteProperty + && !propertyById.hasNotifySignal() + && oldValue != propertyById.read(myObject())) + notifyPropertyChange(id); + + return metaCallReturnValue; +} + +void QQmlDesignerMetaObject::notifyPropertyChange(int id) +{ + const QMetaProperty propertyById = property(id); + + if (id < propertyOffset()) { + if (notifyPropertyChangeCallBack) + notifyPropertyChangeCallBack(myObject(), propertyById.name()); + } else { + if (notifyPropertyChangeCallBack) + notifyPropertyChangeCallBack(myObject(), name(id - propertyOffset())); + } +} + +int QQmlDesignerMetaObject::count() const +{ + return m_type->propertyCount(); +} + +QByteArray QQmlDesignerMetaObject::name(int idx) const +{ + return m_type->propertyName(idx); +} + +void QQmlDesignerMetaObject::copyTypeMetaObject() +{ + *static_cast<QMetaObject *>(this) = *m_type->metaObject(); +} + +void QQmlDesignerMetaObject::registerNotifyPropertyChangeCallBack(void (*callback)(QObject *, const QQuickDesignerSupport::PropertyName &)) +{ + notifyPropertyChangeCallBack = callback; +} + +QT_END_NAMESPACE diff --git a/src/quick/designer/qqmldesignermetaobject_p.h b/src/quick/designer/qqmldesignermetaobject_p.h new file mode 100644 index 0000000000..eca4fb6a99 --- /dev/null +++ b/src/quick/designer/qqmldesignermetaobject_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NODEINSTANCEMETAOBJECT_H +#define NODEINSTANCEMETAOBJECT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdesignersupport_p.h" + +#include <QQmlContext> +#include <QScopedPointer> +#include <private/qqmlopenmetaobject_p.h> +#include <private/qqmlvmemetaobject_p.h> + +QT_BEGIN_NAMESPACE + +struct MetaPropertyData; + +class QQmlDesignerMetaObject : public QQmlVMEMetaObject +{ +public: + ~QQmlDesignerMetaObject(); + + static void registerNotifyPropertyChangeCallBack(void (*callback)(QObject*, const QQuickDesignerSupport::PropertyName &propertyName)); + +protected: + QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine); + static QQmlDesignerMetaObject* getNodeInstanceMetaObject(QObject *object, QQmlEngine *engine); + + void createNewDynamicProperty(const QString &name); + int openMetaCall(QMetaObject::Call _c, int _id, void **_a); + int metaCall(QMetaObject::Call _c, int _id, void **_a); + void notifyPropertyChange(int id); + void setValue(int id, const QVariant &value); + QVariant propertyWriteValue(int, const QVariant &); + + QObject *myObject() const { return QQmlVMEMetaObject::object; } + QAbstractDynamicMetaObject *parent() const { return const_cast<QAbstractDynamicMetaObject *>(dynamicMetaObjectParent()); } + + const QAbstractDynamicMetaObject *dynamicMetaObjectParent() const; + + const QMetaObject *metaObjectParent() const; + + int propertyOffset() const; + + int count() const; + QByteArray name(int) const; + + void copyTypeMetaObject(); + +private: + void init(QObject *, QQmlEngine *engine); + + QPointer<QQmlContext> m_context; + QQmlOpenMetaObjectType *m_type; + QScopedPointer<MetaPropertyData> m_data; + //QAbstractDynamicMetaObject *m_parent; + QQmlPropertyCache *m_cache; + + friend class QQuickDesignerSupportProperties; +}; + +QT_END_NAMESPACE + +#endif // NODEINSTANCEMETAOBJECT_H diff --git a/src/quick/designer/qquickdesignercustomobjectdata.cpp b/src/quick/designer/qquickdesignercustomobjectdata.cpp new file mode 100644 index 0000000000..1666ffb0a5 --- /dev/null +++ b/src/quick/designer/qquickdesignercustomobjectdata.cpp @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdesignersupportmetainfo_p.h" +#include "qquickdesignersupportproperties_p.h" + +#include "qquickdesignercustomobjectdata_p.h" + +#include <QGlobalStatic> +#include <QQmlContext> +#include <QQmlEngine> + +#include <private/qqmlbinding_p.h> + +QT_BEGIN_NAMESPACE + +typedef QHash<QObject*, QQuickDesignerCustomObjectData*> CustomObjectDataHash; +Q_GLOBAL_STATIC(CustomObjectDataHash, s_designerObjectToDataHash) + +struct HandleDestroyedFunctor { + QQuickDesignerCustomObjectData *data; + void operator()() { data->handleDestroyed(); } +}; + +QQuickDesignerCustomObjectData::QQuickDesignerCustomObjectData(QObject *object) + : m_object(object) +{ + if (object) { + populateResetHashes(); + s_designerObjectToDataHash()->insert(object, this); + + HandleDestroyedFunctor functor; + functor.data = this; + QObject::connect(object, &QObject::destroyed, functor); + } +} + +void QQuickDesignerCustomObjectData::registerData(QObject *object) +{ + new QQuickDesignerCustomObjectData(object); +} + +QQuickDesignerCustomObjectData *QQuickDesignerCustomObjectData::get(QObject *object) +{ + return s_designerObjectToDataHash()->value(object); +} + +QVariant QQuickDesignerCustomObjectData::getResetValue(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQuickDesignerCustomObjectData* data = get(object); + + if (data) + return data->getResetValue(propertyName); + + return QVariant(); +} + +void QQuickDesignerCustomObjectData::doResetProperty(QObject *object, QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQuickDesignerCustomObjectData* data = get(object); + + if (data) + data->doResetProperty(context, propertyName); +} + +bool QQuickDesignerCustomObjectData::hasValidResetBinding(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQuickDesignerCustomObjectData* data = get(object); + + if (data) + return data->hasValidResetBinding(propertyName); + + return false; +} + +bool QQuickDesignerCustomObjectData::hasBindingForProperty(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + bool *hasChanged) +{ + QQuickDesignerCustomObjectData* data = get(object); + + if (data) + return data->hasBindingForProperty(context, propertyName, hasChanged); + + return false; +} + +void QQuickDesignerCustomObjectData::setPropertyBinding(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + const QString &expression) +{ + QQuickDesignerCustomObjectData* data = get(object); + + if (data) + data->setPropertyBinding(context, propertyName, expression); +} + +void QQuickDesignerCustomObjectData::keepBindingFromGettingDeleted(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQuickDesignerCustomObjectData* data = get(object); + + if (data) + data->keepBindingFromGettingDeleted(context, propertyName); +} + +void QQuickDesignerCustomObjectData::populateResetHashes() +{ + QQuickDesignerSupport::PropertyNameList propertyNameList = + QQuickDesignerSupportProperties::propertyNameListForWritableProperties(object()); + + Q_FOREACH (const QQuickDesignerSupport::PropertyName &propertyName, propertyNameList) { + QQmlProperty property(object(), QString::fromUtf8(propertyName), QQmlEngine::contextForObject(object())); + + QQmlAbstractBinding::Ptr binding = QQmlAbstractBinding::Ptr(QQmlPropertyPrivate::binding(property)); + + if (binding) { + m_resetBindingHash.insert(propertyName, binding); + } else if (property.isWritable()) { + m_resetValueHash.insert(propertyName, property.read()); + } + } +} + +QObject *QQuickDesignerCustomObjectData::object() const +{ + return m_object; +} + +QVariant QQuickDesignerCustomObjectData::getResetValue(const QQuickDesignerSupport::PropertyName &propertyName) const +{ + return m_resetValueHash.value(propertyName); +} + +void QQuickDesignerCustomObjectData::doResetProperty(QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQmlProperty property(object(), QString::fromUtf8(propertyName), context); + + if (!property.isValid()) + return; + + QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(property); + if (binding && !(hasValidResetBinding(propertyName) && getResetBinding(propertyName) == binding)) { + binding->setEnabled(false, 0); + } + + + if (hasValidResetBinding(propertyName)) { + QQmlAbstractBinding *binding = getResetBinding(propertyName); + + QQmlBinding *qmlBinding = dynamic_cast<QQmlBinding*>(binding); + if (qmlBinding) + qmlBinding->setTarget(property); + QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding); + if (qmlBinding) + qmlBinding->update(); + + } else if (property.isResettable()) { + property.reset(); + } else if (property.propertyTypeCategory() == QQmlProperty::List) { + QQmlListReference list = qvariant_cast<QQmlListReference>(property.read()); + + if (!QQuickDesignerSupportProperties::hasFullImplementedListInterface(list)) { + qWarning() << "Property list interface not fully implemented for Class " << property.property().typeName() << " in property " << property.name() << "!"; + return; + } + + list.clear(); + } else if (property.isWritable()) { + if (property.read() == getResetValue(propertyName)) + return; + + property.write(getResetValue(propertyName)); + } +} + +bool QQuickDesignerCustomObjectData::hasValidResetBinding(const QQuickDesignerSupport::PropertyName &propertyName) const +{ + return m_resetBindingHash.contains(propertyName) && m_resetBindingHash.value(propertyName).data(); +} + +QQmlAbstractBinding *QQuickDesignerCustomObjectData::getResetBinding(const QQuickDesignerSupport::PropertyName &propertyName) const +{ + return m_resetBindingHash.value(propertyName).data(); +} + +bool QQuickDesignerCustomObjectData::hasBindingForProperty(QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + bool *hasChanged) const +{ + if (QQuickDesignerSupportProperties::isPropertyBlackListed(propertyName)) + return false; + + QQmlProperty property(object(), QString::fromUtf8(propertyName), context); + + bool hasBinding = QQmlPropertyPrivate::binding(property); + + if (hasChanged) { + *hasChanged = hasBinding != m_hasBindingHash.value(propertyName, false); + if (*hasChanged) + m_hasBindingHash.insert(propertyName, hasBinding); + } + + return QQmlPropertyPrivate::binding(property); +} + +void QQuickDesignerCustomObjectData::setPropertyBinding(QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + const QString &expression) +{ + QQmlProperty property(object(), QString::fromUtf8(propertyName), context); + + if (!property.isValid()) + return; + + if (property.isProperty()) { + QQmlBinding *binding = new QQmlBinding(expression, object(), context); + binding->setTarget(property); + binding->setNotifyOnValueChanged(true); + + QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding); + //Refcounting is taking take care of deletion + binding->update(); + if (binding->hasError()) { + if (property.property().userType() == QVariant::String) + property.write(QVariant(QLatin1Char('#') + expression + QLatin1Char('#'))); + } + + } else { + qWarning() << Q_FUNC_INFO << ": Cannot set binding for property" << propertyName << ": property is unknown for type"; + } +} + +void QQuickDesignerCustomObjectData::keepBindingFromGettingDeleted(QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName) +{ + //Refcounting is taking care + Q_UNUSED(context) + Q_UNUSED(propertyName) +} + +void QQuickDesignerCustomObjectData::handleDestroyed() +{ + s_designerObjectToDataHash()->remove(m_object); + delete this; +} + +QT_END_NAMESPACE + diff --git a/src/quick/designer/qquickdesignercustomobjectdata_p.h b/src/quick/designer/qquickdesignercustomobjectdata_p.h new file mode 100644 index 0000000000..6734540a54 --- /dev/null +++ b/src/quick/designer/qquickdesignercustomobjectdata_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERCUSTOMOBJECTDATA_H +#define DESIGNERCUSTOMOBJECTDATA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdesignersupport_p.h" + +#include <QHash> +#include <QObject> +#include <QVariant> + +#include <private/qqmlbinding_p.h> + +QT_BEGIN_NAMESPACE +class QQmlContext; + +class QQuickDesignerCustomObjectData +{ +public: + static void registerData(QObject *object); + static QQuickDesignerCustomObjectData *get(QObject *object); + static QVariant getResetValue(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName); + static void doResetProperty(QObject *object, QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName); + static bool hasValidResetBinding(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName); + static bool hasBindingForProperty(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + bool *hasChanged); + static void setPropertyBinding(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + const QString &expression); + static void keepBindingFromGettingDeleted(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName); + void handleDestroyed(); + +private: + QQuickDesignerCustomObjectData(QObject *object); + void populateResetHashes(); + QObject *object() const; + QVariant getResetValue(const QQuickDesignerSupport::PropertyName &propertyName) const; + void doResetProperty(QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName); + bool hasValidResetBinding(const QQuickDesignerSupport::PropertyName &propertyName) const; + QQmlAbstractBinding *getResetBinding(const QQuickDesignerSupport::PropertyName &propertyName) const; + bool hasBindingForProperty(QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName, bool *hasChanged) const; + void setPropertyBinding(QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName, const QString &expression); + void keepBindingFromGettingDeleted(QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName); + + QObject *m_object; + QHash<QQuickDesignerSupport::PropertyName, QVariant> m_resetValueHash; + QHash<QQuickDesignerSupport::PropertyName, QQmlAbstractBinding::Ptr> m_resetBindingHash; + mutable QHash<QQuickDesignerSupport::PropertyName, bool> m_hasBindingHash; +}; + +QT_END_NAMESPACE + +#endif // DESIGNERCUSTOMOBJECTDATA_H diff --git a/src/quick/designer/designersupport.cpp b/src/quick/designer/qquickdesignersupport.cpp index 56d2badb62..bc6352a677 100644 --- a/src/quick/designer/designersupport.cpp +++ b/src/quick/designer/qquickdesignersupport.cpp @@ -31,7 +31,7 @@ ** ****************************************************************************/ -#include "designersupport.h" +#include "qquickdesignersupport_p.h" #include <private/qquickitem_p.h> #include <QtQuick/private/qquickshadereffectsource_p.h> @@ -46,16 +46,16 @@ #include <private/qqmlcomponentattached_p.h> #include <private/qqmldata_p.h> -#include "designerwindowmanager_p.h" +#include "qquickdesignerwindowmanager_p.h" QT_BEGIN_NAMESPACE -DesignerSupport::DesignerSupport() +QQuickDesignerSupport::QQuickDesignerSupport() { } -DesignerSupport::~DesignerSupport() +QQuickDesignerSupport::~QQuickDesignerSupport() { typedef QHash<QQuickItem*, QSGLayer*>::iterator ItemTextureHashIt; @@ -67,7 +67,7 @@ DesignerSupport::~DesignerSupport() } } -void DesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool hide) +void QQuickDesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool hide) { if (referencedItem == 0) return; @@ -100,7 +100,7 @@ void DesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool hide) } } -void DesignerSupport::derefFromEffectItem(QQuickItem *referencedItem, bool unhide) +void QQuickDesignerSupport::derefFromEffectItem(QQuickItem *referencedItem, bool unhide) { if (referencedItem == 0) return; @@ -109,7 +109,7 @@ void DesignerSupport::derefFromEffectItem(QQuickItem *referencedItem, bool unhid QQuickItemPrivate::get(referencedItem)->derefFromEffectItem(unhide); } -QImage DesignerSupport::renderImageForItem(QQuickItem *referencedItem, const QRectF &boundingRect, const QSize &imageSize) +QImage QQuickDesignerSupport::renderImageForItem(QQuickItem *referencedItem, const QRectF &boundingRect, const QSize &imageSize) { if (referencedItem == 0 || referencedItem->parentItem() == 0) { qDebug() << __FILE__ << __LINE__ << "Warning: Item can be rendered."; @@ -136,7 +136,7 @@ QImage DesignerSupport::renderImageForItem(QQuickItem *referencedItem, const QRe return renderImage; } -bool DesignerSupport::isDirty(QQuickItem *referencedItem, DirtyType dirtyType) +bool QQuickDesignerSupport::isDirty(QQuickItem *referencedItem, DirtyType dirtyType) { if (referencedItem == 0) return false; @@ -144,7 +144,7 @@ bool DesignerSupport::isDirty(QQuickItem *referencedItem, DirtyType dirtyType) return QQuickItemPrivate::get(referencedItem)->dirtyAttributes & dirtyType; } -void DesignerSupport::addDirty(QQuickItem *referencedItem, DesignerSupport::DirtyType dirtyType) +void QQuickDesignerSupport::addDirty(QQuickItem *referencedItem, QQuickDesignerSupport::DirtyType dirtyType) { if (referencedItem == 0) return; @@ -152,7 +152,7 @@ void DesignerSupport::addDirty(QQuickItem *referencedItem, DesignerSupport::Dirt QQuickItemPrivate::get(referencedItem)->dirtyAttributes |= dirtyType; } -void DesignerSupport::resetDirty(QQuickItem *referencedItem) +void QQuickDesignerSupport::resetDirty(QQuickItem *referencedItem) { if (referencedItem == 0) return; @@ -161,7 +161,7 @@ void DesignerSupport::resetDirty(QQuickItem *referencedItem) QQuickItemPrivate::get(referencedItem)->removeFromDirtyList(); } -QTransform DesignerSupport::windowTransform(QQuickItem *referencedItem) +QTransform QQuickDesignerSupport::windowTransform(QQuickItem *referencedItem) { if (referencedItem == 0) return QTransform(); @@ -169,7 +169,7 @@ QTransform DesignerSupport::windowTransform(QQuickItem *referencedItem) return QQuickItemPrivate::get(referencedItem)->itemToWindowTransform(); } -QTransform DesignerSupport::parentTransform(QQuickItem *referencedItem) +QTransform QQuickDesignerSupport::parentTransform(QQuickItem *referencedItem) { if (referencedItem == 0) return QTransform(); @@ -211,12 +211,9 @@ bool isValidAnchorName(const QString &name) return anchorNameList.contains(name); } -bool DesignerSupport::isAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem) +bool QQuickDesignerSupport::isAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem) { -#ifndef QT_NO_DYNAMIC_CAST - Q_ASSERT(dynamic_cast<QQuickItemPrivate*>(QQuickItemPrivate::get(fromItem))); -#endif - QQuickItemPrivate *fromItemPrivate = static_cast<QQuickItemPrivate*>(QQuickItemPrivate::get(fromItem)); + QQuickItemPrivate *fromItemPrivate = QQuickItemPrivate::get(fromItem); QQuickAnchors *anchors = fromItemPrivate->anchors(); return anchors->fill() == toItem || anchors->centerIn() == toItem @@ -229,9 +226,9 @@ bool DesignerSupport::isAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem) || anchors->baseline().item == toItem; } -bool DesignerSupport::areChildrenAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem) +bool QQuickDesignerSupport::areChildrenAnchoredTo(QQuickItem *fromItem, QQuickItem *toItem) { - foreach (QQuickItem *childItem, fromItem->childItems()) { + Q_FOREACH (QQuickItem *childItem, fromItem->childItems()) { if (childItem) { if (isAnchoredTo(childItem, toItem)) return true; @@ -246,7 +243,7 @@ bool DesignerSupport::areChildrenAnchoredTo(QQuickItem *fromItem, QQuickItem *to QQuickAnchors *anchors(QQuickItem *item) { - QQuickItemPrivate *itemPrivate = static_cast<QQuickItemPrivate*>(QQuickItemPrivate::get(item)); + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); return itemPrivate->anchors(); } @@ -278,7 +275,7 @@ QQuickAnchors::Anchor anchorLineFlagForName(const QString &name) return QQuickAnchors::LeftAnchor; } -bool DesignerSupport::hasAnchor(QQuickItem *item, const QString &name) +bool QQuickDesignerSupport::hasAnchor(QQuickItem *item, const QString &name) { if (!isValidAnchorName(name)) return false; @@ -313,19 +310,19 @@ bool DesignerSupport::hasAnchor(QQuickItem *item, const QString &name) return anchors(item)->usedAnchors().testFlag(anchorLineFlagForName(name)); } -QQuickItem *DesignerSupport::anchorFillTargetItem(QQuickItem *item) +QQuickItem *QQuickDesignerSupport::anchorFillTargetItem(QQuickItem *item) { return anchors(item)->fill(); } -QQuickItem *DesignerSupport::anchorCenterInTargetItem(QQuickItem *item) +QQuickItem *QQuickDesignerSupport::anchorCenterInTargetItem(QQuickItem *item) { return anchors(item)->centerIn(); } -QPair<QString, QObject*> DesignerSupport::anchorLineTarget(QQuickItem *item, const QString &name, QQmlContext *context) +QPair<QString, QObject*> QQuickDesignerSupport::anchorLineTarget(QQuickItem *item, const QString &name, QQmlContext *context) { QObject *targetObject = 0; QString targetName; @@ -350,7 +347,7 @@ QPair<QString, QObject*> DesignerSupport::anchorLineTarget(QQuickItem *item, con return QPair<QString, QObject*>(targetName, targetObject); } -void DesignerSupport::resetAnchor(QQuickItem *item, const QString &name) +void QQuickDesignerSupport::resetAnchor(QQuickItem *item, const QString &name) { if (name == QLatin1String("anchors.fill")) { anchors(item)->resetFill(); @@ -373,7 +370,7 @@ void DesignerSupport::resetAnchor(QQuickItem *item, const QString &name) } } -void DesignerSupport::emitComponentCompleteSignalForAttachedProperty(QQuickItem *item) +void QQuickDesignerSupport::emitComponentCompleteSignalForAttachedProperty(QQuickItem *item) { QQmlData *data = QQmlData::get(item); if (data && data->context) { @@ -384,24 +381,24 @@ void DesignerSupport::emitComponentCompleteSignalForAttachedProperty(QQuickItem } } -QList<QObject*> DesignerSupport::statesForItem(QQuickItem *item) +QList<QObject*> QQuickDesignerSupport::statesForItem(QQuickItem *item) { QList<QObject*> objectList; QList<QQuickState *> stateList = QQuickItemPrivate::get(item)->_states()->states(); objectList.reserve(stateList.size()); - foreach (QQuickState* state, stateList) + Q_FOREACH (QQuickState* state, stateList) objectList.append(state); return objectList; } -bool DesignerSupport::isComponentComplete(QQuickItem *item) +bool QQuickDesignerSupport::isComponentComplete(QQuickItem *item) { - return static_cast<QQuickItemPrivate*>(QQuickItemPrivate::get(item))->componentComplete; + return QQuickItemPrivate::get(item)->componentComplete; } -int DesignerSupport::borderWidth(QQuickItem *item) +int QQuickDesignerSupport::borderWidth(QQuickItem *item) { QQuickRectangle *rectangle = qobject_cast<QQuickRectangle*>(item); if (rectangle) @@ -410,60 +407,71 @@ int DesignerSupport::borderWidth(QQuickItem *item) return 0; } -void DesignerSupport::refreshExpressions(QQmlContext *context) +void QQuickDesignerSupport::refreshExpressions(QQmlContext *context) { QQmlContextPrivate::get(context)->data->refreshExpressions(); } -void DesignerSupport::setRootItem(QQuickView *view, QQuickItem *item) +void QQuickDesignerSupport::setRootItem(QQuickView *view, QQuickItem *item) { QQuickViewPrivate::get(view)->setRootObject(item); } -bool DesignerSupport::isValidWidth(QQuickItem *item) +bool QQuickDesignerSupport::isValidWidth(QQuickItem *item) { return QQuickItemPrivate::get(item)->heightValid; } -bool DesignerSupport::isValidHeight(QQuickItem *item) +bool QQuickDesignerSupport::isValidHeight(QQuickItem *item) { return QQuickItemPrivate::get(item)->widthValid; } -void DesignerSupport::updateDirtyNode(QQuickItem *item) +void QQuickDesignerSupport::updateDirtyNode(QQuickItem *item) { if (item->window()) QQuickWindowPrivate::get(item->window())->updateDirtyNode(item); } -void DesignerSupport::activateDesignerWindowManager() +void QQuickDesignerSupport::activateDesignerWindowManager() { - QSGRenderLoop::setInstance(new DesignerWindowManager); + QSGRenderLoop::setInstance(new QQuickDesignerWindowManager); } -void DesignerSupport::activateDesignerMode() +void QQuickDesignerSupport::activateDesignerMode() { QQmlEnginePrivate::activateDesignerMode(); } -void DesignerSupport::disableComponentComplete() +void QQuickDesignerSupport::disableComponentComplete() { QQmlVME::disableComponentComplete(); } -void DesignerSupport::enableComponentComplete() +void QQuickDesignerSupport::enableComponentComplete() { QQmlVME::enableComponentComplete(); } -void DesignerSupport::createOpenGLContext(QQuickWindow *window) +void QQuickDesignerSupport::createOpenGLContext(QQuickWindow *window) { - DesignerWindowManager::createOpenGLContext(window); + QQuickDesignerWindowManager::createOpenGLContext(window); } -void DesignerSupport::polishItems(QQuickWindow *window) +void QQuickDesignerSupport::polishItems(QQuickWindow *window) { QQuickWindowPrivate::get(window)->polishItems(); } +ComponentCompleteDisabler::ComponentCompleteDisabler() +{ + QQuickDesignerSupport::disableComponentComplete(); +} + +ComponentCompleteDisabler::~ComponentCompleteDisabler() +{ + QQuickDesignerSupport::enableComponentComplete(); +} + + QT_END_NAMESPACE diff --git a/src/quick/designer/designersupport.h b/src/quick/designer/qquickdesignersupport_p.h index 51fcef4512..e15c109f7b 100644 --- a/src/quick/designer/designersupport.h +++ b/src/quick/designer/qquickdesignersupport_p.h @@ -45,7 +45,6 @@ // We mean it. // - #include <QtQuick/qtquickglobal.h> #include <QtCore/QtGlobal> #include <QtCore/QHash> @@ -62,9 +61,13 @@ class QQuickView; class QObject; class QQuickWindow; -class Q_QUICK_EXPORT DesignerSupport +class Q_QUICK_EXPORT QQuickDesignerSupport { public: + typedef QByteArray PropertyName; + typedef QList<PropertyName> PropertyNameList; + typedef QByteArray TypeName; + enum DirtyType { TransformOrigin = 0x00000001, Transform = 0x00000002, @@ -95,8 +98,8 @@ public: }; - DesignerSupport(); - ~DesignerSupport(); + QQuickDesignerSupport(); + ~QQuickDesignerSupport(); void refFromEffectItem(QQuickItem *referencedItem, bool hide = true); void derefFromEffectItem(QQuickItem *referencedItem, bool unhide = true); @@ -119,7 +122,6 @@ public: static void resetAnchor(QQuickItem *item, const QString &name); static void emitComponentCompleteSignalForAttachedProperty(QQuickItem *item); - static QList<QObject*> statesForItem(QQuickItem *item); static bool isComponentComplete(QQuickItem *item); @@ -149,6 +151,16 @@ private: QHash<QQuickItem*, QSGLayer*> m_itemTextureHash; }; +class Q_QUICK_EXPORT ComponentCompleteDisabler +{ +public: + ComponentCompleteDisabler(); + + ~ComponentCompleteDisabler(); +}; + +typedef QQuickDesignerSupport DesignerSupport; + QT_END_NAMESPACE #endif // DESIGNERSUPPORT_H diff --git a/src/quick/designer/qquickdesignersupportitems.cpp b/src/quick/designer/qquickdesignersupportitems.cpp new file mode 100644 index 0000000000..4f23fe6630 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportitems.cpp @@ -0,0 +1,320 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdesignersupportitems_p.h" +#include "qquickdesignersupportproperties_p.h" + +#include <private/qabstractanimation_p.h> +#include <private/qobject_p.h> +#include <private/qquickbehavior_p.h> +#include <private/qquicktext_p.h> +#include <private/qquicktextinput_p.h> +#include <private/qquicktextedit_p.h> +#include <private/qquicktransition_p.h> + +#include <private/qquickanimation_p.h> +#include <private/qqmlmetatype_p.h> +#include <private/qqmltimer_p.h> + +QT_BEGIN_NAMESPACE + +static void (*fixResourcePathsForObjectCallBack)(QObject*) = 0; + +static void stopAnimation(QObject *object) +{ + if (object == 0) + return; + + QQuickTransition *transition = qobject_cast<QQuickTransition*>(object); + QQuickAbstractAnimation *animation = qobject_cast<QQuickAbstractAnimation*>(object); + QQmlTimer *timer = qobject_cast<QQmlTimer*>(object); + if (transition) { + transition->setFromState(QString()); + transition->setToState(QString()); + } else if (animation) { +// QQuickScriptAction *scriptAimation = qobject_cast<QQuickScriptAction*>(animation); +// if (scriptAimation) FIXME +// scriptAimation->setScript(QQmlScriptString()); + animation->setLoops(1); + animation->complete(); + animation->setDisableUserControl(); + } else if (timer) { + timer->blockSignals(true); + } +} + +static void allSubObjects(QObject *object, QObjectList &objectList) +{ + // don't add null pointer and stop if the object is already in the list + if (!object || objectList.contains(object)) + return; + + objectList.append(object); + + for (int index = QObject::staticMetaObject.propertyOffset(); + index < object->metaObject()->propertyCount(); + index++) { + QMetaProperty metaProperty = object->metaObject()->property(index); + + // search recursive in property objects + if (metaProperty.isReadable() + && metaProperty.isWritable() + && QQmlMetaType::isQObject(metaProperty.userType())) { + if (qstrcmp(metaProperty.name(), "parent")) { + QObject *propertyObject = QQmlMetaType::toQObject(metaProperty.read(object)); + allSubObjects(propertyObject, objectList); + } + + } + + // search recursive in property object lists + if (metaProperty.isReadable() + && QQmlMetaType::isList(metaProperty.userType())) { + QQmlListReference list(object, metaProperty.name()); + if (list.canCount() && list.canAt()) { + for (int i = 0; i < list.count(); i++) { + QObject *propertyObject = list.at(i); + allSubObjects(propertyObject, objectList); + + } + } + } + } + + // search recursive in object children list + Q_FOREACH (QObject *childObject, object->children()) { + allSubObjects(childObject, objectList); + } + + // search recursive in quick item childItems list + QQuickItem *quickItem = qobject_cast<QQuickItem*>(object); + if (quickItem) { + Q_FOREACH (QQuickItem *childItem, quickItem->childItems()) { + allSubObjects(childItem, objectList); + } + } +} + +void QQuickDesignerSupportItems::tweakObjects(QObject *object) +{ + QObjectList objectList; + allSubObjects(object, objectList); + Q_FOREACH (QObject* childObject, objectList) { + stopAnimation(childObject); + if (fixResourcePathsForObjectCallBack) + fixResourcePathsForObjectCallBack(childObject); + } +} + +static QObject *createDummyWindow(QQmlEngine *engine) +{ + QQmlComponent component(engine, QUrl(QStringLiteral("qrc:/qtquickplugin/mockfiles/Window.qml"))); + return component.create(); +} + +static bool isWindowMetaObject(const QMetaObject *metaObject) +{ + if (metaObject) { + if (metaObject->className() == QByteArrayLiteral("QWindow")) + return true; + + return isWindowMetaObject(metaObject->superClass()); + } + + return false; +} + +static bool isWindow(QObject *object) { + if (object) + return isWindowMetaObject(object->metaObject()); + + return false; +} + +static QQmlType *getQmlType(const QString &typeName, int majorNumber, int minorNumber) +{ + return QQmlMetaType::qmlType(typeName, majorNumber, minorNumber); +} + +static bool isCrashingType(QQmlType *type) +{ + if (type) { + if (type->qmlTypeName() == QStringLiteral("QtMultimedia/MediaPlayer")) + return true; + + if (type->qmlTypeName() == QStringLiteral("QtMultimedia/Audio")) + return true; + + if (type->qmlTypeName() == QStringLiteral("QtQuick.Controls/MenuItem")) + return true; + + if (type->qmlTypeName() == QStringLiteral("QtQuick.Controls/Menu")) + return true; + + if (type->qmlTypeName() == QStringLiteral("QtQuick/Timer")) + return true; + } + + return false; +} + +QObject *QQuickDesignerSupportItems::createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context) +{ + ComponentCompleteDisabler disableComponentComplete; + + Q_UNUSED(disableComponentComplete) + + QObject *object = 0; + QQmlType *type = getQmlType(typeName, majorNumber, minorNumber); + + if (isCrashingType(type)) { + object = new QObject; + } else if (type) { + if ( type->isComposite()) { + object = createComponent(type->sourceUrl(), context); + } else + { + if (type->typeName() == "QQmlComponent") { + object = new QQmlComponent(context->engine(), 0); + } else { + object = type->create(); + } + } + + if (isWindow(object)) { + delete object; + object = createDummyWindow(context->engine()); + } + + } + + if (!object) { + qWarning() << "QuickDesigner: Cannot create an object of type" + << QString::fromLatin1("%1 %2,%3").arg(typeName).arg(majorNumber).arg(minorNumber) + << "- type isn't known to declarative meta type system"; + } + + tweakObjects(object); + + if (object && QQmlEngine::contextForObject(object) == 0) + QQmlEngine::setContextForObject(object, context); + + QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); + + return object; +} + +QObject *QQuickDesignerSupportItems::createComponent(const QUrl &componentUrl, QQmlContext *context) +{ + ComponentCompleteDisabler disableComponentComplete; + Q_UNUSED(disableComponentComplete) + + QQmlComponent component(context->engine(), componentUrl); + + QObject *object = component.beginCreate(context); + tweakObjects(object); + component.completeCreate(); + QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); + + if (component.isError()) { + qWarning() << "Error in:" << Q_FUNC_INFO << componentUrl; + Q_FOREACH (const QQmlError &error, component.errors()) + qWarning() << error; + } + return object; +} + +bool QQuickDesignerSupportItems::objectWasDeleted(QObject *object) +{ + return QObjectPrivate::get(object)->wasDeleted; +} + +void QQuickDesignerSupportItems::disableNativeTextRendering(QQuickItem *item) +{ + QQuickText *text = qobject_cast<QQuickText*>(item); + if (text) + text->setRenderType(QQuickText::QtRendering); + + QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(item); + if (textInput) + textInput->setRenderType(QQuickTextInput::QtRendering); + + QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(item); + if (textEdit) + textEdit->setRenderType(QQuickTextEdit::QtRendering); +} + +void QQuickDesignerSupportItems::disableTextCursor(QQuickItem *item) +{ + Q_FOREACH (QQuickItem *childItem, item->childItems()) + disableTextCursor(childItem); + + QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(item); + if (textInput) + textInput->setCursorVisible(false); + + QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(item); + if (textEdit) + textEdit->setCursorVisible(false); +} + +void QQuickDesignerSupportItems::disableTransition(QObject *object) +{ + QQuickTransition *transition = qobject_cast<QQuickTransition*>(object); + Q_ASSERT(transition); + const QString invalidState = QLatin1String("invalidState"); + transition->setToState(invalidState); + transition->setFromState(invalidState); +} + +void QQuickDesignerSupportItems::disableBehaivour(QObject *object) +{ + QQuickBehavior* behavior = qobject_cast<QQuickBehavior*>(object); + Q_ASSERT(behavior); + behavior->setEnabled(false); +} + +void QQuickDesignerSupportItems::stopUnifiedTimer() +{ + QUnifiedTimer::instance()->setSlowdownFactor(0.00001); + QUnifiedTimer::instance()->setSlowModeEnabled(true); +} + +void QQuickDesignerSupportItems::registerFixResourcePathsForObjectCallBack(void (*callback)(QObject *)) +{ + fixResourcePathsForObjectCallBack = callback; +} + +QT_END_NAMESPACE + + diff --git a/src/quick/designer/qquickdesignersupportitems_p.h b/src/quick/designer/qquickdesignersupportitems_p.h new file mode 100644 index 0000000000..c15d651b33 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportitems_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERSUPPORTITEM_H +#define DESIGNERSUPPORTITEM_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdesignersupport_p.h" + +#include <QObject> +#include <QString> +#include <QVariant> +#include <QList> +#include <QByteArray> +#include <QQmlContext> +#include <QQmlListReference> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QQuickDesignerSupportItems +{ +public: + static QObject *createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context); + static QObject *createComponent(const QUrl &componentUrl, QQmlContext *context); + static void tweakObjects(QObject *object); + static bool objectWasDeleted(QObject *object); + static void disableNativeTextRendering(QQuickItem *item); + static void disableTextCursor(QQuickItem *item); + static void disableTransition(QObject *object); + static void disableBehaivour(QObject *object); + static void stopUnifiedTimer(); + static void registerFixResourcePathsForObjectCallBack(void (*callback)(QObject *)); +}; + +QT_END_NAMESPACE + +#endif // DESIGNERSUPPORTITEM_H diff --git a/src/quick/designer/qquickdesignersupportmetainfo.cpp b/src/quick/designer/qquickdesignersupportmetainfo.cpp new file mode 100644 index 0000000000..c6c7ed38b9 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportmetainfo.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdesignersupportmetainfo_p.h" +#include "qqmldesignermetaobject_p.h" + +#include <private/qqmlmetatype_p.h> + +QT_BEGIN_NAMESPACE + +bool QQuickDesignerSupportMetaInfo::isSubclassOf(QObject *object, const QByteArray &superTypeName) +{ + if (object == 0) + return false; + + const QMetaObject *metaObject = object->metaObject(); + + while (metaObject) { + QQmlType *qmlType = QQmlMetaType::qmlType(metaObject); + if (qmlType && qmlType->qmlTypeName() == QLatin1String(superTypeName)) // ignore version numbers + return true; + + if (metaObject->className() == superTypeName) + return true; + + metaObject = metaObject->superClass(); + } + + return false; +} + +void QQuickDesignerSupportMetaInfo::registerNotifyPropertyChangeCallBack(void (*callback)(QObject *, const QQuickDesignerSupport::PropertyName &)) +{ + QQmlDesignerMetaObject::registerNotifyPropertyChangeCallBack(callback); +} + +QT_END_NAMESPACE + diff --git a/src/quick/designer/qquickdesignersupportmetainfo_p.h b/src/quick/designer/qquickdesignersupportmetainfo_p.h new file mode 100644 index 0000000000..52bf8e3ac0 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportmetainfo_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERSUPPORTMETAINFO_H +#define DESIGNERSUPPORTMETAINFO_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdesignersupport_p.h" + +#include <QObject> +#include <QByteArray> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QQuickDesignerSupportMetaInfo +{ +public: + static bool isSubclassOf(QObject *object, const QByteArray &superTypeName); + static void registerNotifyPropertyChangeCallBack(void (*callback)(QObject *, const QQuickDesignerSupport::PropertyName &)); +}; + +QT_END_NAMESPACE + +#endif // DESIGNERSUPPORTMETAINFO_H diff --git a/src/quick/designer/qquickdesignersupportproperties.cpp b/src/quick/designer/qquickdesignersupportproperties.cpp new file mode 100644 index 0000000000..96f09ada48 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportproperties.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdesignersupportproperties_p.h" + +#include "qqmldesignermetaobject_p.h" +#include "qquickdesignercustomobjectdata_p.h" + +QT_BEGIN_NAMESPACE + +static void addToPropertyNameListIfNotBlackListed(QQuickDesignerSupport::PropertyNameList *propertyNameList, + const QQuickDesignerSupport::PropertyName &propertyName) +{ + if (!QQuickDesignerSupportProperties::isPropertyBlackListed(propertyName)) + propertyNameList->append(propertyName); +} + +void QQuickDesignerSupportProperties::createNewDynamicProperty(QObject *object, QQmlEngine *engine, const QString &name) +{ + QQmlDesignerMetaObject::getNodeInstanceMetaObject(object, engine)->createNewDynamicProperty(name); +} + +void QQuickDesignerSupportProperties::registerNodeInstanceMetaObject(QObject *object, QQmlEngine *engine) +{ + // we just create one and the ownership goes automatically to the object in nodeinstance see init method + QQmlDesignerMetaObject::getNodeInstanceMetaObject(object, engine); +} + +bool QQuickDesignerSupportProperties::hasFullImplementedListInterface(const QQmlListReference &list) +{ + return list.isValid() && list.canCount() && list.canAt() && list.canAppend() && list.canClear(); +} + +void QQuickDesignerSupportProperties::registerCustomData(QObject *object) +{ + QQuickDesignerCustomObjectData::registerData(object); +} + +QVariant QQuickDesignerSupportProperties::getResetValue(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName) +{ + return QQuickDesignerCustomObjectData::getResetValue(object, propertyName); +} + +void QQuickDesignerSupportProperties::doResetProperty(QObject *object, QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQuickDesignerCustomObjectData::doResetProperty(object, context, propertyName); +} + +bool QQuickDesignerSupportProperties::hasValidResetBinding(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName) +{ + return QQuickDesignerCustomObjectData::hasValidResetBinding(object, propertyName); +} + +bool QQuickDesignerSupportProperties::hasBindingForProperty(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + bool *hasChanged) +{ + return QQuickDesignerCustomObjectData::hasBindingForProperty(object, context, propertyName, hasChanged); +} + +void QQuickDesignerSupportProperties::setPropertyBinding(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + const QString &expression) +{ + QQuickDesignerCustomObjectData::setPropertyBinding(object, context, propertyName, expression); +} + +void QQuickDesignerSupportProperties::keepBindingFromGettingDeleted(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQuickDesignerCustomObjectData::keepBindingFromGettingDeleted(object, context, propertyName); +} + +bool QQuickDesignerSupportProperties::isPropertyQObject(const QMetaProperty &metaProperty) +{ + return QQmlMetaType::isQObject(metaProperty.userType()); +} + + +QObject *QQuickDesignerSupportProperties::readQObjectProperty(const QMetaProperty &metaProperty, QObject *object) +{ + return QQmlMetaType::toQObject(metaProperty.read(object)); +} + +void QQuickDesignerSupportProperties::getPropertyCache(QObject *object, QQmlEngine *engine) +{ + QQmlEnginePrivate::get(engine)->cache(object->metaObject()); +} + +QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propertyNameListForWritableProperties(QObject *object, + const QQuickDesignerSupport::PropertyName &baseName, + QObjectList *inspectedObjects) +{ + QQuickDesignerSupport::PropertyNameList propertyNameList; + + QObjectList localObjectList; + + if (inspectedObjects == 0) + inspectedObjects = &localObjectList; + + + if (inspectedObjects->contains(object)) + return propertyNameList; + + inspectedObjects->append(object); + + const QMetaObject *metaObject = object->metaObject(); + for (int index = 0; index < metaObject->propertyCount(); ++index) { + QMetaProperty metaProperty = metaObject->property(index); + QQmlProperty declarativeProperty(object, QString::fromUtf8(metaProperty.name())); + if (declarativeProperty.isValid() && !declarativeProperty.isWritable() && declarativeProperty.propertyTypeCategory() == QQmlProperty::Object) { + if (declarativeProperty.name() != QLatin1String("parent")) { + QObject *childObject = QQmlMetaType::toQObject(declarativeProperty.read()); + if (childObject) + propertyNameList.append(propertyNameListForWritableProperties(childObject, + baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()) + + '.', inspectedObjects)); + } + } else if (QQmlValueTypeFactory::valueType(metaProperty.userType())) { + QQmlValueType *valueType = QQmlValueTypeFactory::valueType(metaProperty.userType()); + valueType->setValue(metaProperty.read(object)); + propertyNameList.append(propertyNameListForWritableProperties(valueType, + baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()) + + '.', inspectedObjects)); + } + + if (metaProperty.isReadable() && metaProperty.isWritable()) { + addToPropertyNameListIfNotBlackListed(&propertyNameList, + baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())); + } + } + + return propertyNameList; +} + +bool QQuickDesignerSupportProperties::isPropertyBlackListed(const QQuickDesignerSupport::PropertyName &propertyName) +{ + if (propertyName.contains(".") && propertyName.contains("__")) + return true; + + if (propertyName.count(".") > 1) + return true; + + return false; +} + +QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allPropertyNames(QObject *object, + const QQuickDesignerSupport::PropertyName &baseName, + QObjectList *inspectedObjects) +{ + QQuickDesignerSupport::PropertyNameList propertyNameList; + + QObjectList localObjectList; + + if (inspectedObjects == 0) + inspectedObjects = &localObjectList; + + + if (inspectedObjects->contains(object)) + return propertyNameList; + + inspectedObjects->append(object); + + + const QMetaObject *metaObject = object->metaObject(); + for (int index = 0; index < metaObject->propertyCount(); ++index) { + QMetaProperty metaProperty = metaObject->property(index); + QQmlProperty declarativeProperty(object, QString::fromUtf8(metaProperty.name())); + if (declarativeProperty.isValid() && declarativeProperty.propertyTypeCategory() == QQmlProperty::Object) { + if (declarativeProperty.name() != QLatin1String("parent")) { + QObject *childObject = QQmlMetaType::toQObject(declarativeProperty.read()); + if (childObject) + propertyNameList.append(allPropertyNames(childObject, + baseName + + QQuickDesignerSupport::PropertyName(metaProperty.name()) + + '.', inspectedObjects)); + } + } else if (QQmlValueTypeFactory::valueType(metaProperty.userType())) { + QQmlValueType *valueType = QQmlValueTypeFactory::valueType(metaProperty.userType()); + valueType->setValue(metaProperty.read(object)); + propertyNameList.append(baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())); + propertyNameList.append(allPropertyNames(valueType, + baseName + + QQuickDesignerSupport::PropertyName(metaProperty.name()) + + '.', inspectedObjects)); + } else { + addToPropertyNameListIfNotBlackListed(&propertyNameList, + baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())); + } + } + + return propertyNameList; +} + + +QT_END_NAMESPACE + + + + diff --git a/src/quick/designer/qquickdesignersupportproperties_p.h b/src/quick/designer/qquickdesignersupportproperties_p.h new file mode 100644 index 0000000000..187bc6e2a6 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportproperties_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERSUPPORTPROPERTIES_H +#define DESIGNERSUPPORTPROPERTIES_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdesignersupport_p.h" + +#include <QObject> +#include <QString> +#include <QVariant> +#include <QList> +#include <QByteArray> +#include <QQmlContext> +#include <QQmlListReference> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QQuickDesignerSupportProperties +{ +public: + static void createNewDynamicProperty(QObject *object, QQmlEngine *engine, const QString &name); + static void registerNodeInstanceMetaObject(QObject *object, QQmlEngine *engine); + static void registerCustomData(QObject *object); + static QVariant getResetValue(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName); + static void doResetProperty(QObject *object, QQmlContext *context, const QQuickDesignerSupport::PropertyName &propertyName); + static bool hasValidResetBinding(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName); + + static bool hasBindingForProperty(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + bool *hasChanged); + static void setPropertyBinding(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName, + const QString &expression); + static void keepBindingFromGettingDeleted(QObject *object, + QQmlContext *context, + const QQuickDesignerSupport::PropertyName &propertyName); + + static bool isPropertyQObject(const QMetaProperty &metaProperty); + static QObject *readQObjectProperty(const QMetaProperty &metaProperty, QObject *object); + + static void getPropertyCache(QObject *object, QQmlEngine *engine); + static bool isPropertyBlackListed(const QQuickDesignerSupport::PropertyName &propertyName); + static QQuickDesignerSupport::PropertyNameList propertyNameListForWritableProperties(QObject *object, + const QQuickDesignerSupport::PropertyName &baseName = QQuickDesignerSupport::PropertyName(), + QObjectList *inspectedObjects = 0); + static QQuickDesignerSupport::PropertyNameList allPropertyNames(QObject *object, + const QQuickDesignerSupport::PropertyName &baseName = QQuickDesignerSupport::PropertyName(), + QObjectList *inspectedObjects = 0); + static bool hasFullImplementedListInterface(const QQmlListReference &list); +}; + +QT_END_NAMESPACE + +#endif // DESIGNERSUPPORTPROPERTIES_H diff --git a/src/quick/designer/qquickdesignersupportpropertychanges.cpp b/src/quick/designer/qquickdesignersupportpropertychanges.cpp new file mode 100644 index 0000000000..92fa637b54 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportpropertychanges.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdesignersupportpropertychanges_p.h" + +#include <private/qquickpropertychanges_p.h> +#include <private/qquickstateoperations_p.h> + +QT_BEGIN_NAMESPACE + +void QQuickDesignerSupportPropertyChanges::attachToState(QObject *propertyChanges) +{ + QQuickPropertyChanges *propertyChange = qobject_cast<QQuickPropertyChanges*>(propertyChanges); + + if (!propertyChange) + return; + + propertyChange->attachToState(); +} + +QObject *QQuickDesignerSupportPropertyChanges::targetObject(QObject *propertyChanges) +{ + QQuickPropertyChanges *propertyChange = qobject_cast<QQuickPropertyChanges*>(propertyChanges); + + if (!propertyChange) + return 0; + + return propertyChange->object(); +} + +void QQuickDesignerSupportPropertyChanges::removeProperty(QObject *propertyChanges, const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQuickPropertyChanges *propertyChange = qobject_cast<QQuickPropertyChanges*>(propertyChanges); + + if (!propertyChange) + return; + + propertyChange->removeProperty(QString::fromUtf8(propertyName)); +} + +QVariant QQuickDesignerSupportPropertyChanges::getProperty(QObject *propertyChanges, + const QQuickDesignerSupport::PropertyName &propertyName) +{ + QQuickPropertyChanges *propertyChange = qobject_cast<QQuickPropertyChanges*>(propertyChanges); + + if (!propertyChange) + return QVariant(); + + return propertyChange->property(QString::fromUtf8(propertyName)); +} + +void QQuickDesignerSupportPropertyChanges::changeValue(QObject *propertyChanges, + const QQuickDesignerSupport::PropertyName &propertyName, + const QVariant &value) +{ + QQuickPropertyChanges *propertyChange = qobject_cast<QQuickPropertyChanges*>(propertyChanges); + + if (!propertyChange) + return; + + propertyChange->changeValue(QString::fromUtf8(propertyName), value); +} + +void QQuickDesignerSupportPropertyChanges::changeExpression(QObject *propertyChanges, + const QQuickDesignerSupport::PropertyName &propertyName, + const QString &expression) +{ + QQuickPropertyChanges *propertyChange = qobject_cast<QQuickPropertyChanges*>(propertyChanges); + + if (!propertyChange) + return; + + propertyChange->changeExpression(QString::fromUtf8(propertyName), expression); +} + +QObject *QQuickDesignerSupportPropertyChanges::stateObject(QObject *propertyChanges) +{ + QQuickPropertyChanges *propertyChange = qobject_cast<QQuickPropertyChanges*>(propertyChanges); + + if (!propertyChange) + return 0; + + return propertyChange->state(); +} + +bool QQuickDesignerSupportPropertyChanges::isNormalProperty(const QQuickDesignerSupport::PropertyName &propertyName) +{ + QMetaObject metaObject = QQuickPropertyChanges::staticMetaObject; + + return (metaObject.indexOfProperty(propertyName) > 0); // 'restoreEntryValues', 'explicit' +} + +void QQuickDesignerSupportPropertyChanges::detachFromState(QObject *propertyChanges) +{ + QQuickPropertyChanges *propertyChange = qobject_cast<QQuickPropertyChanges*>(propertyChanges); + + if (!propertyChange) + return; + + propertyChange->detachFromState(); +} + +QT_END_NAMESPACE + + diff --git a/src/quick/designer/qquickdesignersupportpropertychanges_p.h b/src/quick/designer/qquickdesignersupportpropertychanges_p.h new file mode 100644 index 0000000000..432383d5b4 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportpropertychanges_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERSUPPORTPROPERTYCHANGES_H +#define DESIGNERSUPPORTPROPERTYCHANGES_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdesignersupport_p.h" + +#include <QVariant> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QQuickDesignerSupportPropertyChanges +{ +public: + static void detachFromState(QObject *propertyChanges); + static void attachToState(QObject *propertyChanges); + static QObject *targetObject(QObject *propertyChanges); + static void removeProperty(QObject *propertyChanges, const QQuickDesignerSupport::PropertyName &propertyName); + static QVariant getProperty(QObject *propertyChanges, const QQuickDesignerSupport::PropertyName &propertyName); + static void changeValue(QObject *propertyChanges, const QQuickDesignerSupport::PropertyName &propertyName, const QVariant &value); + static void changeExpression(QObject *propertyChanges, const QQuickDesignerSupport::PropertyName &propertyName, const QString &expression); + static QObject *stateObject(QObject *propertyChanges); + static bool isNormalProperty(const QQuickDesignerSupport::PropertyName &propertyName); +}; + +QT_END_NAMESPACE + +#endif // DESIGNERSUPPORTPROPERTYCHANGES_H diff --git a/src/quick/designer/qquickdesignersupportstates.cpp b/src/quick/designer/qquickdesignersupportstates.cpp new file mode 100644 index 0000000000..b75ec7115a --- /dev/null +++ b/src/quick/designer/qquickdesignersupportstates.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdesignersupportstates_p.h" + +#include <private/qquickstategroup_p.h> +#include <private/qquickpropertychanges_p.h> + +QT_BEGIN_NAMESPACE + +bool QQuickDesignerSupportStates::isStateActive(QObject *object, QQmlContext *context) +{ + QQuickState *stateObject = qobject_cast<QQuickState*>(object); + + if (!stateObject) + return false; + + QQuickStateGroup *stateGroup = stateObject->stateGroup(); + + QQmlProperty property(object, QLatin1String("name"), context); + + return stateObject && stateGroup && stateGroup->state() == property.read(); +} + +void QQuickDesignerSupportStates::activateState(QObject *object, QQmlContext *context) +{ + QQuickState *stateObject = qobject_cast<QQuickState*>(object); + + if (!stateObject) + return; + + QQuickStateGroup *stateGroup = stateObject->stateGroup(); + + QQmlProperty property(object, QLatin1String("name"), context); + + stateGroup->setState(property.read().toString()); +} + +void QQuickDesignerSupportStates::deactivateState(QObject *object) +{ + QQuickState *stateObject = qobject_cast<QQuickState*>(object); + + if (!stateObject) + return; + + QQuickStateGroup *stateGroup = stateObject->stateGroup(); + + if (stateGroup) + stateGroup->setState(QString()); +} + +bool QQuickDesignerSupportStates::changeValueInRevertList(QObject *state, QObject *target, + const QQuickDesignerSupport::PropertyName &propertyName, + const QVariant &value) +{ + QQuickState *stateObject = qobject_cast<QQuickState*>(state); + + if (!stateObject) + return false; + + return stateObject->changeValueInRevertList(target, QString::fromUtf8(propertyName), value); +} + +bool QQuickDesignerSupportStates::updateStateBinding(QObject *state, QObject *target, + const QQuickDesignerSupport::PropertyName &propertyName, + const QString &expression) +{ + QQuickState *stateObject = qobject_cast<QQuickState*>(state); + + if (!stateObject) + return false; + + return stateObject->changeValueInRevertList(target, QString::fromUtf8(propertyName), expression); +} + +bool QQuickDesignerSupportStates::resetStateProperty(QObject *state, QObject *target, + const QQuickDesignerSupport::PropertyName &propertyName, + const QVariant & /* resetValue */) +{ + QQuickState *stateObject = qobject_cast<QQuickState*>(state); + + if (!stateObject) + return false; + + return stateObject->removeEntryFromRevertList(target, QString::fromUtf8(propertyName)); +} + +QT_END_NAMESPACE + diff --git a/src/quick/designer/qquickdesignersupportstates_p.h b/src/quick/designer/qquickdesignersupportstates_p.h new file mode 100644 index 0000000000..daa5a2ff01 --- /dev/null +++ b/src/quick/designer/qquickdesignersupportstates_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERSUPPORTSTATES_H +#define DESIGNERSUPPORTSTATES_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdesignersupport_p.h" + +#include <QVariant> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QQuickDesignerSupportStates +{ +public: + static bool isStateActive(QObject *object, QQmlContext *context); + static void activateState(QObject *object, QQmlContext *context); + static void deactivateState(QObject *object); + static bool changeValueInRevertList(QObject *state, + QObject *target, + const QQuickDesignerSupport::PropertyName &propertyName, + const QVariant &value); + + static bool updateStateBinding(QObject *state, QObject *target, + const QQuickDesignerSupport::PropertyName &propertyName, + const QString &expression); + + static bool resetStateProperty(QObject *state, QObject *target, + const QQuickDesignerSupport::PropertyName &propertyName, + const QVariant &); +}; + +QT_END_NAMESPACE + +#endif // DESIGNERSUPPORTSTATES_H diff --git a/src/quick/designer/designerwindowmanager.cpp b/src/quick/designer/qquickdesignerwindowmanager.cpp index f37d6a2180..b1ad42ddb4 100644 --- a/src/quick/designer/designerwindowmanager.cpp +++ b/src/quick/designer/qquickdesignerwindowmanager.cpp @@ -31,35 +31,34 @@ ** ****************************************************************************/ -#include "designerwindowmanager_p.h" +#include "qquickdesignerwindowmanager_p.h" #include "private/qquickwindow_p.h" #include <QtGui/QOpenGLContext> #include <QtQuick/QQuickWindow> - QT_BEGIN_NAMESPACE -DesignerWindowManager::DesignerWindowManager() +QQuickDesignerWindowManager::QQuickDesignerWindowManager() : m_sgContext(QSGContext::createDefaultContext()) { m_renderContext.reset(new QSGRenderContext(m_sgContext.data())); } -void DesignerWindowManager::show(QQuickWindow *window) +void QQuickDesignerWindowManager::show(QQuickWindow *window) { makeOpenGLContext(window); } -void DesignerWindowManager::hide(QQuickWindow *) +void QQuickDesignerWindowManager::hide(QQuickWindow *) { } -void DesignerWindowManager::windowDestroyed(QQuickWindow *) +void QQuickDesignerWindowManager::windowDestroyed(QQuickWindow *) { } -void DesignerWindowManager::makeOpenGLContext(QQuickWindow *window) +void QQuickDesignerWindowManager::makeOpenGLContext(QQuickWindow *window) { if (!m_openGlContext) { m_openGlContext.reset(new QOpenGLContext()); @@ -73,31 +72,31 @@ void DesignerWindowManager::makeOpenGLContext(QQuickWindow *window) } } -void DesignerWindowManager::exposureChanged(QQuickWindow *) +void QQuickDesignerWindowManager::exposureChanged(QQuickWindow *) { } -QImage DesignerWindowManager::grab(QQuickWindow *) +QImage QQuickDesignerWindowManager::grab(QQuickWindow *) { return QImage(); } -void DesignerWindowManager::maybeUpdate(QQuickWindow *) +void QQuickDesignerWindowManager::maybeUpdate(QQuickWindow *) { } -QSGContext *DesignerWindowManager::sceneGraphContext() const +QSGContext *QQuickDesignerWindowManager::sceneGraphContext() const { return m_sgContext.data(); } -void DesignerWindowManager::createOpenGLContext(QQuickWindow *window) +void QQuickDesignerWindowManager::createOpenGLContext(QQuickWindow *window) { window->create(); window->update(); } -void DesignerWindowManager::update(QQuickWindow *window) +void QQuickDesignerWindowManager::update(QQuickWindow *window) { makeOpenGLContext(window); } diff --git a/src/quick/designer/designerwindowmanager_p.h b/src/quick/designer/qquickdesignerwindowmanager_p.h index e7a7314c20..6d98e25347 100644 --- a/src/quick/designer/designerwindowmanager_p.h +++ b/src/quick/designer/qquickdesignerwindowmanager_p.h @@ -60,11 +60,11 @@ class QSGRenderContext; class QAnimationDriver; class QOpenGLContext; -class DesignerWindowManager : public QSGRenderLoop +class QQuickDesignerWindowManager : public QSGRenderLoop { Q_OBJECT public: - DesignerWindowManager(); + QQuickDesignerWindowManager(); void show(QQuickWindow *window); void hide(QQuickWindow *window); diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index 75507c68d2..9932747dd3 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -46,7 +46,7 @@ #include <QtCore/QBuffer> #include <QtCore/qdatetime.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4scopedvalue_p.h> @@ -994,7 +994,7 @@ void QQuickCanvasItem::loadImage(const QUrl& url) if (!d->pixmaps.contains(fullPathUrl)) { QQuickPixmap* pix = new QQuickPixmap(); QQmlRefPointer<QQuickCanvasPixmap> canvasPix; - canvasPix.take(new QQuickCanvasPixmap(pix)); + canvasPix.adopt(new QQuickCanvasPixmap(pix)); d->pixmaps.insert(fullPathUrl, canvasPix); pix->load(qmlEngine(this) diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h index bcd7072903..4a1a59d61e 100644 --- a/src/quick/items/context2d/qquickcanvasitem_p.h +++ b/src/quick/items/context2d/qquickcanvasitem_p.h @@ -68,8 +68,6 @@ private: class QQuickCanvasItem : public QQuickItem { Q_OBJECT - Q_ENUMS(RenderTarget) - Q_ENUMS(RenderStrategy) Q_PROPERTY(bool available READ isAvailable NOTIFY availableChanged) Q_PROPERTY(QString contextType READ contextType WRITE setContextType NOTIFY contextTypeChanged) @@ -85,12 +83,14 @@ public: Image, FramebufferObject }; + Q_ENUM(RenderTarget) enum RenderStrategy { Immediate, Threaded, Cooperative }; + Q_ENUM(RenderStrategy) QQuickCanvasItem(QQuickItem *parent = 0); ~QQuickCanvasItem(); diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 4aa3b1c8d0..0a09ee42de 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -53,7 +53,7 @@ #include <private/qv4object_p.h> #include <private/qquickwindow_p.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4objectproto_p.h> #include <private/qv4scopedvalue_p.h> @@ -300,7 +300,7 @@ static QStringList qExtractFontFamiliesFromString(const QString &fontFamiliesStr */ static bool qSetFontFamilyFromTokens(QFont &font, const QStringList &fontFamilyTokens) { - foreach (QString fontFamilyToken, fontFamilyTokens) { + foreach (const QString &fontFamilyToken, fontFamilyTokens) { QFontDatabase fontDatabase; if (fontDatabase.hasFamily(fontFamilyToken)) { font.setFamily(fontFamilyToken); @@ -411,7 +411,7 @@ static QFont qt_font_from_string(const QString& fontString, const QFont ¤t int usedTokens = NoTokens; // Optional properties can be in any order, but font-size and font-family must be last. - foreach (const QString token, tokens) { + foreach (const QString &token, tokens) { if (token.compare(QLatin1String("normal")) == 0) { if (!(usedTokens & FontStyle) || !(usedTokens & FontVariant) || !(usedTokens & FontWeight)) { // Could be font-style, font-variant or font-weight. @@ -884,7 +884,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object V4_OBJECT2(QQuickJSContext2DPixelData, QV4::Object) V4_NEEDS_DESTROY - static QV4::ReturnedValue getIndexed(QV4::Managed *m, uint index, bool *hasProperty); + static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty); static void putIndexed(QV4::Managed *m, uint index, const QV4::Value &value); static QV4::ReturnedValue proto_get_length(QV4::CallContext *ctx); @@ -1379,7 +1379,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx QV4::ScopedValue value(scope, ctx->argument(0)); - if (value->asObject()) { + if (value->as<Object>()) { QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>(); if (color.isValid()) { r->d()->context->state.fillStyle = color; @@ -1488,7 +1488,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *c QV4::ScopedValue value(scope, ctx->argument(0)); - if (value->asObject()) { + if (value->as<Object>()) { QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>(); if (color.isValid()) { r->d()->context->state.fillStyle = color; @@ -1719,7 +1719,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon } else { QImage patternTexture; - if (QV4::Object *o = ctx->args()[0].asObject()) { + if (const QV4::Object *o = ctx->args()[0].as<Object>()) { QV4::ScopedString s(scope, scope.engine->newString(QStringLiteral("data"))); QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, o->get(s)); if (!!pixelData) { @@ -2912,7 +2912,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext } else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) { QImage img = canvas->toImage(); if (!img.isNull()) - pixmap.take(new QQuickCanvasPixmap(img)); + pixmap.adopt(new QQuickCanvasPixmap(img)); } else { V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch"); } @@ -2921,7 +2921,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext if (!!imageData) { QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>()); if (pix && !pix->d()->image.isNull()) { - pixmap.take(new QQuickCanvasPixmap(pix->d()->image)); + pixmap.adopt(new QQuickCanvasPixmap(pix->d()->image)); } else { V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch"); } @@ -3089,12 +3089,12 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(QV4::CallContext return QV4::Encode(r->d()->image.width() * r->d()->image.height() * 4); } -QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint index, bool *hasProperty) +QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty) { Q_ASSERT(m->as<QQuickJSContext2DPixelData>()); - QV4::ExecutionEngine *v4 = static_cast<QQuickJSContext2DPixelData *>(m)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const QQuickJSContext2DPixelData *>(m)->engine(); QV4::Scope scope(v4); - QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<QQuickJSContext2DPixelData *>(m)); + QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<const QQuickJSContext2DPixelData *>(m)); if (index < static_cast<quint32>(r->d()->image.width() * r->d()->image.height() * 4)) { if (hasProperty) @@ -3357,7 +3357,7 @@ QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallCo qreal pos = ctx->args()[0].toNumber(); QColor color; - if (ctx->args()[1].asObject()) { + if (ctx->args()[1].as<Object>()) { color = scope.engine->toVariant(ctx->args()[1], qMetaTypeId<QColor>()).value<QColor>(); } else { color = qt_color_from_string(ctx->args()[1]); @@ -4235,7 +4235,7 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV4::ExecutionEngine *v4) gradientProto = proto; proto = scope.engine->newObject(); - proto->defineAccessorProperty(scope.engine->id_length, QQuickJSContext2DPixelData::proto_get_length, 0); + proto->defineAccessorProperty(scope.engine->id_length(), QQuickJSContext2DPixelData::proto_get_length, 0); pixelArrayProto = proto; } diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h index 67d3a2e4fb..78fa26d791 100644 --- a/src/quick/items/context2d/qquickcontext2d_p.h +++ b/src/quick/items/context2d/qquickcontext2d_p.h @@ -48,7 +48,7 @@ #include <private/qv8engine_p.h> #include <QtCore/QWaitCondition> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> //#define QQUICKCONTEXT2D_DEBUG //enable this for just DEBUG purpose! diff --git a/src/quick/items/qquickanchors.cpp b/src/quick/items/qquickanchors.cpp index f559f166bf..606d4c45da 100644 --- a/src/quick/items/qquickanchors.cpp +++ b/src/quick/items/qquickanchors.cpp @@ -414,13 +414,27 @@ void QQuickAnchorsPrivate::updateMe() void QQuickAnchorsPrivate::updateOnComplete() { //optimization to only set initial dependencies once, at completion time - QSet<QQuickItem *> dependencies; - dependencies << fill << centerIn - << left.item << right.item << hCenter.item - << top.item << bottom.item << vCenter.item << baseline.item; - - foreach (QQuickItem *dependency, dependencies) - addDepend(dependency); + QQuickItem *dependencies[9]; + dependencies[0] = fill; + dependencies[1] = centerIn; + dependencies[2] = left.item; + dependencies[3] = right.item; + dependencies[4] = hCenter.item; + dependencies[5] = top.item; + dependencies[6] = bottom.item; + dependencies[7] = vCenter.item; + dependencies[8] = baseline.item; + + std::sort(dependencies, dependencies + 9); + + QQuickItem *lastDependency = 0; + for (int i = 0; i < 9; ++i) { + QQuickItem *dependency = dependencies[i]; + if (lastDependency != dependency) { + addDepend(dependency); + lastDependency = dependency; + } + } update(); } diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h index 4778afc88b..a10ebb4b73 100644 --- a/src/quick/items/qquickanimatedsprite_p.h +++ b/src/quick/items/qquickanimatedsprite_p.h @@ -70,12 +70,12 @@ class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem Q_PROPERTY(bool paused READ paused WRITE setPaused NOTIFY pausedChanged) Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged) - Q_ENUMS(LoopParameters) public: explicit QQuickAnimatedSprite(QQuickItem *parent = 0); enum LoopParameters { Infinite = -1 }; + Q_ENUM(LoopParameters) bool running() const { diff --git a/src/quick/items/qquickborderimage_p.h b/src/quick/items/qquickborderimage_p.h index f2a172fad3..8a88e3d0d3 100644 --- a/src/quick/items/qquickborderimage_p.h +++ b/src/quick/items/qquickborderimage_p.h @@ -44,7 +44,6 @@ class QQuickBorderImagePrivate; class Q_AUTOTEST_EXPORT QQuickBorderImage : public QQuickImageBase { Q_OBJECT - Q_ENUMS(TileMode) Q_PROPERTY(QQuickScaleGrid *border READ border CONSTANT) Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged) @@ -59,6 +58,7 @@ public: QQuickScaleGrid *border(); enum TileMode { Stretch = Qt::StretchTile, Repeat = Qt::RepeatTile, Round = Qt::RoundTile }; + Q_ENUM(TileMode) TileMode horizontalTileMode() const; void setHorizontalTileMode(TileMode); diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h index 4bd4cfc6fd..2b4b2a51d4 100644 --- a/src/quick/items/qquickdrag_p.h +++ b/src/quick/items/qquickdrag_p.h @@ -140,7 +140,6 @@ class Q_AUTOTEST_EXPORT QQuickDrag : public QObject { Q_OBJECT - Q_ENUMS(Axis DragType) Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged RESET resetTarget) Q_PROPERTY(Axis axis READ axis WRITE setAxis NOTIFY axisChanged) Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged) @@ -160,12 +159,14 @@ public: ~QQuickDrag(); enum DragType { None, Automatic, Internal }; + Q_ENUM(DragType) QQuickItem *target() const; void setTarget(QQuickItem *target); void resetTarget(); enum Axis { XAxis=0x01, YAxis=0x02, XAndYAxis=0x03, XandYAxis=XAndYAxis }; + Q_ENUM(Axis) Axis axis() const; void setAxis(Axis); diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 19fb66c19c..ea4398bc71 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -619,7 +619,7 @@ is finished. \qmlsignal QtQuick::Flickable::movementStarted() This signal is emitted when the view begins moving due to user - interaction. + interaction or a generated flick(). The corresponding handler is \c onMovementStarted. */ @@ -628,9 +628,9 @@ is finished. \qmlsignal QtQuick::Flickable::movementEnded() This signal is emitted when the view stops moving due to user - interaction. If a flick was generated, this signal will + interaction or a generated flick(). If a flick was active, this signal will be emitted once the flick stops. If a flick was not - generated, this signal will be emitted when the + active, this signal will be emitted when the user stops dragging - i.e. a mouse or touch release. The corresponding handler is \c onMovementEnded. @@ -1347,7 +1347,7 @@ void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event) if (window() && window()->mouseGrabberItem()) { QPointF localPos = window()->mouseGrabberItem()->mapFromScene(event->windowPos()); QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos)); - window()->sendEvent(window()->mouseGrabberItem(), mouseEvent.data()); + QCoreApplication::sendEvent(window(), mouseEvent.data()); } // And the event has been consumed @@ -1451,6 +1451,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) d->lastPosTime = currentTimestamp; d->accumulatedWheelPixelDelta += QVector2D(event->pixelDelta()); d->drag(currentTimestamp, event->type(), event->posF(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, true, velocity); + event->accept(); } if (!event->isAccepted()) @@ -1670,6 +1671,9 @@ void QQuickFlickable::geometryChanged(const QRectF &newGeometry, \qmlmethod QtQuick::Flickable::flick(qreal xVelocity, qreal yVelocity) Flicks the content with \a xVelocity horizontally and \a yVelocity vertically in pixels/sec. + + Calling this method will update the corresponding moving and flicking properties and signals, + just like a real flick. */ void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity) @@ -1679,8 +1683,15 @@ void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity) d->vData.reset(); d->hData.velocity = xVelocity; d->vData.velocity = yVelocity; + bool flickedX = d->flickX(xVelocity); bool flickedY = d->flickY(yVelocity); + + if (flickedX) + d->hMoved = true; + if (flickedY) + d->vMoved = true; + movementStarting(); d->flickingStarted(flickedX, flickedY); } diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index 3c3cd362dd..c974da66d6 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -93,7 +93,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem Q_PROPERTY(QQmlListProperty<QQuickItem> flickableChildren READ flickableChildren) Q_CLASSINFO("DefaultProperty", "flickableData") - Q_ENUMS(FlickableDirection) Q_FLAGS(BoundsBehavior) public: @@ -177,6 +176,7 @@ public: QQuickItem *contentItem(); enum FlickableDirection { AutoFlickDirection=0x00, HorizontalFlick=0x01, VerticalFlick=0x02, HorizontalAndVerticalFlick=0x03 }; + Q_ENUM(FlickableDirection) FlickableDirection flickableDirection() const; void setFlickableDirection(FlickableDirection); diff --git a/src/quick/items/qquickflipable_p.h b/src/quick/items/qquickflipable_p.h index bd2efe0676..31bfe97923 100644 --- a/src/quick/items/qquickflipable_p.h +++ b/src/quick/items/qquickflipable_p.h @@ -47,7 +47,6 @@ class Q_AUTOTEST_EXPORT QQuickFlipable : public QQuickItem { Q_OBJECT - Q_ENUMS(Side) Q_PROPERTY(QQuickItem *front READ front WRITE setFront NOTIFY frontChanged) Q_PROPERTY(QQuickItem *back READ back WRITE setBack NOTIFY backChanged) Q_PROPERTY(Side side READ side NOTIFY sideChanged) @@ -64,6 +63,7 @@ public: void setBack(QQuickItem *); enum Side { Front, Back }; + Q_ENUM(Side) Side side() const; Q_SIGNALS: diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp index 6031315b90..74abd8cf9f 100644 --- a/src/quick/items/qquickframebufferobject.cpp +++ b/src/quick/items/qquickframebufferobject.cpp @@ -47,11 +47,13 @@ class QQuickFramebufferObjectPrivate : public QQuickItemPrivate public: QQuickFramebufferObjectPrivate() : followsItemSize(true) + , mirrorVertically(false) , node(0) { } bool followsItemSize; + bool mirrorVertically; mutable QSGFramebufferObjectNode *node; }; @@ -138,6 +140,34 @@ bool QQuickFramebufferObject::textureFollowsItemSize() const } /*! + * \property QQuickFramebufferObject::mirrorVertically + * + * This property controls if the size of the FBO's contents should be mirrored + * vertically when drawing. This allows easy integration of third-party + * rendering code that does not follow the standard expectations. + * + * The default value is \c {false}. + * + * \since 5.6 + */ + +void QQuickFramebufferObject::setMirrorVertically(bool enable) +{ + Q_D(QQuickFramebufferObject); + if (d->mirrorVertically == enable) + return; + d->mirrorVertically = enable; + emit mirrorVerticallyChanged(d->mirrorVertically); + update(); +} + +bool QQuickFramebufferObject::mirrorVertically() const +{ + Q_D(const QQuickFramebufferObject); + return d->mirrorVertically; +} + +/*! * \internal */ void QQuickFramebufferObject::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) @@ -290,6 +320,7 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode QQuickWindow::TextureHasAlphaChannel)); } + n->setTextureCoordinatesTransform(d->mirrorVertically ? QSGSimpleTextureNode::MirrorVertically : QSGSimpleTextureNode::NoTransform); n->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest); n->setRect(0, 0, width(), height()); diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h index 4a0248c082..7fb7262222 100644 --- a/src/quick/items/qquickframebufferobject.h +++ b/src/quick/items/qquickframebufferobject.h @@ -49,6 +49,7 @@ class Q_QUICK_EXPORT QQuickFramebufferObject : public QQuickItem Q_DECLARE_PRIVATE(QQuickFramebufferObject) Q_PROPERTY(bool textureFollowsItemSize READ textureFollowsItemSize WRITE setTextureFollowsItemSize NOTIFY textureFollowsItemSizeChanged) + Q_PROPERTY(bool mirrorVertically READ mirrorVertically WRITE setMirrorVertically NOTIFY mirrorVerticallyChanged) public: @@ -73,6 +74,9 @@ public: bool textureFollowsItemSize() const; void setTextureFollowsItemSize(bool follows); + bool mirrorVertically() const; + void setMirrorVertically(bool enable); + virtual Renderer *createRenderer() const = 0; bool isTextureProvider() const Q_DECL_OVERRIDE; @@ -87,6 +91,7 @@ protected: Q_SIGNALS: void textureFollowsItemSizeChanged(bool); + void mirrorVerticallyChanged(bool); private Q_SLOTS: void invalidateSceneGraph(); diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index 99c77488f4..3ac9c6eb1c 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -267,9 +267,13 @@ qreal QQuickGridViewPrivate::originPosition() const qreal QQuickGridViewPrivate::lastPosition() const { qreal pos = 0; - if (model && model->count()) { - // get end position of last item - pos = (rowPosAt(model->count() - 1) + rowSize()); + if (model && (model->count() || !visibleItems.isEmpty())) { + qreal lastRowPos = model->count() ? rowPosAt(model->count() - 1) : 0; + if (!visibleItems.isEmpty()) { + // If there are items in delayRemove state, they may be after any items linked to the model + lastRowPos = qMax(lastRowPos, static_cast<FxGridItemSG*>(visibleItems.last())->rowPos()); + } + pos = lastRowPos + rowSize(); } return pos; } @@ -918,13 +922,13 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte tempPosition -= bias; } FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart); - if (!topItem && strictHighlightRange && currentItem) { + if (strictHighlightRange && currentItem) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); topItem = currentItem; } FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd); - if (!bottomItem && strictHighlightRange && currentItem) { + if (strictHighlightRange && currentItem) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); bottomItem = currentItem; diff --git a/src/quick/items/qquickgridview_p.h b/src/quick/items/qquickgridview_p.h index 7e1ace01dd..389ef27585 100644 --- a/src/quick/items/qquickgridview_p.h +++ b/src/quick/items/qquickgridview_p.h @@ -52,8 +52,6 @@ class Q_AUTOTEST_EXPORT QQuickGridView : public QQuickItemView Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged) - Q_ENUMS(SnapMode) - Q_ENUMS(Flow) Q_CLASSINFO("DefaultProperty", "data") public: @@ -61,6 +59,7 @@ public: FlowLeftToRight = LeftToRight, FlowTopToBottom = TopToBottom }; + Q_ENUM(Flow) QQuickGridView(QQuickItem *parent=0); ~QQuickGridView(); @@ -78,6 +77,7 @@ public: void setCellHeight(qreal); enum SnapMode { NoSnap, SnapToRow, SnapOneRow }; + Q_ENUM(SnapMode) SnapMode snapMode() const; void setSnapMode(SnapMode mode); diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h index be514ae2f5..421360bd35 100644 --- a/src/quick/items/qquickimage_p.h +++ b/src/quick/items/qquickimage_p.h @@ -40,12 +40,9 @@ QT_BEGIN_NAMESPACE class QQuickImagePrivate; -class Q_AUTOTEST_EXPORT QQuickImage : public QQuickImageBase +class Q_QUICK_PRIVATE_EXPORT QQuickImage : public QQuickImageBase { Q_OBJECT - Q_ENUMS(FillMode) - Q_ENUMS(HAlignment) - Q_ENUMS(VAlignment) Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedGeometryChanged) @@ -62,11 +59,14 @@ public: enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter }; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally, Pad }; + Q_ENUM(FillMode) FillMode fillMode() const; void setFillMode(FillMode); diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 223cb8f46f..e54f5bb9c9 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -213,15 +213,27 @@ void QQuickImageBase::load() d->devicePixelRatio = 1.0; QUrl loadUrl = d->url; - if (d->url.scheme() == QStringLiteral("image") - || d->url.toString().endsWith(QLatin1String(".svg")) - || d->url.toString().endsWith(QLatin1String(".svgz"))) { - // QQuickImageProvider and SVG can generate a high resolution image when - // sourceSize is set. If sourceSize is not set then the provider default size - // will be used, as usual. - if (!d->sourcesize.isEmpty()) + + // QQuickImageProvider and SVG can generate a high resolution image when + // sourceSize is set. If sourceSize is not set then the provider default size + // will be used, as usual. + bool setDevicePixelRatio = false; + if (!d->sourcesize.isValid()) { + if (loadUrl.scheme() == QStringLiteral("image")) { + setDevicePixelRatio = true; + } else { + QString stringUrl = loadUrl.toString(); + if (stringUrl.endsWith(QLatin1String("svg")) || + stringUrl.endsWith(QLatin1String("svgz"))) { + setDevicePixelRatio = true; + } + } + + if (setDevicePixelRatio) d->devicePixelRatio = targetDevicePixelRatio; - } else { + } + + if (!setDevicePixelRatio) { // (possible) local file: loadUrl and d->devicePixelRatio will be modified if // an "@2x" file is found. resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio); @@ -368,7 +380,7 @@ void QQuickImageBase::resolve2xLocalFile(const QUrl &url, qreal targetDevicePixe // Look for an @2x version QString localFile2x = image2xPath(localFile); - if (!QFile(localFile2x).exists()) + if (!QFile::exists(localFile2x)) return; // @2x file found found: Change url and devicePixelRatio diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h index 4fcfaecd7d..98943a235c 100644 --- a/src/quick/items/qquickimagebase_p.h +++ b/src/quick/items/qquickimagebase_p.h @@ -43,7 +43,6 @@ class QQuickImageBasePrivate; class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(Status) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -57,6 +56,7 @@ public: QQuickImageBase(QQuickItem *parent=0); ~QQuickImageBase(); enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; qreal progress() const; diff --git a/src/quick/items/qquickimplicitsizeitem_p_p.h b/src/quick/items/qquickimplicitsizeitem_p_p.h index f2e502af15..d606474e9d 100644 --- a/src/quick/items/qquickimplicitsizeitem_p_p.h +++ b/src/quick/items/qquickimplicitsizeitem_p_p.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE -class QQuickImplicitSizeItemPrivate : public QQuickItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickImplicitSizeItemPrivate : public QQuickItemPrivate { Q_DECLARE_PUBLIC(QQuickImplicitSizeItem) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 5fd1882216..32c3e651dd 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -1304,8 +1304,8 @@ void QQuickKeysAttached::setPriority(Priority order) void QQuickKeysAttached::componentComplete() { - Q_D(QQuickKeysAttached); #ifndef QT_NO_IM + Q_D(QQuickKeysAttached); if (d->item) { for (int ii = 0; ii < d->targets.count(); ++ii) { QQuickItem *targetItem = d->targets.at(ii); @@ -1608,6 +1608,85 @@ void QQuickItemPrivate::setLayoutMirror(bool mirror) } } +/*! + \qmltype EnterKey + \instantiates QQuickEnterKeyAttached + \inqmlmodule QtQuick + \ingroup qtquick-input + \since 5.6 + \brief Provides a property to manipulate the appearance of Enter key on + an on-screen keyboard. + + The EnterKey attached property is used to manipulate the appearance and + behavior of the Enter key on an on-screen keyboard. +*/ + +/*! + \qmlproperty enumeration QtQuick::EnterKey::type + + Holds the type of the Enter key. + + \note Not all of these values are supported on all platforms. For + unsupported values the default key is used instead. + + \value Qt.EnterKeyDefault The default Enter key. This can be either a + button to accept the input and close the + keyboard, or a \e Return button to enter a + newline in case of a multi-line input field. + + \value Qt.EnterKeyReturn Show a \e Return button that inserts a + newline. + + \value Qt.EnterKeyDone Show a \e {"Done"} button. Typically, the + keyboard is expected to close when the button + is pressed. + + \value Qt.EnterKeyGo Show a \e {"Go"} button. Typically used in an + address bar when entering a URL. + + \value Qt.EnterKeySend Show a \e {"Send"} button. + + \value Qt.EnterKeySearch Show a \e {"Search"} button. + + \value Qt.EnterKeyNext Show a \e {"Next"} button. Typically used in a + form to allow navigating to the next input + field without the keyboard closing. + + \value Qt.EnterKeyPrevious Show a \e {"Previous"} button. +*/ + +QQuickEnterKeyAttached::QQuickEnterKeyAttached(QObject *parent) + : QObject(parent), itemPrivate(0), keyType(Qt::EnterKeyDefault) +{ + if (QQuickItem *item = qobject_cast<QQuickItem*>(parent)) { + itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->extra.value().enterKeyAttached = this; + } else + qmlInfo(parent) << tr("EnterKey attached property only works with Items"); +} + +QQuickEnterKeyAttached *QQuickEnterKeyAttached::qmlAttachedProperties(QObject *object) +{ + return new QQuickEnterKeyAttached(object); +} + +Qt::EnterKeyType QQuickEnterKeyAttached::type() const +{ + return keyType; +} + +void QQuickEnterKeyAttached::setType(Qt::EnterKeyType type) +{ + if (keyType != type) { + keyType = type; +#ifndef QT_NO_IM + if (itemPrivate && itemPrivate->activeFocus) + QGuiApplication::inputMethod()->update(Qt::ImEnterKeyType); +#endif + typeChanged(); + } +} + void QQuickItemPrivate::setAccessible() { isAccessible = true; @@ -2776,7 +2855,7 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c) window = c; if (polishScheduled) - QQuickWindowPrivate::get(window)->itemsToPolish.insert(q); + QQuickWindowPrivate::get(window)->itemsToPolish.append(q); if (!parentItem) QQuickWindowPrivate::get(window)->parentlessItems.insert(q); @@ -2808,7 +2887,7 @@ void QQuickItemPrivate::derefWindow() removeFromDirtyList(); QQuickWindowPrivate *c = QQuickWindowPrivate::get(window); if (polishScheduled) - c->itemsToPolish.remove(q); + c->itemsToPolish.removeOne(q); QMutableHashIterator<int, QQuickItem *> itemTouchMapIt(c->itemForTouchPointId); while (itemTouchMapIt.hasNext()) { if (itemTouchMapIt.next().value() == q) @@ -3960,6 +4039,11 @@ QVariant QQuickItem::inputMethodQuery(Qt::InputMethodQuery query) const case Qt::ImPreferredLanguage: if (d->extra.isAllocated() && d->extra->keyHandler) v = d->extra->keyHandler->inputMethodQuery(query); + break; + case Qt::ImEnterKeyType: + if (d->extra.isAllocated() && d->extra->enterKeyAttached) + v = d->extra->enterKeyAttached->type(); + break; default: break; } @@ -4102,7 +4186,7 @@ void QQuickItem::polish() if (d->window) { QQuickWindowPrivate *p = QQuickWindowPrivate::get(d->window); bool maybeupdate = p->itemsToPolish.isEmpty(); - p->itemsToPolish.insert(this); + p->itemsToPolish.append(this); if (maybeupdate) d->window->maybeUpdate(); } } @@ -7839,6 +7923,7 @@ void QQuickItemLayer::updateMatrix() QQuickItemPrivate::ExtraData::ExtraData() : z(0), scale(1), rotation(0), opacity(1), contents(0), screenAttached(0), layoutDirectionAttached(0), + enterKeyAttached(0), keyHandler(0), layer(0), effectRefCount(0), hideRefCount(0), opacityNode(0), clipNode(0), rootNode(0), diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 463113386b..d92910ce9c 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -141,7 +141,6 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QQmlParserStatus Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQuickItemLayer *layer READ layer DESIGNABLE false CONSTANT FINAL) - Q_ENUMS(TransformOrigin) Q_CLASSINFO("DefaultProperty", "data") Q_CLASSINFO("qt_HasQmlAccessors", "true") @@ -187,6 +186,7 @@ public: Left, Center, Right, BottomLeft, Bottom, BottomRight }; + Q_ENUM(TransformOrigin) QQuickItem(QQuickItem *parent = 0); virtual ~QQuickItem(); diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 64d8bd0ede..5e0246c32e 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -78,6 +78,7 @@ QT_BEGIN_NAMESPACE class QNetworkReply; class QQuickItemKeyFilter; class QQuickLayoutMirroringAttached; +class QQuickEnterKeyAttached; class QQuickScreenAttached; class QQuickContents : public QQuickItemChangeListener @@ -338,6 +339,7 @@ public: QQuickContents *contents; QQuickScreenAttached *screenAttached; QQuickLayoutMirroringAttached* layoutDirectionAttached; + QQuickEnterKeyAttached *enterKeyAttached; QQuickItemKeyFilter *keyHandler; mutable QQuickItemLayer *layer; #ifndef QT_NO_CURSOR @@ -645,8 +647,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickKeyNavigationAttached : public QObject, publi Q_PROPERTY(QQuickItem *backtab READ backtab WRITE setBacktab NOTIFY backtabChanged) Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged) - Q_ENUMS(Priority) - public: QQuickKeyNavigationAttached(QObject * = 0); @@ -664,6 +664,7 @@ public: void setBacktab(QQuickItem *); enum Priority { BeforeItem, AfterItem }; + Q_ENUM(Priority) Priority priority() const; void setPriority(Priority); @@ -710,6 +711,27 @@ private: QQuickItemPrivate *itemPrivate; }; +class QQuickEnterKeyAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(Qt::EnterKeyType type READ type WRITE setType NOTIFY typeChanged) + +public: + explicit QQuickEnterKeyAttached(QObject *parent = Q_NULLPTR); + + Qt::EnterKeyType type() const; + void setType(Qt::EnterKeyType type); + + static QQuickEnterKeyAttached *qmlAttachedProperties(QObject *); +Q_SIGNALS: + void typeChanged(); +private: + friend class QQuickItemPrivate; + QQuickItemPrivate *itemPrivate; + + Qt::EnterKeyType keyType; +}; + class QQuickKeysAttachedPrivate : public QObjectPrivate { public: @@ -739,8 +761,6 @@ class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter Q_PROPERTY(QQmlListProperty<QQuickItem> forwardTo READ forwardTo) Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged) - Q_ENUMS(Priority) - public: QQuickKeysAttached(QObject *parent=0); ~QQuickKeysAttached(); @@ -755,6 +775,7 @@ public: } enum Priority { BeforeItem, AfterItem}; + Q_ENUM(Priority) Priority priority() const; void setPriority(Priority); @@ -895,5 +916,7 @@ QML_DECLARE_TYPE(QQuickKeyNavigationAttached) QML_DECLARE_TYPEINFO(QQuickKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES) QML_DECLARE_TYPE(QQuickLayoutMirroringAttached) QML_DECLARE_TYPEINFO(QQuickLayoutMirroringAttached, QML_HAS_ATTACHED_PROPERTIES) +QML_DECLARE_TYPE(QQuickEnterKeyAttached) +QML_DECLARE_TYPEINFO(QQuickEnterKeyAttached, QML_HAS_ATTACHED_PROPERTIES) #endif // QQUICKITEM_P_H diff --git a/src/quick/items/qquickitemanimation_p.h b/src/quick/items/qquickitemanimation_p.h index 907687a2bd..9f0b3dccb8 100644 --- a/src/quick/items/qquickitemanimation_p.h +++ b/src/quick/items/qquickitemanimation_p.h @@ -136,7 +136,7 @@ public: BottomFirst, TopFirst }; - Q_ENUMS(Orientation) + Q_ENUM(Orientation) int duration() const; void setDuration(int); diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 5fbae66b6c..4df1ef038c 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -158,11 +158,6 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickPathView>(uri,major,minor,"PathView"); qmlRegisterUncreatableType<QQuickBasePositioner>(uri,major,minor,"Positioner", QStringLiteral("Positioner is an abstract type that is only available as an attached property.")); -#ifndef QT_NO_VALIDATOR - qmlRegisterType<QQuickIntValidator>(uri,major,minor,"IntValidator"); - qmlRegisterType<QQuickDoubleValidator>(uri,major,minor,"DoubleValidator"); - qmlRegisterType<QRegExpValidator>(uri,major,minor,"RegExpValidator"); -#endif qmlRegisterType<QQuickRectangle>(uri,major,minor,"Rectangle"); qmlRegisterType<QQuickRepeater>(uri,major,minor,"Repeater"); qmlRegisterType<QQuickRow>(uri,major,minor,"Row"); @@ -190,9 +185,6 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickCurve>(); qmlRegisterType<QQuickScaleGrid>(); qmlRegisterType<QQuickTextLine>(); -#ifndef QT_NO_VALIDATOR - qmlRegisterType<QValidator>(); -#endif qmlRegisterType<QQuickPen>(); qmlRegisterType<QQuickFlickableVisibleArea>(); qRegisterMetaType<QQuickAnchorLine>("QQuickAnchorLine"); @@ -269,6 +261,18 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickPinchArea, 1>(uri, 2, 5,"PinchArea"); qmlRegisterType<QQuickImage, 2>(uri, 2, 5,"Image"); qmlRegisterType<QQuickMouseArea, 2>(uri, 2, 5, "MouseArea"); + + qmlRegisterType<QQuickText, 6>(uri, 2, 6, "Text"); + qmlRegisterType<QQuickTextEdit, 6>(uri, 2, 6, "TextEdit"); + qmlRegisterType<QQuickTextInput, 6>(uri, 2, 6, "TextInput"); + qmlRegisterUncreatableType<QQuickBasePositioner, 6>(uri, 2, 6, "Positioner", + QStringLiteral("Positioner is an abstract type that is only available as an attached property.")); + qmlRegisterType<QQuickColumn, 6>(uri, 2, 6, "Column"); + qmlRegisterType<QQuickRow, 6>(uri, 2, 6, "Row"); + qmlRegisterType<QQuickGrid, 6>(uri, 2, 6, "Grid"); + qmlRegisterType<QQuickFlow, 6>(uri, 2, 6, "Flow"); + qmlRegisterUncreatableType<QQuickEnterKeyAttached, 6>(uri, 2, 6, "EnterKey", + QQuickEnterKeyAttached::tr("EnterKey is only available via attached properties")); } static void initResources() diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 01ef1e65f7..d4c8c3f8ee 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -71,19 +71,19 @@ FxViewItem::~FxViewItem() qreal FxViewItem::itemX() const { - return transitionableItem ? transitionableItem->itemX() : item->x(); + return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0); } qreal FxViewItem::itemY() const { - return transitionableItem ? transitionableItem->itemY() : item->y(); + return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0); } void FxViewItem::moveTo(const QPointF &pos, bool immediate) { if (transitionableItem) transitionableItem->moveTo(pos, immediate); - else + else if (item) item->setPosition(pos); } @@ -91,21 +91,26 @@ void FxViewItem::setVisible(bool visible) { if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning()) return; - QQuickItemPrivate::get(item)->setCulled(!visible); + if (item) + QQuickItemPrivate::get(item)->setCulled(!visible); } void FxViewItem::trackGeometry(bool track) { if (track) { if (!trackGeom) { - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + if (item) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + } trackGeom = true; } } else { if (trackGeom) { - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + if (item) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + } trackGeom = false; } } @@ -905,11 +910,7 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) qreal pos = isContentFlowReversed() ? -position() - size() : position(); FxViewItem *item = visibleItem(idx); - qreal maxExtent; - if (layoutOrientation() == Qt::Vertical) - maxExtent = isContentFlowReversed() ? q->minYExtent()-size(): -q->maxYExtent(); - else - maxExtent = isContentFlowReversed() ? q->minXExtent()-size(): -q->maxXExtent(); + qreal maxExtent = calculatedMaxExtent(); if (!item) { qreal itemPos = positionAt(idx); changedVisibleIndex(idx); @@ -955,11 +956,7 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) break; } pos = qMin(pos, maxExtent); - qreal minExtent; - if (layoutOrientation() == Qt::Vertical) - minExtent = isContentFlowReversed() ? q->maxYExtent()-size(): -q->minYExtent(); - else - minExtent = isContentFlowReversed() ? q->maxXExtent()-size(): -q->minXExtent(); + qreal minExtent = calculatedMinExtent(); pos = qMax(pos, minExtent); moveReason = QQuickItemViewPrivate::Other; q->cancelFlick(); @@ -1130,6 +1127,29 @@ qreal QQuickItemViewPrivate::maxExtentForAxis(const AxisData &axisData, bool for return extent; } +qreal QQuickItemViewPrivate::calculatedMinExtent() const +{ + Q_Q(const QQuickItemView); + qreal minExtent; + if (layoutOrientation() == Qt::Vertical) + minExtent = isContentFlowReversed() ? q->maxYExtent() - size(): -q->minYExtent(); + else + minExtent = isContentFlowReversed() ? q->maxXExtent() - size(): -q->minXExtent(); + return minExtent; + +} + +qreal QQuickItemViewPrivate::calculatedMaxExtent() const +{ + Q_Q(const QQuickItemView); + qreal maxExtent; + if (layoutOrientation() == Qt::Vertical) + maxExtent = isContentFlowReversed() ? q->minYExtent() - size(): -q->maxYExtent(); + else + maxExtent = isContentFlowReversed() ? q->minXExtent() - size(): -q->maxXExtent(); + return maxExtent; +} + // for debugging only void QQuickItemViewPrivate::checkVisible() const { @@ -1199,7 +1219,7 @@ void QQuickItemView::destroyRemoved() for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end();) { FxViewItem *item = *it; - if (item->index == -1 && item->attached->delayRemove() == false) { + if (item->index == -1 && (!item->attached || item->attached->delayRemove() == false)) { if (d->transitioner && d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)) { // don't remove from visibleItems until next layout() d->runDelayedRemoveTransition = true; @@ -1277,10 +1297,12 @@ void QQuickItemView::trackedPositionChanged() if (trackedPos < pos + d->highlightRangeStart) pos = trackedPos - d->highlightRangeStart; if (d->highlightRange != StrictlyEnforceRange) { - if (pos > d->endPosition() - d->size()) - pos = d->endPosition() - d->size(); - if (pos < d->startPosition()) - pos = d->startPosition(); + qreal maxExtent = d->calculatedMaxExtent(); + if (pos > maxExtent) + pos = maxExtent; + qreal minExtent = d->calculatedMinExtent(); + if (pos < minExtent) + pos = minExtent; } } else { if (d->trackedItem != d->currentItem) { @@ -1344,7 +1366,7 @@ void QQuickItemView::geometryChanged(const QRectF &newGeometry, const QRectF &ol { Q_D(QQuickItemView); d->markExtentsDirty(); - if (isComponentComplete() && d->isValid()) + if (isComponentComplete() && (d->isValid() || !d->visibleItems.isEmpty())) d->forceLayoutPolish(); QQuickFlickable::geometryChanged(newGeometry, oldGeometry); } @@ -1641,7 +1663,8 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex) applyPendingChanges(); if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) { if (currentItem) { - currentItem->attached->setIsCurrentItem(false); + if (currentItem->attached) + currentItem->attached->setIsCurrentItem(false); releaseItem(currentItem); currentItem = 0; currentIndex = modelIndex; @@ -1664,11 +1687,12 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex) int oldCurrentIndex = currentIndex; currentIndex = modelIndex; currentItem = createItem(modelIndex, false); - if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item)) + if (oldCurrentItem && oldCurrentItem->attached && (!currentItem || oldCurrentItem->item != currentItem->item)) oldCurrentItem->attached->setIsCurrentItem(false); if (currentItem) { currentItem->item->setFocus(true); - currentItem->attached->setIsCurrentItem(true); + if (currentItem->attached) + currentItem->attached->setIsCurrentItem(true); initializeCurrentItem(); } @@ -1806,7 +1830,7 @@ void QQuickItemViewPrivate::updateViewport() { Q_Q(QQuickItemView); qreal extra = headerSize() + footerSize(); - qreal contentSize = isValid() ? (endPosition() - startPosition()) : 0.0; + qreal contentSize = isValid() || !visibleItems.isEmpty() ? (endPosition() - startPosition()) : 0.0; if (layoutOrientation() == Qt::Vertical) q->setContentHeight(contentSize + extra); else @@ -1824,6 +1848,7 @@ void QQuickItemViewPrivate::layout() if (!isValid() && !visibleItems.count()) { clear(); setPosition(contentStartOffset()); + updateViewport(); if (transitioner) transitioner->setPopulateTransitionEnabled(false); inLayout = false; @@ -1967,7 +1992,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult QQmlChangeSet::Change removal; for (QList<FxViewItem*>::Iterator it = visibleItems.begin(); it != visibleItems.end();) { FxViewItem *item = *it; - if (item->index == -1 && !item->attached->delayRemove()) { + if (item->index == -1 && (!item->attached || !item->attached->delayRemove())) { removeItem(item, removal, &removalResult); removedCount++; it = visibleItems.erase(it); @@ -2007,8 +2032,10 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult } itemCount += insertions[i].count; } - for (int i=0; i<newItems.count(); i++) - newItems.at(i)->attached->emitAdd(); + for (int i=0; i<newItems.count(); i++) { + if (newItems.at(i)->attached) + newItems.at(i)->attached->emitAdd(); + } // for each item that was moved directly into the view as a result of a move(), // find the index it was moved from in order to set its initial position, so that we @@ -2040,7 +2067,8 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult if (currentChanges.currentChanged) { if (currentChanges.currentRemoved && currentItem) { - currentItem->attached->setIsCurrentItem(false); + if (currentItem->item && currentItem->attached) + currentItem->attached->setIsCurrentItem(false); releaseItem(currentItem); currentItem = 0; } @@ -2092,10 +2120,10 @@ bool QQuickItemViewPrivate::applyRemovalChange(const QQmlChangeSet::Change &remo } else { // removed item visibleAffected = true; - if (!removal.isMove()) + if (!removal.isMove() && item->item && item->attached) item->attached->emitRemove(); - if (item->attached->delayRemove() && !removal.isMove()) { + if (item->item && item->attached && item->attached->delayRemove() && !removal.isMove()) { item->index = -1; QObject::connect(item->attached, SIGNAL(delayRemoveChanged()), q, SLOT(destroyRemoved()), Qt::QueuedConnection); ++it; @@ -2352,12 +2380,14 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item) item->trackGeometry(false); QQmlInstanceModel::ReleaseFlags flags = model->release(item->item); - if (flags == 0) { - // item was not destroyed, and we no longer reference it. - QQuickItemPrivate::get(item->item)->setCulled(true); - unrequestedItems.insert(item->item, model->indexOf(item->item, q)); - } else if (flags & QQmlInstanceModel::Destroyed) { - item->item->setParentItem(0); + if (item->item) { + if (flags == 0) { + // item was not destroyed, and we no longer reference it. + QQuickItemPrivate::get(item->item)->setCulled(true); + unrequestedItems.insert(item->item, model->indexOf(item->item, q)); + } else if (flags & QQmlInstanceModel::Destroyed) { + item->item->setParentItem(0); + } } delete item; return flags != QQmlInstanceModel::Referenced; @@ -2421,7 +2451,7 @@ void QQuickItemViewPrivate::updateUnrequestedIndexes() void QQuickItemViewPrivate::updateUnrequestedPositions() { - for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.begin(), cend = unrequestedItems.end(); it != cend; ++it) + for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.cbegin(), cend = unrequestedItems.cend(); it != cend; ++it) repositionPackageItemAt(it.key(), it.value()); } diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index 6e5ae032c2..3e28ff336d 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -88,11 +88,6 @@ class Q_AUTOTEST_EXPORT QQuickItemView : public QQuickFlickable Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd) Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged) - Q_ENUMS(HighlightRangeMode) - Q_ENUMS(PositionMode) - Q_ENUMS(VerticalLayoutDirection) - Q_ENUMS(LayoutDirection) - public: // this holds all layout enum values so they can be referred to by other enums // to ensure consistent values - e.g. QML references to GridView.TopToBottom flow @@ -103,11 +98,13 @@ public: VerticalTopToBottom, VerticalBottomToTop }; + Q_ENUM(LayoutDirection) enum VerticalLayoutDirection { TopToBottom = VerticalTopToBottom, BottomToTop = VerticalBottomToTop }; + Q_ENUM(VerticalLayoutDirection) QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent = 0); ~QQuickItemView(); @@ -185,6 +182,7 @@ public: virtual void setHighlightFollowsCurrentItem(bool); enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange }; + Q_ENUM(HighlightRangeMode) HighlightRangeMode highlightRangeMode() const; void setHighlightRangeMode(HighlightRangeMode mode); @@ -200,6 +198,7 @@ public: virtual void setHighlightMoveDuration(int); enum PositionMode { Beginning, Center, End, Visible, Contain, SnapPosition }; + Q_ENUM(PositionMode) Q_INVOKABLE void positionViewAtIndex(int index, int mode); Q_INVOKABLE int indexAt(qreal x, qreal y) const; diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index a8352b229e..0931db4e56 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -53,6 +53,8 @@ public: qreal itemX() const; qreal itemY() const; + inline qreal itemWidth() const { return item ? item->width() : 0; } + inline qreal itemHeight() const { return item ? item->height() : 0; } void moveTo(const QPointF &pos, bool immediate); void setVisible(bool visible); @@ -75,7 +77,7 @@ public: virtual bool contains(qreal x, qreal y) const = 0; - QQuickItem *item; + QPointer<QQuickItem> item; QQuickItemView *view; QQuickItemViewTransitionableItem *transitionableItem; QQuickItemViewAttached *attached; @@ -198,6 +200,8 @@ public: qreal minExtentForAxis(const AxisData &axisData, bool forXAxis) const; qreal maxExtentForAxis(const AxisData &axisData, bool forXAxis) const; + qreal calculatedMinExtent() const; + qreal calculatedMaxExtent() const; void applyPendingChanges(); bool applyModelChanges(ChangeResult *insertionResult, ChangeResult *removalResult); diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index 7fa6cdc161..6fa299bf03 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -34,6 +34,7 @@ #include "qquickitemviewtransition_p.h" #include <QtQuick/qquickitem.h> #include <QtQuick/private/qquicktransition_p.h> +#include <QtQuick/private/qquicktransitionmanager_p_p.h> QT_BEGIN_NAMESPACE diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index 170072a814..6f93697cc5 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -34,16 +34,20 @@ #ifndef QQUICKITEMVIEWTRANSITION_P_P_H #define QQUICKITEMVIEWTRANSITION_P_P_H -#include <private/qquicktransitionmanager_p_p.h> +#include <QtQuick/private/qtquickglobal_p.h> +#include <QtCore/qobject.h> +#include <QtCore/qpoint.h> +#include <QtQml/qqml.h> QT_BEGIN_NAMESPACE class QQuickItem; +class QQuickTransition; class QQuickItemViewTransitionableItem; class QQuickItemViewTransitionJob; -class QQuickItemViewTransitionChangeListener +class Q_QUICK_PRIVATE_EXPORT QQuickItemViewTransitionChangeListener { public: QQuickItemViewTransitionChangeListener() {} @@ -53,7 +57,7 @@ public: }; -class QQuickItemViewTransitioner +class Q_QUICK_PRIVATE_EXPORT QQuickItemViewTransitioner { public: enum TransitionType { @@ -113,7 +117,7 @@ private: /* An item that can be transitioned using QQuickViewTransitionJob. */ -class QQuickItemViewTransitionableItem +class Q_QUICK_PRIVATE_EXPORT QQuickItemViewTransitionableItem { public: QQuickItemViewTransitionableItem(QQuickItem *i); diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 20b6dd5b36..a1d765d6ec 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -267,18 +267,18 @@ public: } qreal itemPosition() const { if (view->orientation() == QQuickListView::Vertical) - return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -item->height()-itemY() : itemY()); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -itemHeight()-itemY() : itemY()); else - return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX()); + return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemWidth()-itemX() : itemX()); } qreal size() const Q_DECL_OVERRIDE { if (section()) - return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight()+section()->height() : itemWidth()+section()->width()); else - return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight() : itemWidth()); } qreal itemSize() const { - return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight() : itemWidth()); } qreal sectionSize() const Q_DECL_OVERRIDE { if (section()) @@ -289,11 +289,11 @@ public: if (view->orientation() == QQuickListView::Vertical) { return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -itemY() - : itemY() + item->height()); + : itemY() + itemHeight()); } else { return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemX() - : itemX() + item->width()); + : itemX() + itemWidth()); } } void setPosition(qreal pos, bool immediate = false) { @@ -320,8 +320,8 @@ public: item->setWidth(size); } bool contains(qreal x, qreal y) const Q_DECL_OVERRIDE { - return (x >= itemX() && x < itemX() + item->width() && - y >= itemY() && y < itemY() + item->height()); + return (x >= itemX() && x < itemX() + itemWidth() && + y >= itemY() && y < itemY() + itemHeight()); } QQuickListView *view; @@ -332,7 +332,7 @@ private: if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) { if (section()) pos += section()->height(); - return QPointF(itemX(), -item->height() - pos); + return QPointF(itemX(), -itemHeight() - pos); } else { if (section()) pos += section()->height(); @@ -342,7 +342,7 @@ private: if (view->effectiveLayoutDirection() == Qt::RightToLeft) { if (section()) pos += section()->width(); - return QPointF(-item->width() - pos, itemY()); + return QPointF(-itemWidth() - pos, itemY()); } else { if (section()) pos += section()->width(); @@ -427,14 +427,24 @@ qreal QQuickListViewPrivate::lastPosition() const { qreal pos = 0; if (!visibleItems.isEmpty()) { - int invisibleCount = visibleItems.count() - visibleIndex; + int invisibleCount = INT_MIN; + int delayRemovedCount = 0; for (int i = visibleItems.count()-1; i >= 0; --i) { if (visibleItems.at(i)->index != -1) { - invisibleCount = model->count() - visibleItems.at(i)->index - 1; + // Find the invisible count after the last visible item with known index + invisibleCount = model->count() - (visibleItems.at(i)->index + 1 + delayRemovedCount); break; + } else if (visibleItems.at(i)->attached->delayRemove()) { + ++delayRemovedCount; } } - pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing); + if (invisibleCount == INT_MIN) { + // All visible items are in delayRemove state + invisibleCount = model->count(); + } + pos = (*(--visibleItems.constEnd()))->endPosition(); + if (invisibleCount > 0) + pos += invisibleCount * (averageSize + spacing); } else if (model && model->count()) { pos = (model->count() * averageSize + (model->count()-1) * spacing); } @@ -599,10 +609,11 @@ bool QQuickListViewPrivate::releaseItem(FxViewItem *item) if (!item || !model) return true; + QPointer<QQuickItem> it = item->item; QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached); bool released = QQuickItemViewPrivate::releaseItem(item); - if (released && att && att->m_sectionItem) { + if (released && it && att && att->m_sectionItem) { // We hold no more references to this item int i = 0; do { @@ -657,10 +668,11 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal while (modelIndex < model->count() && pos <= fillTo) { if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer)))) break; - qCDebug(lcItemViewDelegateLifecycle) << "refill: append item" << modelIndex << "pos" << pos << "buffer" << doBuffer << "item" << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "refill: append item" << modelIndex << "pos" << pos << "buffer" << doBuffer << "item" << (QObject *)(item->item); if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(pos, true); - QQuickItemPrivate::get(item->item)->setCulled(doBuffer); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(doBuffer); pos += item->size() + spacing; visibleItems.append(item); ++modelIndex; @@ -673,12 +685,13 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) { if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer)))) break; - qCDebug(lcItemViewDelegateLifecycle) << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos << "buffer" << doBuffer << "item" << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos << "buffer" << doBuffer << "item" << (QObject *)(item->item); --visibleIndex; visiblePos -= item->size() + spacing; if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(visiblePos, true); - QQuickItemPrivate::get(item->item)->setCulled(doBuffer); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(doBuffer); visibleItems.prepend(item); changed = true; } @@ -709,7 +722,7 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer visibleIndex++; visibleItems.removeAt(index); if (item->transitionScheduledOrRunning()) { - qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << (QObject *)(item->item); item->releaseAfterTransition = true; releasePendingTransition.append(item); } else { @@ -728,10 +741,10 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) { if (item->attached->delayRemove()) break; - qCDebug(lcItemViewDelegateLifecycle) << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position() << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position() << (QObject *)(item->item); visibleItems.removeLast(); if (item->transitionScheduledOrRunning()) { - qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << item->item->objectName(); + qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << (QObject *)(item->item); item->releaseAfterTransition = true; releasePendingTransition.append(item); } else { @@ -1457,13 +1470,13 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte tempPosition -= bias; } FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart); - if (!topItem && strictHighlightRange && currentItem) { + if (strictHighlightRange && currentItem) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); topItem = currentItem; } FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd); - if (!bottomItem && strictHighlightRange && currentItem) { + if (strictHighlightRange && currentItem) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); bottomItem = currentItem; @@ -2844,7 +2857,8 @@ void QQuickListView::viewportMoved(Qt::Orientations orient) qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd; for (int i = 0; i < d->visibleItems.count(); ++i) { FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i)); - QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to); } if (d->currentItem) QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to); diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h index bcb4e18751..7f64e12bba 100644 --- a/src/quick/items/qquicklistview_p.h +++ b/src/quick/items/qquicklistview_p.h @@ -47,8 +47,6 @@ class Q_AUTOTEST_EXPORT QQuickViewSection : public QObject Q_PROPERTY(SectionCriteria criteria READ criteria WRITE setCriteria NOTIFY criteriaChanged) Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_PROPERTY(int labelPositioning READ labelPositioning WRITE setLabelPositioning NOTIFY labelPositioningChanged) - Q_ENUMS(SectionCriteria) - Q_ENUMS(LabelPositioning) public: QQuickViewSection(QQuickListView *parent=0); @@ -56,6 +54,7 @@ public: void setProperty(const QString &); enum SectionCriteria { FullString, FirstCharacter }; + Q_ENUM(SectionCriteria) SectionCriteria criteria() const { return m_criteria; } void setCriteria(SectionCriteria); @@ -65,6 +64,7 @@ public: QString sectionString(const QString &value); enum LabelPositioning { InlineLabels = 0x01, CurrentLabelAtStart = 0x02, NextLabelAtEnd = 0x04 }; + Q_ENUM(LabelPositioning) int labelPositioning() { return m_labelPositioning; } void setLabelPositioning(int pos); @@ -106,10 +106,6 @@ class Q_AUTOTEST_EXPORT QQuickListView : public QQuickItemView Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 2) Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 2) - Q_ENUMS(Orientation) - Q_ENUMS(SnapMode) - Q_ENUMS(HeaderPositioning) - Q_ENUMS(FooterPositioning) Q_CLASSINFO("DefaultProperty", "data") public: @@ -120,6 +116,7 @@ public: void setSpacing(qreal spacing); enum Orientation { Horizontal = Qt::Horizontal, Vertical = Qt::Vertical }; + Q_ENUM(Orientation) Orientation orientation() const; void setOrientation(Orientation); @@ -140,14 +137,17 @@ public: void setHighlightMoveDuration(int) Q_DECL_OVERRIDE; enum SnapMode { NoSnap, SnapToItem, SnapOneItem }; + Q_ENUM(SnapMode) SnapMode snapMode() const; void setSnapMode(SnapMode mode); enum HeaderPositioning { InlineHeader, OverlayHeader, PullBackHeader }; + Q_ENUM(HeaderPositioning) HeaderPositioning headerPositioning() const; void setHeaderPositioning(HeaderPositioning positioning); enum FooterPositioning { InlineFooter, OverlayFooter, PullBackFooter }; + Q_ENUM(FooterPositioning) FooterPositioning footerPositioning() const; void setFooterPositioning(FooterPositioning positioning); diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index dd04568db2..d46e25d255 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -576,7 +576,6 @@ void QQuickLoader::setSource(QQmlV4Function *args) if (!ipv->isUndefined()) { d->disposeInitialPropertyValues(); d->initialPropertyValues.set(args->v4engine(), ipv); - d->qmlGlobalForIpv.set(args->v4engine(), args->qmlGlobal()); } setSource(sourceUrl, false); // already cleared and set ipv above. @@ -642,11 +641,11 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj) QQmlComponentPrivate *d = QQmlComponentPrivate::get(component); Q_ASSERT(d && d->engine); - QV4::ExecutionEngine *v4 = qmlGlobalForIpv.engine(); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(d->engine); Q_ASSERT(v4); QV4::Scope scope(v4); QV4::ScopedValue ipv(scope, initialPropertyValues.value()); - d->initializeObjectWithInitialProperties(*qmlGlobalForIpv.valueRef(), ipv, obj); + d->initializeObjectWithInitialProperties(ipv, obj); } void QQuickLoaderIncubator::statusChanged(Status status) @@ -943,7 +942,7 @@ QV4::ReturnedValue QQuickLoaderPrivate::extractInitialPropertyValues(QQmlV4Funct QV4::ScopedValue valuemap(scope, QV4::Primitive::undefinedValue()); if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); - if (!v->isObject() || v->asArrayObject()) { + if (!v->isObject() || v->as<QV4::ArrayObject>()) { *error = true; qmlInfo(loader) << QQuickLoader::tr("setSource: value is not an object"); } else { diff --git a/src/quick/items/qquickloader_p.h b/src/quick/items/qquickloader_p.h index 2c0e98de59..6ed4f2437b 100644 --- a/src/quick/items/qquickloader_p.h +++ b/src/quick/items/qquickloader_p.h @@ -42,7 +42,6 @@ class QQuickLoaderPrivate; class Q_AUTOTEST_EXPORT QQuickLoader : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(Status) Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -69,6 +68,7 @@ public: void resetSourceComponent(); enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; qreal progress() const; diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h index 621419d1a7..9677318b58 100644 --- a/src/quick/items/qquickloader_p_p.h +++ b/src/quick/items/qquickloader_p_p.h @@ -50,7 +50,7 @@ #include "qquickitemchangelistener_p.h" #include <qqmlincubator.h> -#include <private/qv4value_inl_p.h> +#include <private/qv4value_p.h> QT_BEGIN_NAMESPACE @@ -102,7 +102,6 @@ public: QQmlContext *itemContext; QQuickLoaderIncubator *incubator; QV4::PersistentValue initialPropertyValues; - QV4::PersistentValue qmlGlobalForIpv; bool updatingSize: 1; bool active : 1; bool loadingFromSource : 1; diff --git a/src/quick/items/qquickopenglinfo_p.h b/src/quick/items/qquickopenglinfo_p.h index 2a2e2a719b..511413c814 100644 --- a/src/quick/items/qquickopenglinfo_p.h +++ b/src/quick/items/qquickopenglinfo_p.h @@ -63,7 +63,6 @@ class QQuickOpenGLInfo : public QObject Q_PROPERTY(int minorVersion READ minorVersion NOTIFY minorVersionChanged FINAL) Q_PROPERTY(ContextProfile profile READ profile NOTIFY profileChanged FINAL) Q_PROPERTY(RenderableType renderableType READ renderableType NOTIFY renderableTypeChanged FINAL) - Q_ENUMS(ContextProfile RenderableType) public: QQuickOpenGLInfo(QQuickItem *item = 0); @@ -77,6 +76,7 @@ public: CoreProfile = QSurfaceFormat::CoreProfile, CompatibilityProfile = QSurfaceFormat::CompatibilityProfile }; + Q_ENUM(ContextProfile) ContextProfile profile() const; // keep in sync with QSurfaceFormat::RenderableType @@ -85,6 +85,7 @@ public: OpenGL = QSurfaceFormat::OpenGL, OpenGLES = QSurfaceFormat::OpenGLES }; + Q_ENUM(RenderableType) RenderableType renderableType() const; static QQuickOpenGLInfo *qmlAttachedProperties(QObject *object); diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h index 356e4a46f6..28eb3398a0 100644 --- a/src/quick/items/qquickpainteditem.h +++ b/src/quick/items/qquickpainteditem.h @@ -43,7 +43,6 @@ class QQuickPaintedItemPrivate; class Q_QUICK_EXPORT QQuickPaintedItem : public QQuickItem { Q_OBJECT - Q_ENUMS(RenderTarget) Q_PROPERTY(QSize contentsSize READ contentsSize WRITE setContentsSize NOTIFY contentsSizeChanged) Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged) @@ -58,6 +57,7 @@ public: FramebufferObject, InvertedYFramebufferObject }; + Q_ENUM(RenderTarget) enum PerformanceHint { FastFBOResizing = 0x1 diff --git a/src/quick/items/qquickpainteditem_p.h b/src/quick/items/qquickpainteditem_p.h index 3712e964f8..2759d9d683 100644 --- a/src/quick/items/qquickpainteditem_p.h +++ b/src/quick/items/qquickpainteditem_p.h @@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE class QQuickPaintedItemTextureProvider; class QSGPainterNode; -class QQuickPaintedItemPrivate : public QQuickItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickPaintedItemPrivate : public QQuickItemPrivate { public: QQuickPaintedItemPrivate(); diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp index 58605f79dd..302532c3d1 100644 --- a/src/quick/items/qquickpathview.cpp +++ b/src/quick/items/qquickpathview.cpp @@ -98,7 +98,7 @@ QQuickPathViewPrivate::QQuickPathViewPrivate() , inRefill(false) , dragMargin(0), deceleration(100), maximumFlickVelocity(QML_FLICK_DEFAULTMAXVELOCITY) , moveOffset(this, &QQuickPathViewPrivate::setAdjustedOffset), flickDuration(0) - , firstIndex(-1), pathItems(-1), requestedIndex(-1), cacheSize(0), requestedZ(0) + , pathItems(-1), requestedIndex(-1), cacheSize(0), requestedZ(0) , moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0) , moveHighlight(this, &QQuickPathViewPrivate::setHighlightPosition) , highlightPosition(0) @@ -447,7 +447,6 @@ void QQuickPathViewPrivate::regenerate() if (!isValid()) return; - firstIndex = -1; updateMappedRange(); q->refill(); } @@ -1473,7 +1472,7 @@ int QQuickPathView::indexAt(qreal x, qreal y) const QQuickItem *item = d->items.at(idx); QPointF p = item->mapFromItem(this, QPointF(x, y)); if (item->contains(p)) - return (d->firstIndex + idx) % d->modelCount; + return d->model->indexOf(item, 0); } return -1; @@ -1896,12 +1895,12 @@ void QQuickPathView::refill() int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount); // first move existing items and remove items off path - int idx = d->firstIndex; - qCDebug(lcItemViewDelegateLifecycle) << "firstIndex" << idx << "currentIndex" << d->currentIndex << "offset" << d->offset; + qCDebug(lcItemViewDelegateLifecycle) << "currentIndex" << d->currentIndex << "offset" << d->offset; QList<QQuickItem*>::iterator it = d->items.begin(); while (it != d->items.end()) { - qreal pos = d->positionOfIndex(idx); QQuickItem *item = *it; + int idx = d->model->indexOf(item, 0); + qreal pos = d->positionOfIndex(idx); if (lcItemViewDelegateLifecycle().isDebugEnabled()) { QQuickText *text = qmlobject_cast<QQuickText*>(item); if (text) @@ -1923,81 +1922,140 @@ void QQuickPathView::refill() if (!d->isInBound(pos, d->mappedRange - d->mappedCache, 1.0 + d->mappedCache)) { qCDebug(lcItemViewDelegateLifecycle) << "release" << idx << "@" << pos << ", !isInBound: lower" << (d->mappedRange - d->mappedCache) << "upper" << (1.0 + d->mappedCache); d->releaseItem(item); - if (it == d->items.begin()) { - if (++d->firstIndex >= d->modelCount) { - d->firstIndex = 0; - } - } it = d->items.erase(it); } else { ++it; } } - ++idx; - if (idx >= d->modelCount) - idx = 0; } - if (!d->items.count()) - d->firstIndex = -1; - bool waiting = false; if (d->modelCount) { - // add items to beginning and end + // add items as needed if (d->items.count() < count+d->cacheSize) { - int idx = qRound(d->modelCount - d->offset) % d->modelCount; + int endIdx = 0; + qreal endPos; + int startIdx = 0; qreal startPos = 0.0; - if (d->haveHighlightRange && (d->highlightRangeMode != QQuickPathView::NoHighlightRange - || d->snapMode != QQuickPathView::NoSnap)) - startPos = d->highlightRangeStart; - if (d->firstIndex >= 0) { - startPos = d->positionOfIndex(d->firstIndex); - idx = (d->firstIndex + d->items.count()) % d->modelCount; + if (d->items.count()) { + //Find the beginning and end, items may not be in sorted order + endPos = -1.0; + startPos = 2.0; + + for (int i = 0; i < d->items.count(); i++) { + int idx = d->model->indexOf(d->items[i], 0); + qreal curPos = d->positionOfIndex(idx); + if (curPos > endPos) { + endPos = curPos; + endIdx = idx; + } + + if (curPos < startPos) { + startPos = curPos; + startIdx = idx; + } + } + } else { + if (d->haveHighlightRange + && (d->highlightRangeMode != QQuickPathView::NoHighlightRange + || d->snapMode != QQuickPathView::NoSnap)) + startPos = d->highlightRangeStart; + // With no items, then "end" is just off the top so we populate via append + endIdx = (qRound(d->modelCount - d->offset) - 1) % d->modelCount; + endPos = d->positionOfIndex(endIdx); } - qreal pos = d->positionOfIndex(idx); - while ((d->isInBound(pos, startPos, 1.0 + d->mappedCache) || !d->items.count()) && d->items.count() < count+d->cacheSize) { - qCDebug(lcItemViewDelegateLifecycle) << "append" << idx << "@" << pos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); - QQuickItem *item = d->getItem(idx, idx+1, pos >= 1.0); + //Append + int idx = endIdx + 1; + if (idx >= d->modelCount) + idx = 0; + qreal nextPos = d->positionOfIndex(idx); + while ((d->isInBound(nextPos, endPos, 1.0 + d->mappedCache) || !d->items.count()) + && d->items.count() < count+d->cacheSize) { + qCDebug(lcItemViewDelegateLifecycle) << "append" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); + QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0); if (!item) { waiting = true; break; } + if (d->items.contains(item)) { + break; //Otherwise we'd "re-add" it, and get confused + } if (d->currentIndex == idx) { currentVisible = true; - d->currentItemOffset = pos; + d->currentItemOffset = nextPos; } - if (d->items.count() == 0) - d->firstIndex = idx; d->items.append(item); - d->updateItem(item, pos); + d->updateItem(item, nextPos); + endIdx = idx; + endPos = nextPos; ++idx; if (idx >= d->modelCount) idx = 0; - pos = d->positionOfIndex(idx); + nextPos = d->positionOfIndex(idx); } - idx = d->firstIndex - 1; + //Prepend + idx = startIdx - 1; if (idx < 0) idx = d->modelCount - 1; - pos = d->positionOfIndex(idx); - while (!waiting && d->isInBound(pos, d->mappedRange - d->mappedCache, startPos) && d->items.count() < count+d->cacheSize) { - qCDebug(lcItemViewDelegateLifecycle) << "prepend" << idx << "@" << pos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); - QQuickItem *item = d->getItem(idx, idx+1, pos >= 1.0); + nextPos = d->positionOfIndex(idx); + while (!waiting && d->isInBound(nextPos, d->mappedRange - d->mappedCache, startPos) + && d->items.count() < count+d->cacheSize) { + qCDebug(lcItemViewDelegateLifecycle) << "prepend" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); + QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0); if (!item) { waiting = true; break; } + if (d->items.contains(item)) { + break; //Otherwise we'd "re-add" it, and get confused + } if (d->currentIndex == idx) { currentVisible = true; - d->currentItemOffset = pos; + d->currentItemOffset = nextPos; } d->items.prepend(item); - d->updateItem(item, pos); - d->firstIndex = idx; - idx = d->firstIndex - 1; + d->updateItem(item, nextPos); + startIdx = idx; + startPos = nextPos; + --idx; if (idx < 0) idx = d->modelCount - 1; - pos = d->positionOfIndex(idx); + nextPos = d->positionOfIndex(idx); + } + + // In rare cases, when jumping around with pathCount close to modelCount, + // new items appear in the middle. This more generic addition iteration handles this + // Since this is the rare case, we try append/prepend first and only do this if + // there are gaps still left to fill. + if (!waiting && d->items.count() < count+d->cacheSize) { + qCDebug(lcItemViewDelegateLifecycle) << "Checking for pathview middle inserts, items count was" << d->items.count(); + idx = startIdx; + QQuickItem *lastItem = d->items[0]; + while (idx != endIdx) { + //This gets the reference from the delegate model, and will not re-create + QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0); + if (!item) { + waiting = true; + break; + } + if (!d->items.contains(item)) { //We found a hole + nextPos = d->positionOfIndex(idx); + qCDebug(lcItemViewDelegateLifecycle) << "middle insert" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); + if (d->currentIndex == idx) { + currentVisible = true; + d->currentItemOffset = nextPos; + } + int lastListIdx = d->items.indexOf(lastItem); + d->items.insert(lastListIdx + 1, item); + d->updateItem(item, nextPos); + } + + lastItem = item; + ++idx; + if (idx >= d->modelCount) + idx = 0; + } } } } @@ -2128,7 +2186,6 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset) d->offset = qmlMod(d->modelCount - d->currentIndex, d->modelCount); changedOffset = true; } - d->firstIndex = -1; d->updateMappedRange(); d->scheduleLayout(); } @@ -2185,8 +2242,16 @@ void QQuickPathViewPrivate::createCurrentItem() { if (requestedIndex != -1) return; - int itemIndex = (currentIndex - firstIndex + modelCount) % modelCount; - if (itemIndex < items.count()) { + + bool inItems = false; + for (int i = 0; i < items.count(); i++) { + if (model->indexOf(items[i], 0) == currentIndex) { + inItems = true; + break; + } + } + + if (inItems) { if ((currentItem = getItem(currentIndex, currentIndex))) { currentItem->setFocus(true); if (QQuickPathViewAttached *att = attached(currentItem)) diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h index 8062e07795..0f2e4a956c 100644 --- a/src/quick/items/qquickpathview_p.h +++ b/src/quick/items/qquickpathview_p.h @@ -78,10 +78,6 @@ class Q_AUTOTEST_EXPORT QQuickPathView : public QQuickItem Q_PROPERTY(int cacheItemCount READ cacheItemCount WRITE setCacheItemCount NOTIFY cacheItemCountChanged) - Q_ENUMS(HighlightRangeMode) - Q_ENUMS(SnapMode) - Q_ENUMS(PositionMode) - public: QQuickPathView(QQuickItem *parent=0); virtual ~QQuickPathView(); @@ -105,6 +101,7 @@ public: QQuickItem *highlightItem(); enum HighlightRangeMode { NoHighlightRange, ApplyRange, StrictlyEnforceRange }; + Q_ENUM(HighlightRangeMode) HighlightRangeMode highlightRangeMode() const; void setHighlightRangeMode(HighlightRangeMode mode); @@ -146,10 +143,12 @@ public: void setCacheItemCount(int); enum SnapMode { NoSnap, SnapToItem, SnapOneItem }; + Q_ENUM(SnapMode) SnapMode snapMode() const; void setSnapMode(SnapMode mode); enum PositionMode { Beginning, Center, End, Contain=4, SnapPosition }; // 3 == Visible in other views + Q_ENUM(PositionMode) Q_INVOKABLE void positionViewAtIndex(int index, int mode); Q_INVOKABLE int indexAt(qreal x, qreal y) const; Q_INVOKABLE QQuickItem *itemAt(qreal x, qreal y) const; diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h index 35ea8616a5..2a497881d4 100644 --- a/src/quick/items/qquickpathview_p_p.h +++ b/src/quick/items/qquickpathview_p_p.h @@ -155,7 +155,6 @@ public: QQuickTimeLine tl; QQuickTimeLineValueProxy<QQuickPathViewPrivate> moveOffset; int flickDuration; - int firstIndex; int pathItems; int requestedIndex; int cacheSize; diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h index d2de59b5d6..602b2804cc 100644 --- a/src/quick/items/qquickpincharea_p.h +++ b/src/quick/items/qquickpincharea_p.h @@ -42,7 +42,6 @@ class Q_AUTOTEST_EXPORT QQuickPinch : public QObject { Q_OBJECT - Q_ENUMS(Axis) Q_PROPERTY(QQuickItem *target READ target WRITE setTarget RESET resetTarget) Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged) Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged) @@ -103,6 +102,7 @@ public: } enum Axis { NoDrag=0x00, XAxis=0x01, YAxis=0x02, XAndYAxis=0x03, XandYAxis=XAndYAxis }; + Q_ENUM(Axis) Axis axis() const { return m_axis; } void setAxis(Axis a) { if (a == m_axis) diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp index 887d317069..de2596b679 100644 --- a/src/quick/items/qquickpositioners.cpp +++ b/src/quick/items/qquickpositioners.cpp @@ -70,6 +70,10 @@ QQuickBasePositioner::PositionedItem::PositionedItem(QQuickItem *i) , index(-1) , isNew(false) , isVisible(true) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) { } @@ -116,6 +120,13 @@ void QQuickBasePositioner::PositionedItem::startTransition(QQuickItemViewTransit transitionableItem->startTransition(transitioner, index); } +void QQuickBasePositioner::PositionedItem::updatePadding(qreal lp, qreal tp, qreal rp, qreal bp) +{ + leftPadding = lp; + topPadding = tp; + rightPadding = rp; + bottomPadding = bp; +} QQuickBasePositioner::QQuickBasePositioner(PositionerType at, QQuickItem *parent) : QQuickImplicitSizeItem(*(new QQuickBasePositionerPrivate), parent) @@ -388,11 +399,8 @@ void QQuickBasePositioner::prePositioning() void QQuickBasePositioner::positionItem(qreal x, qreal y, PositionedItem *target) { - Q_D(QQuickBasePositioner); - if ( (target->itemX() != x || target->itemY() != y) - && d->type == Both) { + if ( target->itemX() != x || target->itemY() != y ) target->moveTo(QPointF(x, y)); - } } void QQuickBasePositioner::positionItemX(qreal x, PositionedItem *target) @@ -503,6 +511,185 @@ void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *sp } } +qreal QQuickBasePositioner::padding() const +{ + Q_D(const QQuickBasePositioner); + return d->padding(); +} + +void QQuickBasePositioner::setPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + if (qFuzzyCompare(d->padding(), padding)) + return; + + d->extra.value().padding = padding; + d->setPositioningDirty(); + emit paddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) + emit topPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickBasePositioner::resetPadding() +{ + setPadding(0); +} + +qreal QQuickBasePositioner::topPadding() const +{ + Q_D(const QQuickBasePositioner); + if (d->extra.isAllocated() && d->extra->explicitTopPadding) + return d->extra->topPadding; + return d->padding(); +} + +void QQuickBasePositioner::setTopPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + d->setTopPadding(padding); +} + +void QQuickBasePositioner::resetTopPadding() +{ + Q_D(QQuickBasePositioner); + d->setTopPadding(0, true); +} + +qreal QQuickBasePositioner::leftPadding() const +{ + Q_D(const QQuickBasePositioner); + if (d->extra.isAllocated() && d->extra->explicitLeftPadding) + return d->extra->leftPadding; + return d->padding(); +} + +void QQuickBasePositioner::setLeftPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + d->setLeftPadding(padding); +} + +void QQuickBasePositioner::resetLeftPadding() +{ + Q_D(QQuickBasePositioner); + d->setLeftPadding(0, true); +} + +qreal QQuickBasePositioner::rightPadding() const +{ + Q_D(const QQuickBasePositioner); + if (d->extra.isAllocated() && d->extra->explicitRightPadding) + return d->extra->rightPadding; + return d->padding(); +} + +void QQuickBasePositioner::setRightPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + d->setRightPadding(padding); +} + +void QQuickBasePositioner::resetRightPadding() +{ + Q_D(QQuickBasePositioner); + d->setRightPadding(0, true); +} + +qreal QQuickBasePositioner::bottomPadding() const +{ + Q_D(const QQuickBasePositioner); + if (d->extra.isAllocated() && d->extra->explicitBottomPadding) + return d->extra->bottomPadding; + return d->padding(); +} + +void QQuickBasePositioner::setBottomPadding(qreal padding) +{ + Q_D(QQuickBasePositioner); + d->setBottomPadding(padding); +} + +void QQuickBasePositioner::resetBottomPadding() +{ + Q_D(QQuickBasePositioner); + d->setBottomPadding(0, true); +} + +QQuickBasePositionerPrivate::ExtraData::ExtraData() + : padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) +{ +} + +void QQuickBasePositionerPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickBasePositioner); + qreal oldPadding = q->topPadding(); + if (!reset || extra.isAllocated()) { + extra.value().topPadding = value; + extra.value().explicitTopPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + setPositioningDirty(); + emit q->topPaddingChanged(); + } +} + +void QQuickBasePositionerPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickBasePositioner); + qreal oldPadding = q->leftPadding(); + if (!reset || extra.isAllocated()) { + extra.value().leftPadding = value; + extra.value().explicitLeftPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + setPositioningDirty(); + emit q->leftPaddingChanged(); + } +} + +void QQuickBasePositionerPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickBasePositioner); + qreal oldPadding = q->rightPadding(); + if (!reset || extra.isAllocated()) { + extra.value().rightPadding = value; + extra.value().explicitRightPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + setPositioningDirty(); + emit q->rightPaddingChanged(); + } +} + +void QQuickBasePositionerPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickBasePositioner); + qreal oldPadding = q->bottomPadding(); + if (!reset || extra.isAllocated()) { + extra.value().bottomPadding = value; + extra.value().explicitBottomPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + setPositioningDirty(); + emit q->bottomPaddingChanged(); + } +} + /*! \qmltype Positioner \instantiates QQuickPositionerAttached @@ -640,6 +827,16 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem) \sa Row, Grid, Flow, Positioner, ColumnLayout, {Qt Quick Examples - Positioners} */ /*! + \since 5.6 + \qmlproperty real QtQuick::Column::padding + \qmlproperty real QtQuick::Column::topPadding + \qmlproperty real QtQuick::Column::leftPadding + \qmlproperty real QtQuick::Column::bottomPadding + \qmlproperty real QtQuick::Column::rightPadding + + These properties hold the padding around the content. +*/ +/*! \qmlproperty Transition QtQuick::Column::populate This property holds the transition to be run for items that are part of @@ -715,20 +912,23 @@ QQuickColumn::QQuickColumn(QQuickItem *parent) void QQuickColumn::doPositioning(QSizeF *contentSize) { //Precondition: All items in the positioned list have a valid item pointer and should be positioned - qreal voffset = 0; + qreal voffset = topPadding(); + const qreal padding = leftPadding() + rightPadding(); + contentSize->setWidth(qMax(contentSize->width(), padding)); for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; - positionItemY(voffset, &child); - contentSize->setWidth(qMax(contentSize->width(), child.item->width())); + positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); + contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding)); voffset += child.item->height(); voffset += spacing(); } - if (voffset != 0)//If we positioned any items, undo the spacing from the last item + if (voffset - topPadding() != 0)//If we positioned any items, undo the spacing from the last item voffset -= spacing(); - contentSize->setHeight(voffset); + contentSize->setHeight(voffset + bottomPadding()); } void QQuickColumn::reportConflictingAnchors() @@ -794,6 +994,16 @@ void QQuickColumn::reportConflictingAnchors() \sa Column, Grid, Flow, Positioner, RowLayout, {Qt Quick Examples - Positioners} */ /*! + \since 5.6 + \qmlproperty real QtQuick::Row::padding + \qmlproperty real QtQuick::Row::topPadding + \qmlproperty real QtQuick::Row::leftPadding + \qmlproperty real QtQuick::Row::bottomPadding + \qmlproperty real QtQuick::Row::rightPadding + + These properties hold the padding around the content. +*/ +/*! \qmlproperty Transition QtQuick::Row::populate This property holds the transition to be run for items that are part of @@ -940,27 +1150,34 @@ void QQuickRow::doPositioning(QSizeF *contentSize) { //Precondition: All items in the positioned list have a valid item pointer and should be positioned QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this)); - qreal hoffset = 0; + qreal hoffset1 = leftPadding(); + qreal hoffset2 = rightPadding(); + if (!d->isLeftToRight()) + qSwap(hoffset1, hoffset2); + qreal hoffset = hoffset1; + const qreal padding = topPadding() + bottomPadding(); + contentSize->setHeight(qMax(contentSize->height(), padding)); QList<qreal> hoffsets; for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; if (d->isLeftToRight()) { - positionItemX(hoffset, &child); + positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } else { hoffsets << hoffset; } - contentSize->setHeight(qMax(contentSize->height(), child.item->height())); + contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding)); hoffset += child.item->width(); hoffset += spacing(); } - if (hoffset != 0)//If we positioned any items, undo the extra spacing from the last item + if (hoffset - hoffset1 != 0)//If we positioned any items, undo the extra spacing from the last item hoffset -= spacing(); - contentSize->setWidth(hoffset); + contentSize->setWidth(hoffset + hoffset2); if (d->isLeftToRight()) return; @@ -976,7 +1193,8 @@ void QQuickRow::doPositioning(QSizeF *contentSize) for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; hoffset = end - hoffsets[acc++] - child.item->width(); - positionItemX(hoffset, &child); + positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } } @@ -1044,6 +1262,16 @@ void QQuickRow::reportConflictingAnchors() \sa Flow, Row, Column, Positioner, GridLayout, {Qt Quick Examples - Positioners} */ /*! + \since 5.6 + \qmlproperty real QtQuick::Grid::padding + \qmlproperty real QtQuick::Grid::topPadding + \qmlproperty real QtQuick::Grid::leftPadding + \qmlproperty real QtQuick::Grid::bottomPadding + \qmlproperty real QtQuick::Grid::rightPadding + + These properties hold the padding around the content. +*/ +/*! \qmlproperty Transition QtQuick::Grid::populate This property holds the transition to be run for items that are part of @@ -1423,8 +1651,11 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) c = (numVisible+(m_rows-1))/m_rows; } - if (r == 0 || c == 0) - return; //Nothing to do + if (r == 0 || c == 0) { + contentSize->setHeight(topPadding() + bottomPadding()); + contentSize->setWidth(leftPadding() + rightPadding()); + return; //Nothing else to do + } QList<qreal> maxColWidth; QList<qreal> maxRowHeight; @@ -1476,6 +1707,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) widthSum += columnSpacing; widthSum += maxColWidth[j]; } + widthSum += leftPadding() + rightPadding(); qreal heightSum = 0; for (int i = 0; i < maxRowHeight.size(); i++) { @@ -1483,6 +1715,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) heightSum += rowSpacing; heightSum += maxRowHeight[i]; } + heightSum += topPadding() + bottomPadding(); contentSize->setHeight(heightSum); contentSize->setWidth(widthSum); @@ -1493,10 +1726,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) else end = widthSum; - qreal xoffset = 0; + qreal xoffset = leftPadding(); if (!d->isLeftToRight()) - xoffset = end; - qreal yoffset = 0; + xoffset = end - rightPadding(); + qreal yoffset = topPadding(); int curRow =0; int curCol =0; for (int i = 0; i < positionedItems.count(); ++i) { @@ -1518,6 +1751,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) alignYOffset += maxRowHeight[curRow] - child.item->height(); positionItem(childXOffset, alignYOffset, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); if (m_flow == LeftToRight) { if (d->isLeftToRight()) @@ -1529,9 +1763,9 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) if (!curCol) { yoffset += maxRowHeight[curRow]+rowSpacing; if (d->isLeftToRight()) - xoffset = 0; + xoffset = leftPadding(); else - xoffset = end; + xoffset = end - rightPadding(); curRow++; if (curRow>=r) break; @@ -1545,7 +1779,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) xoffset += maxColWidth[curCol]+columnSpacing; else xoffset -= maxColWidth[curCol]+columnSpacing; - yoffset = 0; + yoffset = topPadding(); curCol++; if (curCol>=c) break; @@ -1603,6 +1837,16 @@ void QQuickGrid::reportConflictingAnchors() \sa Column, Row, Grid, Positioner, {Qt Quick Examples - Positioners} */ /*! + \since 5.6 + \qmlproperty real QtQuick::Flow::padding + \qmlproperty real QtQuick::Flow::topPadding + \qmlproperty real QtQuick::Flow::leftPadding + \qmlproperty real QtQuick::Flow::bottomPadding + \qmlproperty real QtQuick::Flow::rightPadding + + These properties hold the padding around the content. +*/ +/*! \qmlproperty Transition QtQuick::Flow::populate This property holds the transition to be run for items that are part of @@ -1786,23 +2030,30 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) //Precondition: All items in the positioned list have a valid item pointer and should be positioned Q_D(QQuickFlow); - qreal hoffset = 0; - qreal voffset = 0; + qreal hoffset1 = leftPadding(); + qreal hoffset2 = rightPadding(); + if (!d->isLeftToRight()) + qSwap(hoffset1, hoffset2); + qreal hoffset = hoffset1; + const qreal voffset1 = topPadding(); + qreal voffset = voffset1; qreal linemax = 0; QList<qreal> hoffsets; + contentSize->setWidth(qMax(contentSize->width(), hoffset1 + hoffset2)); + contentSize->setHeight(qMax(contentSize->height(), voffset + bottomPadding())); for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; if (d->flow == LeftToRight) { - if (widthValid() && hoffset && hoffset + child.item->width() > width()) { - hoffset = 0; + if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) { + hoffset = hoffset1; voffset += linemax + spacing(); linemax = 0; } } else { - if (heightValid() && voffset && voffset + child.item->height() > height()) { - voffset = 0; + if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) { + voffset = voffset1; hoffset += linemax + spacing(); linemax = 0; } @@ -1810,13 +2061,16 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) if (d->isLeftToRight()) { positionItem(hoffset, voffset, &child); + child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } else { hoffsets << hoffset; positionItemY(voffset, &child); + child.topPadding = topPadding(); + child.bottomPadding = bottomPadding(); } - contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width())); - contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height())); + contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2)); + contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding())); if (d->flow == LeftToRight) { hoffset += child.item->width(); @@ -1828,6 +2082,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) linemax = qMax(linemax, child.item->width()); } } + if (d->isLeftToRight()) return; @@ -1841,6 +2096,8 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) PositionedItem &child = positionedItems[i]; hoffset = end - hoffsets[acc++] - child.item->width(); positionItemX(hoffset, &child); + child.leftPadding = leftPadding(); + child.rightPadding = rightPadding(); } } diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h index ea779695eb..bc67701306 100644 --- a/src/quick/items/qquickpositioners_p.h +++ b/src/quick/items/qquickpositioners_p.h @@ -86,6 +86,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickBasePositioner : public QQuickImplicitSizeIte Q_PROPERTY(QQuickTransition *populate READ populate WRITE setPopulate NOTIFY populateChanged) Q_PROPERTY(QQuickTransition *move READ move WRITE setMove NOTIFY moveChanged) Q_PROPERTY(QQuickTransition *add READ add WRITE setAdd NOTIFY addChanged) + + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6) public: enum PositionerType { None = 0x0, Horizontal = 0x1, Vertical = 0x2, Both = 0x3 }; @@ -108,6 +114,26 @@ public: void updateAttachedProperties(QQuickPositionerAttached *specificProperty = 0, QQuickItem *specificPropertyOwner = 0) const; + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + protected: QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent); void componentComplete() Q_DECL_OVERRIDE; @@ -120,6 +146,11 @@ Q_SIGNALS: void populateChanged(); void moveChanged(); void addChanged(); + Q_REVISION(6) void paddingChanged(); + Q_REVISION(6) void topPaddingChanged(); + Q_REVISION(6) void leftPaddingChanged(); + Q_REVISION(6) void rightPaddingChanged(); + Q_REVISION(6) void bottomPaddingChanged(); protected Q_SLOTS: void prePositioning(); @@ -144,11 +175,18 @@ protected: bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds); void startTransition(QQuickItemViewTransitioner *transitioner); + void updatePadding(qreal lp, qreal tp, qreal rp, qreal bp); + QQuickItem *item; QQuickItemViewTransitionableItem *transitionableItem; int index; bool isNew; bool isVisible; + + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; }; QPODVector<PositionedItem,8> positionedItems; @@ -236,8 +274,8 @@ public: void setColumnSpacing(qreal); void resetColumnSpacing() { m_useColumnSpacing = false; } - Q_ENUMS(Flow) enum Flow { LeftToRight, TopToBottom }; + Q_ENUM(Flow) Flow flow() const; void setFlow(Flow); @@ -245,14 +283,14 @@ public: void setLayoutDirection (Qt::LayoutDirection); Qt::LayoutDirection effectiveLayoutDirection() const; - Q_ENUMS(HAlignment) - Q_ENUMS(VAlignment) enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter}; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) HAlignment hItemAlign() const; void setHItemAlign(HAlignment align); @@ -301,8 +339,8 @@ class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner public: QQuickFlow(QQuickItem *parent=0); - Q_ENUMS(Flow) enum Flow { LeftToRight, TopToBottom }; + Q_ENUM(Flow) Flow flow() const; void setFlow(Flow); diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h index 3a8fe20351..6e1e15d4ef 100644 --- a/src/quick/items/qquickpositioners_p_p.h +++ b/src/quick/items/qquickpositioners_p_p.h @@ -51,6 +51,7 @@ #include <QtQuick/private/qquickstate_p.h> #include <private/qquicktransitionmanager_p_p.h> #include <private/qquickstatechangescript_p.h> +#include <private/qlazilyallocated_p.h> #include <QtCore/qobject.h> #include <QtCore/qstring.h> @@ -65,10 +66,26 @@ class QQuickBasePositionerPrivate : public QQuickImplicitSizeItemPrivate, public Q_DECLARE_PUBLIC(QQuickBasePositioner) public: + struct ExtraData { + ExtraData(); + + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding : 1; + bool explicitLeftPadding : 1; + bool explicitRightPadding : 1; + bool explicitBottomPadding : 1; + }; + QLazilyAllocated<ExtraData> extra; + QQuickBasePositionerPrivate() : spacing(0), type(QQuickBasePositioner::None) , transitioner(0), positioningDirty(false) , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight) + { } @@ -149,6 +166,12 @@ public: virtual void effectiveLayoutDirectionChange() { } + + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickrectangle_p.h b/src/quick/items/qquickrectangle_p.h index 8a00dbaf92..16afa39bdd 100644 --- a/src/quick/items/qquickrectangle_p.h +++ b/src/quick/items/qquickrectangle_p.h @@ -125,7 +125,7 @@ private: }; class QQuickRectanglePrivate; -class Q_AUTOTEST_EXPORT QQuickRectangle : public QQuickItem +class Q_QUICK_PRIVATE_EXPORT QQuickRectangle : public QQuickItem { Q_OBJECT diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index 6b0b9c3a06..cc4cec443a 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -46,7 +46,6 @@ #include <QtQuick/QQuickWindow> #include <QtQuick/private/qquickwindow_p.h> -#include <private/qqmlprofilerservice_p.h> #include <QtCore/private/qobject_p.h> QT_BEGIN_NAMESPACE diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp index 0168d73c8f..09b504b742 100644 --- a/src/quick/items/qquickrepeater.cpp +++ b/src/quick/items/qquickrepeater.cpp @@ -50,6 +50,7 @@ QQuickRepeaterPrivate::QQuickRepeaterPrivate() , delegateValidated(false) , itemCount(0) { + setTransparentForPositioner(true); } QQuickRepeaterPrivate::~QQuickRepeaterPrivate() @@ -360,8 +361,8 @@ void QQuickRepeater::clear() if (QQuickItem *item = d->deletables.at(i)) { if (complete) emit itemRemoved(i, item); - item->setParentItem(0); d->model->release(item); + item->setParentItem(0); } } } @@ -397,9 +398,17 @@ void QQuickRepeaterPrivate::requestItems() void QQuickRepeater::createdItem(int index, QObject *) { Q_D(QQuickRepeater); + QObject *object = d->model->object(index, false); + QQuickItem *item = qmlobject_cast<QQuickItem*>(object); + emit itemAdded(index, item); +} + +void QQuickRepeater::initItem(int index, QObject *object) +{ + Q_D(QQuickRepeater); + QQuickItem *item = qmlobject_cast<QQuickItem*>(object); + if (!d->deletables.at(index)) { - QObject *object = d->model->object(index, false); - QQuickItem *item = qmlobject_cast<QQuickItem*>(object); if (!item) { if (object) { d->model->release(object); @@ -425,17 +434,9 @@ void QQuickRepeater::createdItem(int index, QObject *) } item->stackBefore(after); } - emit itemAdded(index, item); } } -void QQuickRepeater::initItem(int, QObject *object) -{ - QQuickItem *item = qmlobject_cast<QQuickItem*>(object); - if (item) - item->setParentItem(parentItem()); -} - void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset) { Q_D(QQuickRepeater); @@ -465,8 +466,8 @@ void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset) d->deletables.remove(index); emit itemRemoved(index, item); if (item) { - item->setParentItem(0); d->model->release(item); + item->setParentItem(0); } --d->itemCount; } diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h index 7e0c021c19..b12da7a706 100644 --- a/src/quick/items/qquickscalegrid_p_p.h +++ b/src/quick/items/qquickscalegrid_p_p.h @@ -47,7 +47,6 @@ QT_BEGIN_NAMESPACE class QQuickScaleGrid : public QObject { Q_OBJECT - Q_ENUMS(TileRule) Q_PROPERTY(int left READ left WRITE setLeft NOTIFY borderChanged) Q_PROPERTY(int top READ top WRITE setTop NOTIFY borderChanged) diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index 1c60d9feaa..75a8319615 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -92,8 +92,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem Q_PROPERTY(QString log READ log NOTIFY logChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1) - Q_ENUMS(CullMode) - Q_ENUMS(Status) public: enum CullMode @@ -102,6 +100,7 @@ public: BackFaceCulling = QQuickShaderEffectMaterial::BackFaceCulling, FrontFaceCulling = QQuickShaderEffectMaterial::FrontFaceCulling }; + Q_ENUM(CullMode) enum Status { @@ -109,6 +108,7 @@ public: Uncompiled, Error }; + Q_ENUM(Status) QQuickShaderEffect(QQuickItem *parent = 0); ~QQuickShaderEffect(); diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp index de6cae0ea6..b84a4adaab 100644 --- a/src/quick/items/qquickshadereffectnode.cpp +++ b/src/quick/items/qquickshadereffectnode.cpp @@ -83,7 +83,9 @@ QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectM , m_compiled(false) , m_initialized(false) { - for (int i = 0; i < m_attributes.count(); ++i) + const int attributesCount = m_attributes.count(); + m_attributeNames.reserve(attributesCount + 1); + for (int i = 0; i < attributesCount; ++i) m_attributeNames.append(m_attributes.at(i).constData()); m_attributeNames.append(0); } diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h index 31e503be42..94bb315566 100644 --- a/src/quick/items/qquickshadereffectsource_p.h +++ b/src/quick/items/qquickshadereffectsource_p.h @@ -67,7 +67,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged) Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged) - Q_ENUMS(Format WrapMode) public: enum WrapMode { ClampToEdge, @@ -75,12 +74,14 @@ public: RepeatVertically, Repeat }; + Q_ENUM(WrapMode) enum Format { Alpha = GL_ALPHA, RGB = GL_RGB, RGBA = GL_RGBA }; + Q_ENUM(Format) QQuickShaderEffectSource(QQuickItem *parent = 0); ~QQuickShaderEffectSource(); diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index 579919db27..ac7fbc24af 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -358,7 +358,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction xa; xa.property = property; - xa.toBinding = QQmlAbstractBinding::getPointer(newBinding); + xa.toBinding = newBinding; xa.fromValue = xa.property.read(); xa.deletableToBinding = true; actions << xa; @@ -377,7 +377,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction ya; ya.property = property; - ya.toBinding = QQmlAbstractBinding::getPointer(newBinding); + ya.toBinding = newBinding; ya.fromValue = ya.property.read(); ya.deletableToBinding = true; actions << ya; @@ -396,7 +396,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction sa; sa.property = property; - sa.toBinding = QQmlAbstractBinding::getPointer(newBinding); + sa.toBinding = newBinding; sa.fromValue = sa.property.read(); sa.deletableToBinding = true; actions << sa; @@ -415,7 +415,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction ra; ra.property = property; - ra.toBinding = QQmlAbstractBinding::getPointer(newBinding); + ra.toBinding = newBinding; ra.fromValue = ra.property.read(); ra.deletableToBinding = true; actions << ra; @@ -434,7 +434,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction wa; wa.property = property; - wa.toBinding = QQmlAbstractBinding::getPointer(newBinding); + wa.toBinding = newBinding; wa.fromValue = wa.property.read(); wa.deletableToBinding = true; actions << wa; @@ -453,7 +453,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions() newBinding->setTarget(property); QQuickStateAction ha; ha.property = property; - ha.toBinding = QQmlAbstractBinding::getPointer(newBinding); + ha.toBinding = newBinding; ha.fromValue = ha.property.read(); ha.deletableToBinding = true; actions << ha; @@ -482,7 +482,7 @@ void QQuickParentChange::saveOriginals() saveCurrentValues(); }*/ -void QQuickParentChange::execute(Reason) +void QQuickParentChange::execute() { Q_D(QQuickParentChange); d->doChange(d->parent); @@ -493,7 +493,7 @@ bool QQuickParentChange::isReversable() return true; } -void QQuickParentChange::reverse(Reason) +void QQuickParentChange::reverse() { Q_D(QQuickParentChange); d->doChange(d->origParent, d->origStackBefore); @@ -765,12 +765,7 @@ class QQuickAnchorChangesPrivate : public QQuickStateOperationPrivate { public: QQuickAnchorChangesPrivate() - : target(0), anchorSet(new QQuickAnchorSet), - leftBinding(0), rightBinding(0), hCenterBinding(0), - topBinding(0), bottomBinding(0), vCenterBinding(0), baselineBinding(0), - origLeftBinding(0), origRightBinding(0), origHCenterBinding(0), - origTopBinding(0), origBottomBinding(0), origVCenterBinding(0), - origBaselineBinding(0) + : target(0), anchorSet(new QQuickAnchorSet) { } @@ -779,21 +774,21 @@ public: QQuickItem *target; QQuickAnchorSet *anchorSet; - QQmlBinding *leftBinding; - QQmlBinding *rightBinding; - QQmlBinding *hCenterBinding; - QQmlBinding *topBinding; - QQmlBinding *bottomBinding; - QQmlBinding *vCenterBinding; - QQmlBinding *baselineBinding; - - QQmlAbstractBinding *origLeftBinding; - QQmlAbstractBinding *origRightBinding; - QQmlAbstractBinding *origHCenterBinding; - QQmlAbstractBinding *origTopBinding; - QQmlAbstractBinding *origBottomBinding; - QQmlAbstractBinding *origVCenterBinding; - QQmlAbstractBinding *origBaselineBinding; + QExplicitlySharedDataPointer<QQmlBinding> leftBinding; + QExplicitlySharedDataPointer<QQmlBinding> rightBinding; + QExplicitlySharedDataPointer<QQmlBinding> hCenterBinding; + QExplicitlySharedDataPointer<QQmlBinding> topBinding; + QExplicitlySharedDataPointer<QQmlBinding> bottomBinding; + QExplicitlySharedDataPointer<QQmlBinding> vCenterBinding; + QExplicitlySharedDataPointer<QQmlBinding> baselineBinding; + + QQmlAbstractBinding::Ptr origLeftBinding; + QQmlAbstractBinding::Ptr origRightBinding; + QQmlAbstractBinding::Ptr origHCenterBinding; + QQmlAbstractBinding::Ptr origTopBinding; + QQmlAbstractBinding::Ptr origBottomBinding; + QQmlAbstractBinding::Ptr origVCenterBinding; + QQmlAbstractBinding::Ptr origBaselineBinding; QQuickAnchorLine rewindLeft; QQuickAnchorLine rewindRight; @@ -831,8 +826,6 @@ public: qreal origX; qreal origY; - QList<QQmlAbstractBinding*> oldBindings; - QQmlProperty leftProp; QQmlProperty rightProp; QQmlProperty hCenterProp; @@ -849,29 +842,6 @@ QQuickAnchorChanges::QQuickAnchorChanges(QObject *parent) QQuickAnchorChanges::~QQuickAnchorChanges() { - /* - if the anchorchanges is active at destruction, any non-active orig - bindings need to be destroyed - - the basic logic is that if both e.g. left and origLeft are present, - then we are active (otherwise left would have been destroyed), and - left is in use and origLeft needs to be cleaned up. - */ - Q_D(QQuickAnchorChanges); - if (d->leftBinding && d->origLeftBinding) - d->origLeftBinding->destroy(); - if (d->rightBinding && d->origRightBinding) - d->origRightBinding->destroy(); - if (d->hCenterBinding && d->origHCenterBinding) - d->origHCenterBinding->destroy(); - if (d->topBinding && d->origTopBinding) - d->origTopBinding->destroy(); - if (d->bottomBinding && d->origBottomBinding) - d->origBottomBinding->destroy(); - if (d->vCenterBinding && d->origVCenterBinding) - d->origVCenterBinding->destroy(); - if (d->baselineBinding && d->origBaselineBinding) - d->origBaselineBinding->destroy(); } QQuickAnchorChanges::ActionList QQuickAnchorChanges::actions() @@ -967,7 +937,7 @@ void QQuickAnchorChanges::setObject(QQuickItem *target) \endqml */ -void QQuickAnchorChanges::execute(Reason reason) +void QQuickAnchorChanges::execute() { Q_D(QQuickAnchorChanges); if (!d->target) @@ -978,94 +948,84 @@ void QQuickAnchorChanges::execute(Reason reason) if (d->applyOrigLeft) { if (!d->origLeftBinding) targetPrivate->anchors()->resetLeft(); - QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding); + QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding.data()); } if (d->applyOrigRight) { if (!d->origRightBinding) targetPrivate->anchors()->resetRight(); - QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding); + QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding.data()); } if (d->applyOrigHCenter) { if (!d->origHCenterBinding) targetPrivate->anchors()->resetHorizontalCenter(); - QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding); + QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding.data()); } if (d->applyOrigTop) { if (!d->origTopBinding) targetPrivate->anchors()->resetTop(); - QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding); + QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding.data()); } if (d->applyOrigBottom) { if (!d->origBottomBinding) targetPrivate->anchors()->resetBottom(); - QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding); + QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding.data()); } if (d->applyOrigVCenter) { if (!d->origVCenterBinding) targetPrivate->anchors()->resetVerticalCenter(); - QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding); + QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding.data()); } if (d->applyOrigBaseline) { if (!d->origBaselineBinding) targetPrivate->anchors()->resetBaseline(); - QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding); - } - - //destroy old bindings - if (reason == ActualChange) { - for (int i = 0; i < d->oldBindings.size(); ++i) { - QQmlAbstractBinding *binding = d->oldBindings.at(i); - if (binding) - binding->destroy(); - } - d->oldBindings.clear(); + QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding.data()); } //reset any anchors that have been specified as "undefined" if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::LeftAnchor) { targetPrivate->anchors()->resetLeft(); - QQmlPropertyPrivate::setBinding(d->leftProp, 0); + QQmlPropertyPrivate::removeBinding(d->leftProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::RightAnchor) { targetPrivate->anchors()->resetRight(); - QQmlPropertyPrivate::setBinding(d->rightProp, 0); + QQmlPropertyPrivate::removeBinding(d->rightProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::HCenterAnchor) { targetPrivate->anchors()->resetHorizontalCenter(); - QQmlPropertyPrivate::setBinding(d->hCenterProp, 0); + QQmlPropertyPrivate::removeBinding(d->hCenterProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::TopAnchor) { targetPrivate->anchors()->resetTop(); - QQmlPropertyPrivate::setBinding(d->topProp, 0); + QQmlPropertyPrivate::removeBinding(d->topProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::BottomAnchor) { targetPrivate->anchors()->resetBottom(); - QQmlPropertyPrivate::setBinding(d->bottomProp, 0); + QQmlPropertyPrivate::removeBinding(d->bottomProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::VCenterAnchor) { targetPrivate->anchors()->resetVerticalCenter(); - QQmlPropertyPrivate::setBinding(d->vCenterProp, 0); + QQmlPropertyPrivate::removeBinding(d->vCenterProp); } if (d->anchorSet->d_func()->resetAnchors & QQuickAnchors::BaselineAnchor) { targetPrivate->anchors()->resetBaseline(); - QQmlPropertyPrivate::setBinding(d->baselineProp, 0); + QQmlPropertyPrivate::removeBinding(d->baselineProp); } //set any anchors that have been specified if (d->leftBinding) - QQmlPropertyPrivate::setBinding(d->leftBinding->property(), d->leftBinding); + QQmlPropertyPrivate::setBinding(d->leftBinding.data()); if (d->rightBinding) - QQmlPropertyPrivate::setBinding(d->rightBinding->property(), d->rightBinding); + QQmlPropertyPrivate::setBinding(d->rightBinding.data()); if (d->hCenterBinding) - QQmlPropertyPrivate::setBinding(d->hCenterBinding->property(), d->hCenterBinding); + QQmlPropertyPrivate::setBinding(d->hCenterBinding.data()); if (d->topBinding) - QQmlPropertyPrivate::setBinding(d->topBinding->property(), d->topBinding); + QQmlPropertyPrivate::setBinding(d->topBinding.data()); if (d->bottomBinding) - QQmlPropertyPrivate::setBinding(d->bottomBinding->property(), d->bottomBinding); + QQmlPropertyPrivate::setBinding(d->bottomBinding.data()); if (d->vCenterBinding) - QQmlPropertyPrivate::setBinding(d->vCenterBinding->property(), d->vCenterBinding); + QQmlPropertyPrivate::setBinding(d->vCenterBinding.data()); if (d->baselineBinding) - QQmlPropertyPrivate::setBinding(d->baselineBinding->property(), d->baselineBinding); + QQmlPropertyPrivate::setBinding(d->baselineBinding.data()); } bool QQuickAnchorChanges::isReversable() @@ -1073,7 +1033,7 @@ bool QQuickAnchorChanges::isReversable() return true; } -void QQuickAnchorChanges::reverse(Reason reason) +void QQuickAnchorChanges::reverse() { Q_D(QQuickAnchorChanges); if (!d->target) @@ -1083,69 +1043,48 @@ void QQuickAnchorChanges::reverse(Reason reason) //reset any anchors set by the state if (d->leftBinding) { targetPrivate->anchors()->resetLeft(); - QQmlPropertyPrivate::setBinding(d->leftBinding->property(), 0); - if (reason == ActualChange) { - d->leftBinding->destroy(); d->leftBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->leftBinding.data()); } if (d->rightBinding) { targetPrivate->anchors()->resetRight(); - QQmlPropertyPrivate::setBinding(d->rightBinding->property(), 0); - if (reason == ActualChange) { - d->rightBinding->destroy(); d->rightBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->rightBinding.data()); } if (d->hCenterBinding) { targetPrivate->anchors()->resetHorizontalCenter(); - QQmlPropertyPrivate::setBinding(d->hCenterBinding->property(), 0); - if (reason == ActualChange) { - d->hCenterBinding->destroy(); d->hCenterBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->hCenterBinding.data()); } if (d->topBinding) { targetPrivate->anchors()->resetTop(); - QQmlPropertyPrivate::setBinding(d->topBinding->property(), 0); - if (reason == ActualChange) { - d->topBinding->destroy(); d->topBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->topBinding.data()); } if (d->bottomBinding) { targetPrivate->anchors()->resetBottom(); - QQmlPropertyPrivate::setBinding(d->bottomBinding->property(), 0); - if (reason == ActualChange) { - d->bottomBinding->destroy(); d->bottomBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->bottomBinding.data()); } if (d->vCenterBinding) { targetPrivate->anchors()->resetVerticalCenter(); - QQmlPropertyPrivate::setBinding(d->vCenterBinding->property(), 0); - if (reason == ActualChange) { - d->vCenterBinding->destroy(); d->vCenterBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->vCenterBinding.data()); } if (d->baselineBinding) { targetPrivate->anchors()->resetBaseline(); - QQmlPropertyPrivate::setBinding(d->baselineBinding->property(), 0); - if (reason == ActualChange) { - d->baselineBinding->destroy(); d->baselineBinding = 0; - } + QQmlPropertyPrivate::removeBinding(d->baselineBinding.data()); } //restore previous anchors if (d->origLeftBinding) - QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding); + QQmlPropertyPrivate::setBinding(d->leftProp, d->origLeftBinding.data()); if (d->origRightBinding) - QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding); + QQmlPropertyPrivate::setBinding(d->rightProp, d->origRightBinding.data()); if (d->origHCenterBinding) - QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding); + QQmlPropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding.data()); if (d->origTopBinding) - QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding); + QQmlPropertyPrivate::setBinding(d->topProp, d->origTopBinding.data()); if (d->origBottomBinding) - QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding); + QQmlPropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding.data()); if (d->origVCenterBinding) - QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding); + QQmlPropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding.data()); if (d->origBaselineBinding) - QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding); + QQmlPropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding.data()); //restore any absolute geometry changed by the state's anchors QQuickAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Vertical_Mask; @@ -1289,10 +1228,6 @@ void QQuickAnchorChanges::copyOriginals(QQuickStateActionEvent *other) d->origX = acp->origX; d->origY = acp->origY; - d->oldBindings.clear(); - d->oldBindings << acp->leftBinding << acp->rightBinding << acp->hCenterBinding - << acp->topBinding << acp->bottomBinding << acp->vCenterBinding << acp->baselineBinding; - //clear old values from other //### could this be generalized for all QQuickStateActionEvents, and called after copyOriginals? acp->leftBinding = 0; @@ -1333,31 +1268,31 @@ void QQuickAnchorChanges::clearBindings() d->anchorSet->d_func()->usedAnchors; if (d->applyOrigLeft || (combined & QQuickAnchors::LeftAnchor)) { targetPrivate->anchors()->resetLeft(); - QQmlPropertyPrivate::setBinding(d->leftProp, 0); + QQmlPropertyPrivate::removeBinding(d->leftProp); } if (d->applyOrigRight || (combined & QQuickAnchors::RightAnchor)) { targetPrivate->anchors()->resetRight(); - QQmlPropertyPrivate::setBinding(d->rightProp, 0); + QQmlPropertyPrivate::removeBinding(d->rightProp); } if (d->applyOrigHCenter || (combined & QQuickAnchors::HCenterAnchor)) { targetPrivate->anchors()->resetHorizontalCenter(); - QQmlPropertyPrivate::setBinding(d->hCenterProp, 0); + QQmlPropertyPrivate::removeBinding(d->hCenterProp); } if (d->applyOrigTop || (combined & QQuickAnchors::TopAnchor)) { targetPrivate->anchors()->resetTop(); - QQmlPropertyPrivate::setBinding(d->topProp, 0); + QQmlPropertyPrivate::removeBinding(d->topProp); } if (d->applyOrigBottom || (combined & QQuickAnchors::BottomAnchor)) { targetPrivate->anchors()->resetBottom(); - QQmlPropertyPrivate::setBinding(d->bottomProp, 0); + QQmlPropertyPrivate::removeBinding(d->bottomProp); } if (d->applyOrigVCenter || (combined & QQuickAnchors::VCenterAnchor)) { targetPrivate->anchors()->resetVerticalCenter(); - QQmlPropertyPrivate::setBinding(d->vCenterProp, 0); + QQmlPropertyPrivate::removeBinding(d->vCenterProp); } if (d->applyOrigBaseline || (combined & QQuickAnchors::BaselineAnchor)) { targetPrivate->anchors()->resetBaseline(); - QQmlPropertyPrivate::setBinding(d->baselineProp, 0); + QQmlPropertyPrivate::removeBinding(d->baselineProp); } } diff --git a/src/quick/items/qquickstateoperations_p.h b/src/quick/items/qquickstateoperations_p.h index 8d4231c5fa..1999e23a83 100644 --- a/src/quick/items/qquickstateoperations_p.h +++ b/src/quick/items/qquickstateoperations_p.h @@ -97,9 +97,9 @@ public: void saveOriginals() Q_DECL_OVERRIDE; //virtual void copyOriginals(QQuickStateActionEvent*); - void execute(Reason reason = ActualChange) Q_DECL_OVERRIDE; + void execute() Q_DECL_OVERRIDE; bool isReversable() Q_DECL_OVERRIDE; - void reverse(Reason reason = ActualChange) Q_DECL_OVERRIDE; + void reverse() Q_DECL_OVERRIDE; EventType type() const Q_DECL_OVERRIDE; bool override(QQuickStateActionEvent*other) Q_DECL_OVERRIDE; void rewind() Q_DECL_OVERRIDE; @@ -180,9 +180,9 @@ public: QQuickItem *object() const; void setObject(QQuickItem *); - void execute(Reason reason = ActualChange) Q_DECL_OVERRIDE; + void execute() Q_DECL_OVERRIDE; bool isReversable() Q_DECL_OVERRIDE; - void reverse(Reason reason = ActualChange) Q_DECL_OVERRIDE; + void reverse() Q_DECL_OVERRIDE; EventType type() const Q_DECL_OVERRIDE; bool override(QQuickStateActionEvent*other) Q_DECL_OVERRIDE; bool changesBindings() Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 205571f2e7..924c455872 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -85,7 +85,16 @@ QQuickTextPrivate::QQuickTextPrivate() } QQuickTextPrivate::ExtraData::ExtraData() - : lineHeight(1.0) + : padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) + , lineHeight(1.0) , doc(0) , minimumPixelSize(12) , minimumPointSize(12) @@ -284,6 +293,74 @@ qreal QQuickTextPrivate::getImplicitHeight() const return implicitHeight; } +qreal QQuickTextPrivate::availableWidth() const +{ + Q_Q(const QQuickText); + return q->width() - q->leftPadding() - q->rightPadding(); +} + +qreal QQuickTextPrivate::availableHeight() const +{ + Q_Q(const QQuickText); + return q->height() - q->topPadding() - q->bottomPadding(); +} + +void QQuickTextPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickText); + qreal oldPadding = q->topPadding(); + if (!reset || extra.isAllocated()) { + extra.value().topPadding = value; + extra.value().explicitTopPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateSize(); + emit q->topPaddingChanged(); + } +} + +void QQuickTextPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickText); + qreal oldPadding = q->leftPadding(); + if (!reset || extra.isAllocated()) { + extra.value().leftPadding = value; + extra.value().explicitLeftPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateSize(); + emit q->leftPaddingChanged(); + } +} + +void QQuickTextPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickText); + qreal oldPadding = q->rightPadding(); + if (!reset || extra.isAllocated()) { + extra.value().rightPadding = value; + extra.value().explicitRightPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateSize(); + emit q->rightPaddingChanged(); + } +} + +void QQuickTextPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickText); + qreal oldPadding = q->bottomPadding(); + if (!reset || extra.isAllocated()) { + extra.value().bottomPadding = value; + extra.value().explicitBottomPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateSize(); + emit q->bottomPaddingChanged(); + } +} + /*! \qmlproperty bool QtQuick::Text::antialiasing @@ -327,9 +404,9 @@ void QQuickTextPrivate::updateLayout() formatModifiesFontSize = fontSizeModified; multilengthEos = -1; } else { - layout.clearAdditionalFormats(); + layout.clearFormats(); if (elideLayout) - elideLayout->clearAdditionalFormats(); + elideLayout->clearFormats(); QString tmp = text; multilengthEos = tmp.indexOf(QLatin1Char('\x9c')); if (multilengthEos != -1) { @@ -410,7 +487,7 @@ void QQuickTextPrivate::updateBaseline(qreal baseline, qreal dy) yoff = dy/2; } - q->setBaselineOffset(baseline + yoff); + q->setBaselineOffset(baseline + yoff + q->topPadding()); } void QQuickTextPrivate::updateSize() @@ -430,6 +507,9 @@ void QQuickTextPrivate::updateSize() return; } + qreal hPadding = q->leftPadding() + q->rightPadding(); + qreal vPadding = q->topPadding() + q->bottomPadding(); + if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) { // How much more expensive is it to just do a full layout on an empty string here? // There may be subtle differences in the height and baseline calculations between @@ -442,8 +522,8 @@ void QQuickTextPrivate::updateSize() ? lineHeight() : fontHeight * lineHeight(); } - updateBaseline(fm.ascent(), q->height() - fontHeight); - q->setImplicitSize(0, fontHeight); + updateBaseline(fm.ascent(), q->height() - fontHeight - vPadding); + q->setImplicitSize(hPadding, fontHeight + vPadding); layedOutTextRect = QRectF(0, 0, 0, fontHeight); emit q->contentSizeChanged(); updateType = UpdatePaintNode; @@ -464,7 +544,7 @@ void QQuickTextPrivate::updateSize() layedOutTextRect = textRect; size = textRect.size(); - updateBaseline(baseline, q->height() - size.height()); + updateBaseline(baseline, q->height() - size.height() - vPadding); } else { widthExceeded = true; // always relayout rich text on width changes.. heightExceeded = false; // rich text layout isn't affected by height changes. @@ -488,15 +568,15 @@ void QQuickTextPrivate::updateSize() naturalWidth = extra->doc->idealWidth(); const bool wasInLayout = internalWidthUpdate; internalWidthUpdate = true; - q->setImplicitWidth(naturalWidth); + q->setImplicitWidth(naturalWidth + hPadding); internalWidthUpdate = wasInLayout; } if (internalWidthUpdate) return; extra->doc->setPageSize(QSizeF()); - if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < q->width())) - extra->doc->setTextWidth(q->width()); + if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < availableWidth())) + extra->doc->setTextWidth(availableWidth()); else extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) @@ -505,7 +585,7 @@ void QQuickTextPrivate::updateSize() size = QSizeF(extra->doc->idealWidth(),dsize.height()); QFontMetricsF fm(font); - updateBaseline(fm.ascent(), q->height() - size.height()); + updateBaseline(fm.ascent(), q->height() - size.height() - vPadding); //### need to confirm cost of always setting these for richText internalWidthUpdate = true; @@ -513,11 +593,11 @@ void QQuickTextPrivate::updateSize() if (!q->widthValid()) iWidth = size.width(); if (iWidth > -1) - q->setImplicitSize(iWidth, size.height()); + q->setImplicitSize(iWidth + hPadding, size.height() + vPadding); internalWidthUpdate = false; if (iWidth == -1) - q->setImplicitHeight(size.height()); + q->setImplicitHeight(size.height() + vPadding); } if (layedOutTextRect.size() != previousSize) @@ -623,7 +703,7 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, // use the text item's width by default if it has one and wrap is on or text must be aligned if (q->widthValid() && (q->wrapMode() != QQuickText::NoWrap || q->effectiveHAlign() != QQuickText::AlignLeft)) - textLine->setWidth(q->width()); + textLine->setWidth(availableWidth()); else textLine->setWidth(INT_MAX); if (lineHeight() != 1.0) @@ -635,10 +715,10 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, } void QQuickTextPrivate::elideFormats( - const int start, const int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats) + const int start, const int length, int offset, QVector<QTextLayout::FormatRange> *elidedFormats) { const int end = start + length; - QList<QTextLayout::FormatRange> formats = layout.additionalFormats(); + const QVector<QTextLayout::FormatRange> formats = layout.formats(); for (int i = 0; i < formats.count(); ++i) { QTextLayout::FormatRange format = formats.at(i); const int formatLength = qMin(format.start + format.length, end) - qMax(format.start, start); @@ -691,10 +771,11 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) && (q->heightValid() || maximumLineCountValid); if ((!requireImplicitSize || (implicitWidthValid && implicitHeightValid)) - && ((singlelineElide && q->width() <= 0.) || (multilineElide && q->heightValid() && q->height() <= 0.))) { + && ((singlelineElide && availableWidth() <= 0.) + || (multilineElide && q->heightValid() && availableHeight() <= 0.))) { // we are elided and we have a zero width or height - widthExceeded = q->widthValid() && q->width() <= 0.; - heightExceeded = q->heightValid() && q->height() <= 0.; + widthExceeded = q->widthValid() && availableWidth() <= 0.; + heightExceeded = q->heightValid() && availableHeight() <= 0.; if (!truncated) { truncated = true; @@ -730,7 +811,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0 ? q->width() : FLT_MAX; - qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX; + qreal maxHeight = q->heightValid() ? availableHeight() : FLT_MAX; const bool customLayout = isLineLaidOutConnected(); const bool wasTruncated = truncated; @@ -751,8 +832,8 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) int scaledFontSize = largeFont; bool widthChanged = false; - widthExceeded = q->width() <= 0 && (singlelineElide || canWrap || horizontalFit); - heightExceeded = q->height() <= 0 && (multilineElide || verticalFit); + widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit); + heightExceeded = availableHeight() <= 0 && (multilineElide || verticalFit); QRectF br; @@ -922,7 +1003,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) bool wasInLayout = internalWidthUpdate; internalWidthUpdate = true; - q->setImplicitSize(naturalWidth, naturalHeight); + q->setImplicitSize(naturalWidth + q->leftPadding() + q->rightPadding(), naturalHeight + q->topPadding() + q->bottomPadding()); internalWidthUpdate = wasInLayout; // Update any variables that are dependent on the validity of the width or height. @@ -939,8 +1020,11 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) const qreal oldWidth = lineWidth; const qreal oldHeight = maxHeight; - lineWidth = q->widthValid() && q->width() > 0 ? q->width() : naturalWidth; - maxHeight = q->heightValid() ? q->height() : FLT_MAX; + const qreal availWidth = availableWidth(); + const qreal availHeight = availableHeight(); + + lineWidth = q->widthValid() && availWidth > 0 ? availWidth : naturalWidth; + maxHeight = q->heightValid() ? availHeight : FLT_MAX; // If the width of the item has changed and it's possible the result of wrapping, // eliding, scaling has changed, or the text is not left aligned do another layout. @@ -993,7 +1077,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) && (q->heightValid() || (maximumLineCountValid && canWrap)); const qreal oldHeight = maxHeight; - maxHeight = q->heightValid() ? q->height() : FLT_MAX; + maxHeight = q->heightValid() ? availableHeight() : FLT_MAX; // If the height of the item has changed and it's possible the result of eliding, // line count truncation or scaling has changed, do another layout. if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight)) @@ -1073,7 +1157,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) elideLayout->setCacheEnabled(true); } if (styledText) { - QList<QTextLayout::FormatRange> formats; + QVector<QTextLayout::FormatRange> formats; switch (elideMode) { case QQuickText::ElideRight: elideFormats(elideStart, elideText.length() - 1, 0, &formats); @@ -1096,7 +1180,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) default: break; } - elideLayout->setAdditionalFormats(formats); + elideLayout->setFormats(formats); } elideLayout->setFont(layout.font()); @@ -1361,6 +1445,16 @@ QQuickText::~QQuickText() */ /*! + \qmlproperty string QtQuick::Text::font.styleName + \since 5.6 + + Sets the style name of the font. + + The style name is case insensitive. If set, the font will be matched against style name instead + of the font properties \l weight, \l bold and \l italic. +*/ + +/*! \qmlproperty bool QtQuick::Text::font.bold Sets whether the font weight is bold. @@ -2279,7 +2373,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data d->updateType = QQuickTextPrivate::UpdateNone; - const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), height(), d->vAlign); + const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), d->availableHeight(), d->vAlign) + topPadding(); QQuickTextNode *node = 0; if (!oldNode) @@ -2296,11 +2390,11 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data const QColor linkColor = QColor::fromRgba(d->linkColor); if (d->richText) { - const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), effectiveHAlign()); + const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), d->availableWidth(), effectiveHAlign()) + leftPadding(); d->ensureDoc(); node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor); } else if (d->layedOutTextRect.width() > 0) { - const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), effectiveHAlign()); + const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, d->availableWidth(), effectiveHAlign()) + leftPadding(); int unelidedLineCount = d->lineCount; if (d->elideLayout) unelidedLineCount -= 1; @@ -2570,7 +2664,7 @@ QString QQuickTextPrivate::anchorAt(const QTextLayout *layout, const QPointF &mo QTextLine line = layout->lineAt(i); if (line.naturalTextRect().contains(mousePos)) { int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter); - foreach (const QTextLayout::FormatRange &formatRange, layout->additionalFormats()) { + foreach (const QTextLayout::FormatRange &formatRange, layout->formats()) { if (formatRange.format.isAnchor() && charPos >= formatRange.start && charPos < formatRange.start + formatRange.length) { @@ -2587,14 +2681,15 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const { Q_Q(const QQuickText); QPointF translatedMousePos = mousePos; - translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect.height() + lineHeightOffset(), q->height(), vAlign); + translatedMousePos.rx() -= q->leftPadding(); + translatedMousePos.ry() -= q->topPadding() + QQuickTextUtil::alignedY(layedOutTextRect.height() + lineHeightOffset(), availableHeight(), vAlign); if (styledText) { QString link = anchorAt(&layout, translatedMousePos); if (link.isEmpty() && elideLayout) link = anchorAt(elideLayout, translatedMousePos); return link; } else if (richText && extra.isAllocated() && extra->doc) { - translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), q->effectiveHAlign()); + translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), availableWidth(), q->effectiveHAlign()); return extra->doc->documentLayout()->anchorAt(translatedMousePos); } return QString(); @@ -2812,4 +2907,125 @@ void QQuickText::invalidateFontCaches() } } +/*! + \since 5.6 + \qmlproperty real QtQuick::Text::padding + \qmlproperty real QtQuick::Text::topPadding + \qmlproperty real QtQuick::Text::leftPadding + \qmlproperty real QtQuick::Text::bottomPadding + \qmlproperty real QtQuick::Text::rightPadding + + These properties hold the padding around the content. This space is reserved + in addition to the contentWidth and contentHeight. +*/ +qreal QQuickText::padding() const +{ + Q_D(const QQuickText); + return d->padding(); +} + +void QQuickText::setPadding(qreal padding) +{ + Q_D(QQuickText); + if (qFuzzyCompare(d->padding(), padding)) + return; + + d->extra.value().padding = padding; + d->updateSize(); + emit paddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) + emit topPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickText::resetPadding() +{ + setPadding(0); +} + +qreal QQuickText::topPadding() const +{ + Q_D(const QQuickText); + if (d->extra.isAllocated() && d->extra->explicitTopPadding) + return d->extra->topPadding; + return d->padding(); +} + +void QQuickText::setTopPadding(qreal padding) +{ + Q_D(QQuickText); + d->setTopPadding(padding); +} + +void QQuickText::resetTopPadding() +{ + Q_D(QQuickText); + d->setTopPadding(0, true); +} + +qreal QQuickText::leftPadding() const +{ + Q_D(const QQuickText); + if (d->extra.isAllocated() && d->extra->explicitLeftPadding) + return d->extra->leftPadding; + return d->padding(); +} + +void QQuickText::setLeftPadding(qreal padding) +{ + Q_D(QQuickText); + d->setLeftPadding(padding); +} + +void QQuickText::resetLeftPadding() +{ + Q_D(QQuickText); + d->setLeftPadding(0, true); +} + +qreal QQuickText::rightPadding() const +{ + Q_D(const QQuickText); + if (d->extra.isAllocated() && d->extra->explicitRightPadding) + return d->extra->rightPadding; + return d->padding(); +} + +void QQuickText::setRightPadding(qreal padding) +{ + Q_D(QQuickText); + d->setRightPadding(padding); +} + +void QQuickText::resetRightPadding() +{ + Q_D(QQuickText); + d->setRightPadding(0, true); +} + +qreal QQuickText::bottomPadding() const +{ + Q_D(const QQuickText); + if (d->extra.isAllocated() && d->extra->explicitBottomPadding) + return d->extra->bottomPadding; + return d->padding(); +} + +void QQuickText::setBottomPadding(qreal padding) +{ + Q_D(QQuickText); + d->setBottomPadding(padding); +} + +void QQuickText::resetBottomPadding() +{ + Q_D(QQuickText); + d->setBottomPadding(0, true); +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index 283e3b510b..f92927c9c4 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -45,15 +45,6 @@ class QQuickTextLine; class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(HAlignment) - Q_ENUMS(VAlignment) - Q_ENUMS(TextStyle) - Q_ENUMS(TextFormat) - Q_ENUMS(TextElideMode) - Q_ENUMS(WrapMode) - Q_ENUMS(LineHeightMode) - Q_ENUMS(FontSizeMode) - Q_ENUMS(RenderType) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) @@ -84,6 +75,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) Q_PROPERTY(QString hoveredLink READ hoveredLink NOTIFY linkHovered REVISION 2) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6) + public: QQuickText(QQuickItem *parent=0); ~QQuickText(); @@ -92,21 +89,26 @@ public: AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter, AlignJustify = Qt::AlignJustify }; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) enum TextStyle { Normal, Outline, Raised, Sunken }; + Q_ENUM(TextStyle) enum TextFormat { PlainText = Qt::PlainText, RichText = Qt::RichText, AutoText = Qt::AutoText, StyledText = 4 }; + Q_ENUM(TextFormat) enum TextElideMode { ElideLeft = Qt::ElideLeft, ElideRight = Qt::ElideRight, ElideMiddle = Qt::ElideMiddle, ElideNone = Qt::ElideNone }; + Q_ENUM(TextElideMode) enum WrapMode { NoWrap = QTextOption::NoWrap, WordWrap = QTextOption::WordWrap, @@ -114,15 +116,19 @@ public: WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere }; + Q_ENUM(WrapMode) enum RenderType { QtRendering, NativeRendering }; + Q_ENUM(RenderType) enum LineHeightMode { ProportionalHeight, FixedHeight }; + Q_ENUM(LineHeightMode) enum FontSizeMode { FixedSize = 0x0, HorizontalFit = 0x01, VerticalFit = 0x02, Fit = HorizontalFit | VerticalFit }; + Q_ENUM(FontSizeMode) QString text() const; void setText(const QString &); @@ -204,6 +210,26 @@ public: Q_REVISION(3) Q_INVOKABLE QString linkAt(qreal x, qreal y) const; + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + Q_SIGNALS: void textChanged(const QString &text); void linkActivated(const QString &link); @@ -231,6 +257,11 @@ Q_SIGNALS: void lineLaidOut(QQuickTextLine *line); void baseUrlChanged(); void renderTypeChanged(); + Q_REVISION(6) void paddingChanged(); + Q_REVISION(6) void topPaddingChanged(); + Q_REVISION(6) void leftPaddingChanged(); + Q_REVISION(6) void rightPaddingChanged(); + Q_REVISION(6) void bottomPaddingChanged(); protected: void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index cd14008728..f43df691b5 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -78,7 +78,7 @@ public: int lineHeightOffset() const; QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const; - void elideFormats(int start, int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats); + void elideFormats(int start, int length, int offset, QVector<QTextLayout::FormatRange> *elidedFormats); void processHoverEvent(QHoverEvent *event); @@ -87,6 +87,15 @@ public: struct ExtraData { ExtraData(); + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding : 1; + bool explicitLeftPadding : 1; + bool explicitRightPadding : 1; + bool explicitBottomPadding : 1; qreal lineHeight; QQuickTextDocumentWithImageResources *doc; QString activeLink; @@ -160,6 +169,15 @@ public: qreal getImplicitWidth() const Q_DECL_OVERRIDE; qreal getImplicitHeight() const Q_DECL_OVERRIDE; + qreal availableWidth() const; + qreal availableHeight() const; + + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); + void ensureDoc(); QRectF setupTextLayout(qreal * const baseline); diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 6929bb44a2..7bc5fab677 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -1313,7 +1313,7 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) QTextLayout *layout = block.layout(); if (isGettingInput) layout->setPreeditArea(cursor.position() - block.position(), e->preeditString()); - QList<QTextLayout::FormatRange> overrides; + QVector<QTextLayout::FormatRange> overrides; const int oldPreeditCursor = preeditCursor; preeditCursor = e->preeditString().length(); hasImState = !e->preeditString().isEmpty(); @@ -1336,7 +1336,7 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) } } } - layout->setAdditionalFormats(overrides); + layout->setFormats(overrides); cursor.endEditBlock(); diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index cd1cf5eef1..dc4e301a36 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -172,6 +172,13 @@ QQuickTextEdit::QQuickTextEdit(QQuickItem *parent) d->init(); } +QQuickTextEdit::QQuickTextEdit(QQuickTextEditPrivate &dd, QQuickItem *parent) +: QQuickImplicitSizeItem(dd, parent) +{ + Q_D(QQuickTextEdit); + d->init(); +} + QString QQuickTextEdit::text() const { Q_D(const QQuickTextEdit); @@ -199,6 +206,17 @@ QString QQuickTextEdit::text() const */ /*! + \qmlproperty string QtQuick::TextEdit::font.styleName + \since 5.6 + + Sets the style name of the font. + + The style name is case insensitive. If set, the font will be matched against style name instead + of the font properties \l weight, \l bold and \l italic. +*/ + + +/*! \qmlproperty bool QtQuick::TextEdit::font.bold Sets whether the font weight is bold. @@ -699,6 +717,62 @@ Qt::InputMethodHints QQuickTextEditPrivate::effectiveInputMethodHints() const } #endif +void QQuickTextEditPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->topPadding(); + if (!reset || extra.isAllocated()) { + extra.value().topPadding = value; + extra.value().explicitTopPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + q->updateSize(); + emit q->topPaddingChanged(); + } +} + +void QQuickTextEditPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->leftPadding(); + if (!reset || extra.isAllocated()) { + extra.value().leftPadding = value; + extra.value().explicitLeftPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + q->updateSize(); + emit q->leftPaddingChanged(); + } +} + +void QQuickTextEditPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->rightPadding(); + if (!reset || extra.isAllocated()) { + extra.value().rightPadding = value; + extra.value().explicitRightPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + q->updateSize(); + emit q->rightPaddingChanged(); + } +} + +void QQuickTextEditPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->bottomPadding(); + if (!reset || extra.isAllocated()) { + extra.value().bottomPadding = value; + extra.value().explicitBottomPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + q->updateSize(); + emit q->bottomPaddingChanged(); + } +} + QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const { Q_D(const QQuickTextEdit); @@ -1658,6 +1732,8 @@ void QQuickTextEdit::mousePressEvent(QMouseEvent *event) #ifndef QT_NO_IM if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) qGuiApp->inputMethod()->show(); +#else + Q_UNUSED(hadActiveFocus); #endif } if (!event->isAccepted()) @@ -1793,6 +1869,14 @@ void QQuickTextEdit::invalidateFontCaches() } } +inline void resetEngine(QQuickTextNodeEngine *engine, const QColor& textColor, const QColor& selectedTextColor, const QColor& selectionColor) +{ + *engine = QQuickTextNodeEngine(); + engine->setTextColor(textColor); + engine->setSelectedTextColor(selectedTextColor); + engine->setSelectionColor(selectionColor); +} + QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) { Q_UNUSED(updatePaintNodeData); @@ -1818,6 +1902,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * while (nodeIterator != d->textNodeMap.end() && !(*nodeIterator)->dirty()) ++nodeIterator; + QQuickTextNodeEngine engine; + QQuickTextNodeEngine frameDecorationsEngine; if (!oldNode || nodeIterator < d->textNodeMap.end()) { @@ -1837,6 +1923,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * // FIXME: the text decorations could probably be handled separately (only updated for affected textFrames) rootNode->resetFrameDecorations(d->createTextNode()); + resetEngine(&frameDecorationsEngine, d->color, d->selectedTextColor, d->selectionColor); QQuickTextNode *node = 0; @@ -1856,11 +1943,12 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * while (!frames.isEmpty()) { QTextFrame *textFrame = frames.takeFirst(); frames.append(textFrame->childFrames()); - rootNode->frameDecorationsNode->m_engine->addFrameDecorations(d->document, textFrame); + frameDecorationsEngine.addFrameDecorations(d->document, textFrame); if (textFrame->lastPosition() < firstDirtyPos || (firstCleanNode && textFrame->firstPosition() >= firstCleanNode->startPos())) continue; node = d->createTextNode(); + resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor); if (textFrame->firstPosition() > textFrame->lastPosition() && textFrame->frameFormat().position() != QTextFrameFormat::InFlow) { @@ -1869,8 +1957,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * ProtectedLayoutAccessor *a = static_cast<ProtectedLayoutAccessor *>(d->document->documentLayout()); QTextCharFormat format = a->formatAccessor(pos); QTextBlock block = textFrame->firstCursorPosition().block(); - node->m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); - node->m_engine->addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document, + engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); + engine.addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document, pos, textFrame->frameFormat().position()); nodeStart = pos; } else { @@ -1888,13 +1976,13 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * if (block.position() < firstDirtyPos) continue; - if (!node->m_engine->hasContents()) { + if (!engine.hasContents()) { nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft(); updateNodeTransform(node, nodeOffset); nodeStart = block.position(); } - node->m_engine->addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); + engine.addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); currentNodeSize += block.length(); if ((it.atEnd()) || (firstCleanNode && block.next().position() >= firstCleanNode->startPos())) // last node that needed replacing or last block of the frame @@ -1903,15 +1991,16 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * QList<int>::const_iterator lowerBound = std::lower_bound(frameBoundaries.constBegin(), frameBoundaries.constEnd(), block.next().position()); if (currentNodeSize > nodeBreakingSize || lowerBound == frameBoundaries.constEnd() || *lowerBound > nodeStart) { currentNodeSize = 0; - d->addCurrentTextNodeToRoot(rootNode, node, nodeIterator, nodeStart); + d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart); node = d->createTextNode(); + resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor); nodeStart = block.next().position(); } } } - d->addCurrentTextNodeToRoot(rootNode, node, nodeIterator, nodeStart); + d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart); } - rootNode->frameDecorationsNode->m_engine->addToSceneGraph(rootNode->frameDecorationsNode, QQuickText::Normal, QColor()); + frameDecorationsEngine.addToSceneGraph(rootNode->frameDecorationsNode, QQuickText::Normal, QColor()); // Now prepend the frame decorations since we want them rendered first, with the text nodes and cursor in front. rootNode->prependChildNode(rootNode->frameDecorationsNode); @@ -2016,6 +2105,19 @@ bool QQuickTextEdit::isInputMethodComposing() const #endif // QT_NO_IM } +QQuickTextEditPrivate::ExtraData::ExtraData() + : padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) +{ +} + void QQuickTextEditPrivate::init() { Q_Q(QQuickTextEdit); @@ -2099,7 +2201,7 @@ void QQuickTextEdit::markDirtyNodesForRange(int start, int end, int charDelta) } // mark the affected nodes as dirty - while (it != d->textNodeMap.constEnd()) { + while (it != d->textNodeMap.end()) { if ((*it)->startPos() <= end) (*it)->setDirty(); else if (charDelta) @@ -2225,7 +2327,7 @@ void QQuickTextEdit::updateSize() return; } - qreal naturalWidth = d->implicitWidth; + qreal naturalWidth = d->implicitWidth - leftPadding() - rightPadding(); qreal newWidth = d->document->idealWidth(); // ### assumes that if the width is set, the text will fill to edges @@ -2243,13 +2345,13 @@ void QQuickTextEdit::updateSize() const bool wasInLayout = d->inLayout; d->inLayout = true; - setImplicitWidth(naturalWidth); + setImplicitWidth(naturalWidth + leftPadding() + rightPadding()); d->inLayout = wasInLayout; if (d->inLayout) // probably the result of a binding loop, but by letting it return; // get this far we'll get a warning to that effect. } if (d->document->textWidth() != width()) { - d->document->setTextWidth(width()); + d->document->setTextWidth(width() - leftPadding() - rightPadding()); newWidth = d->document->idealWidth(); } //### need to confirm cost of always setting these @@ -2264,12 +2366,12 @@ void QQuickTextEdit::updateSize() // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. if (!widthValid() && !d->requireImplicitWidth) - setImplicitSize(newWidth, newHeight); + setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding()); else - setImplicitHeight(newHeight); + setImplicitHeight(newHeight + topPadding() + bottomPadding()); - d->xoff = qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign())); - d->yoff = QQuickTextUtil::alignedY(d->document->size().height(), height(), d->vAlign); + d->xoff = leftPadding() + qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width() - leftPadding() - rightPadding(), effectiveHAlign())); + d->yoff = topPadding() + QQuickTextUtil::alignedY(d->document->size().height(), height() - topPadding() - bottomPadding(), d->vAlign); setBaselineOffset(fm.ascent() + d->yoff + d->textMargin); QSizeF size(newWidth, newHeight); @@ -2416,16 +2518,19 @@ void QQuickTextEditPrivate::handleFocusEvent(QFocusEvent *event) qGuiApp->inputMethod()->show(); q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)), q, SLOT(q_updateAlignment())); +#endif } else { +#ifndef QT_NO_IM q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)), q, SLOT(q_updateAlignment())); #endif + emit q->editingFinished(); } } -void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QSGTransformNode *root, QQuickTextNode *node, TextNodeIterator &it, int startPos) +void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QQuickTextNodeEngine *engine, QSGTransformNode *root, QQuickTextNode *node, TextNodeIterator &it, int startPos) { - node->m_engine->addToSceneGraph(node, QQuickText::Normal, QColor()); + engine->addToSceneGraph(node, QQuickText::Normal, QColor()); it = textNodeMap.insert(it, new TextNode(startPos, node)); ++it; root->appendChildNode(node); @@ -2436,7 +2541,6 @@ QQuickTextNode *QQuickTextEditPrivate::createTextNode() Q_Q(QQuickTextEdit); QQuickTextNode* node = new QQuickTextNode(q); node->setUseNativeRenderer(renderType == QQuickTextEdit::NativeRendering); - node->initEngine(color, selectedTextColor, selectionColor); return node; } @@ -2588,6 +2692,15 @@ bool QQuickTextEditPrivate::isLinkHoveredConnected() */ /*! + \qmlsignal QtQuick::TextEdit::editingFinished() + \since 5.6 + + This signal is emitted when the text edit loses focus. + + The corresponding handler is \c onEditingFinished. +*/ + +/*! \qmlproperty string QtQuick::TextEdit::hoveredLink \since 5.2 @@ -2680,7 +2793,132 @@ void QQuickTextEdit::append(const QString &text) QString QQuickTextEdit::linkAt(qreal x, qreal y) const { Q_D(const QQuickTextEdit); - return d->control->anchorAt(QPointF(x, y)); + return d->control->anchorAt(QPointF(x + topPadding(), y + leftPadding())); +} + +/*! + \since 5.6 + \qmlproperty real QtQuick::TextEdit::padding + \qmlproperty real QtQuick::TextEdit::topPadding + \qmlproperty real QtQuick::TextEdit::leftPadding + \qmlproperty real QtQuick::TextEdit::bottomPadding + \qmlproperty real QtQuick::TextEdit::rightPadding + + These properties hold the padding around the content. This space is reserved + in addition to the contentWidth and contentHeight. +*/ +qreal QQuickTextEdit::padding() const +{ + Q_D(const QQuickTextEdit); + return d->padding(); +} + +void QQuickTextEdit::setPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + if (qFuzzyCompare(d->padding(), padding)) + return; + + d->extra.value().padding = padding; + updateSize(); + if (isComponentComplete()) { + d->updateType = QQuickTextEditPrivate::UpdatePaintNode; + update(); + } + emit paddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) + emit topPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickTextEdit::resetPadding() +{ + setPadding(0); +} + +qreal QQuickTextEdit::topPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->extra.isAllocated() && d->extra->explicitTopPadding) + return d->extra->topPadding; + return d->padding(); +} + +void QQuickTextEdit::setTopPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + d->setTopPadding(padding); +} + +void QQuickTextEdit::resetTopPadding() +{ + Q_D(QQuickTextEdit); + d->setTopPadding(0, true); +} + +qreal QQuickTextEdit::leftPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->extra.isAllocated() && d->extra->explicitLeftPadding) + return d->extra->leftPadding; + return d->padding(); +} + +void QQuickTextEdit::setLeftPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + d->setLeftPadding(padding); +} + +void QQuickTextEdit::resetLeftPadding() +{ + Q_D(QQuickTextEdit); + d->setLeftPadding(0, true); +} + +qreal QQuickTextEdit::rightPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->extra.isAllocated() && d->extra->explicitRightPadding) + return d->extra->rightPadding; + return d->padding(); +} + +void QQuickTextEdit::setRightPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + d->setRightPadding(padding); +} + +void QQuickTextEdit::resetRightPadding() +{ + Q_D(QQuickTextEdit); + d->setRightPadding(0, true); +} + +qreal QQuickTextEdit::bottomPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->extra.isAllocated() && d->extra->explicitBottomPadding) + return d->extra->bottomPadding; + return d->padding(); +} + +void QQuickTextEdit::setBottomPadding(qreal padding) +{ + Q_D(QQuickTextEdit); + d->setBottomPadding(padding); +} + +void QQuickTextEdit::resetBottomPadding() +{ + Q_D(QQuickTextEdit); + d->setBottomPadding(0, true); } QT_END_NAMESPACE diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index bf6763f772..cfe599c0d3 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -47,12 +47,6 @@ class QTextBlock; class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(VAlignment) - Q_ENUMS(HAlignment) - Q_ENUMS(TextFormat) - Q_ENUMS(WrapMode) - Q_ENUMS(SelectionMode) - Q_ENUMS(RenderType) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) @@ -91,8 +85,13 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged) Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl RESET resetBaseUrl NOTIFY baseUrlChanged) Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) - Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument FINAL REVISION 1) + Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument CONSTANT FINAL REVISION 1) Q_PROPERTY(QString hoveredLink READ hoveredLink NOTIFY linkHovered REVISION 2) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6) public: QQuickTextEdit(QQuickItem *parent=0); @@ -103,18 +102,21 @@ public: AlignHCenter = Qt::AlignHCenter, AlignJustify = Qt::AlignJustify }; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) enum TextFormat { PlainText = Qt::PlainText, RichText = Qt::RichText, AutoText = Qt::AutoText }; + Q_ENUM(TextFormat) enum WrapMode { NoWrap = QTextOption::NoWrap, WordWrap = QTextOption::WordWrap, @@ -122,15 +124,18 @@ public: WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere }; + Q_ENUM(WrapMode) enum SelectionMode { SelectCharacters, SelectWords }; + Q_ENUM(SelectionMode) enum RenderType { QtRendering, NativeRendering }; + Q_ENUM(RenderType) QString text() const; void setText(const QString &); @@ -247,6 +252,26 @@ public: Q_REVISION(3) Q_INVOKABLE QString linkAt(qreal x, qreal y) const; + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + Q_SIGNALS: void textChanged(); void contentSizeChanged(); @@ -283,6 +308,12 @@ Q_SIGNALS: void baseUrlChanged(); void inputMethodHintsChanged(); void renderTypeChanged(); + Q_REVISION(6) void editingFinished(); + Q_REVISION(6) void paddingChanged(); + Q_REVISION(6) void topPaddingChanged(); + Q_REVISION(6) void leftPaddingChanged(); + Q_REVISION(6) void rightPaddingChanged(); + Q_REVISION(6) void bottomPaddingChanged(); public Q_SLOTS: void selectAll(); @@ -321,6 +352,8 @@ private: void invalidateFontCaches(); protected: + QQuickTextEdit(QQuickTextEditPrivate &dd, QQuickItem *parent = 0); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index 0cf0f46532..a763f9e56e 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -47,18 +47,19 @@ #include "qquicktextedit_p.h" #include "qquickimplicitsizeitem_p_p.h" -#include "qquicktextcontrol_p.h" #include <QtQml/qqml.h> #include <QtCore/qlist.h> +#include <private/qlazilyallocated_p.h> QT_BEGIN_NAMESPACE class QTextLayout; class QQuickTextDocumentWithImageResources; class QQuickTextControl; class QQuickTextNode; +class QQuickTextNodeEngine; -class QQuickTextEditPrivate : public QQuickImplicitSizeItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickTextEditPrivate : public QQuickImplicitSizeItemPrivate { public: Q_DECLARE_PUBLIC(QQuickTextEdit) @@ -81,10 +82,26 @@ public: }; typedef QList<Node*>::iterator TextNodeIterator; + struct ExtraData { + ExtraData(); + + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding : 1; + bool explicitLeftPadding : 1; + bool explicitRightPadding : 1; + bool explicitBottomPadding : 1; + }; + QLazilyAllocated<ExtraData> extra; + QQuickTextEditPrivate() : color(QRgb(0xFF000000)), selectionColor(QRgb(0xFF000080)), selectedTextColor(QRgb(0xFFFFFFFF)) - , textMargin(0.0), xoff(0), yoff(0), font(sourceFont), cursorComponent(0), cursorItem(0), document(0), control(0) + , textMargin(0.0), xoff(0), yoff(0) + , font(sourceFont), cursorComponent(0), cursorItem(0), document(0), control(0) , quickDocument(0), lastSelectionStart(0), lastSelectionEnd(0), lineCount(0) , hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop) , format(QQuickTextEdit::PlainText), wrapMode(QQuickTextEdit::NoWrap) @@ -124,13 +141,19 @@ public: void setNativeCursorEnabled(bool) {} void handleFocusEvent(QFocusEvent *event); - void addCurrentTextNodeToRoot(QSGTransformNode *, QQuickTextNode*, TextNodeIterator&, int startPos); + void addCurrentTextNodeToRoot(QQuickTextNodeEngine *, QSGTransformNode *, QQuickTextNode*, TextNodeIterator&, int startPos); QQuickTextNode* createTextNode(); #ifndef QT_NO_IM Qt::InputMethodHints effectiveInputMethodHints() const; #endif + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); + QColor color; QColor selectionColor; QColor selectedTextColor; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 5c67d914a5..c29acf3c83 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -90,6 +90,13 @@ QQuickTextInput::QQuickTextInput(QQuickItem* parent) d->init(); } +QQuickTextInput::QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent) +: QQuickImplicitSizeItem(dd, parent) +{ + Q_D(QQuickTextInput); + d->init(); +} + QQuickTextInput::~QQuickTextInput() { } @@ -222,6 +229,16 @@ QString QQuickTextInputPrivate::realText() const */ /*! + \qmlproperty string QtQuick::TextInput::font.styleName + \since 5.6 + + Sets the style name of the font. + + The style name is case insensitive. If set, the font will be matched against style name instead + of the font properties \l weight, \l bold and \l italic. +*/ + +/*! \qmlproperty bool QtQuick::TextInput::font.bold Sets whether the font weight is bold. @@ -786,8 +803,8 @@ QRectF QQuickTextInput::cursorRectangle() const QTextLine l = d->m_textLayout.lineForTextPosition(c); if (!l.isValid()) return QRectF(); - qreal x = l.cursorToX(c) - d->hscroll; - qreal y = l.y() - d->vscroll; + qreal x = l.cursorToX(c) - d->hscroll + leftPadding(); + qreal y = l.y() - d->vscroll + topPadding(); return QRectF(x, y, 1, l.height()); } @@ -910,189 +927,6 @@ void QQuickTextInput::setAutoScroll(bool b) emit autoScrollChanged(d->autoScroll); } -#ifndef QT_NO_VALIDATOR - -/*! - \qmltype IntValidator - \instantiates QIntValidator - \inqmlmodule QtQuick - \ingroup qtquick-text-utility - \brief Defines a validator for integer values - - The IntValidator type provides a validator for integer values. - - If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to - interpret the number and will accept locale specific digits, group separators, and positive - and negative signs. In addition, IntValidator is always guaranteed to accept a number - formatted according to the "C" locale. -*/ - - -QQuickIntValidator::QQuickIntValidator(QObject *parent) - : QIntValidator(parent) -{ -} - -/*! - \qmlproperty string QtQuick::IntValidator::locale - - This property holds the name of the locale used to interpret the number. - - \sa {QtQml::Qt::locale()}{Qt.locale()} -*/ - -QString QQuickIntValidator::localeName() const -{ - return locale().name(); -} - -void QQuickIntValidator::setLocaleName(const QString &name) -{ - if (locale().name() != name) { - setLocale(QLocale(name)); - emit localeNameChanged(); - } -} - -void QQuickIntValidator::resetLocaleName() -{ - QLocale defaultLocale; - if (locale() != defaultLocale) { - setLocale(defaultLocale); - emit localeNameChanged(); - } -} - -/*! - \qmlproperty int QtQuick::IntValidator::top - - This property holds the validator's highest acceptable value. - By default, this property's value is derived from the highest signed integer available (typically 2147483647). -*/ -/*! - \qmlproperty int QtQuick::IntValidator::bottom - - This property holds the validator's lowest acceptable value. - By default, this property's value is derived from the lowest signed integer available (typically -2147483647). -*/ - -/*! - \qmltype DoubleValidator - \instantiates QDoubleValidator - \inqmlmodule QtQuick - \ingroup qtquick-text-utility - \brief Defines a validator for non-integer numbers - - The DoubleValidator type provides a validator for non-integer numbers. - - Input is accepted if it contains a double that is within the valid range - and is in the correct format. - - Input is accepected but invalid if it contains a double that is outside - the range or is in the wrong format; e.g. with too many digits after the - decimal point or is empty. - - Input is rejected if it is not a double. - - Note: If the valid range consists of just positive doubles (e.g. 0.0 to - 100.0) and input is a negative double then it is rejected. If \l notation - is set to DoubleValidator.StandardNotation, and the input contains more - digits before the decimal point than a double in the valid range may have, - it is also rejected. If \l notation is DoubleValidator.ScientificNotation, - and the input is not in the valid range, it is accecpted but invalid. The - value may yet become valid by changing the exponent. -*/ - -QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent) - : QDoubleValidator(parent) -{ -} - -/*! - \qmlproperty string QtQuick::DoubleValidator::locale - - This property holds the name of the locale used to interpret the number. - - \sa {QtQml::Qt::locale()}{Qt.locale()} -*/ - -QString QQuickDoubleValidator::localeName() const -{ - return locale().name(); -} - -void QQuickDoubleValidator::setLocaleName(const QString &name) -{ - if (locale().name() != name) { - setLocale(QLocale(name)); - emit localeNameChanged(); - } -} - -void QQuickDoubleValidator::resetLocaleName() -{ - QLocale defaultLocale; - if (locale() != defaultLocale) { - setLocale(defaultLocale); - emit localeNameChanged(); - } -} - -#endif // QT_NO_VALIDATOR - -/*! - \qmlproperty real QtQuick::DoubleValidator::top - - This property holds the validator's maximum acceptable value. - By default, this property contains a value of infinity. -*/ -/*! - \qmlproperty real QtQuick::DoubleValidator::bottom - - This property holds the validator's minimum acceptable value. - By default, this property contains a value of -infinity. -*/ -/*! - \qmlproperty int QtQuick::DoubleValidator::decimals - - This property holds the validator's maximum number of digits after the decimal point. - By default, this property contains a value of 1000. -*/ -/*! - \qmlproperty enumeration QtQuick::DoubleValidator::notation - This property holds the notation of how a string can describe a number. - - The possible values for this property are: - - \list - \li DoubleValidator.StandardNotation - \li DoubleValidator.ScientificNotation (default) - \endlist - - If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2). -*/ - -/*! - \qmltype RegExpValidator - \instantiates QRegExpValidator - \inqmlmodule QtQuick - \ingroup qtquick-text-utility - \brief Provides a string validator - - The RegExpValidator type provides a validator, which counts as valid any string which - matches a specified regular expression. -*/ -/*! - \qmlproperty regExp QtQuick::RegExpValidator::regExp - - This property holds the regular expression used for validation. - - Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression - matching "a". - - By default, this property contains a regular expression with the pattern .* that matches any string. -*/ - /*! \qmlproperty Validator QtQuick::TextInput::validator @@ -1489,8 +1323,9 @@ void QQuickTextInput::positionAt(QQmlV4Function *args) const int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const { - x += hscroll; - y += vscroll; + Q_Q(const QQuickTextInput); + x += hscroll - q->leftPadding(); + y += vscroll - q->topPadding(); QTextLine line = m_textLayout.lineAt(0); for (int i = 1; i < m_textLayout.lineCount(); ++i) { QTextLine nextLine = m_textLayout.lineAt(i); @@ -1748,7 +1583,7 @@ void QQuickTextInputPrivate::ensureVisible(int position, int preeditCursor, int { Q_Q(QQuickTextInput); QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor); - const qreal width = qMax<qreal>(0, q->width()); + const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding()); qreal cix = 0; qreal widthUsed = 0; if (textLine.isValid()) { @@ -1811,7 +1646,7 @@ void QQuickTextInputPrivate::updateVerticalScroll() #ifndef QT_NO_IM const int preeditLength = m_textLayout.preeditAreaText().length(); #endif - const qreal height = qMax<qreal>(0, q->height()); + const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding()); qreal heightUsed = contentSize.height(); qreal previousScroll = vscroll; @@ -1879,14 +1714,15 @@ void QQuickTextInput::invalidateFontCaches() void QQuickTextInput::ensureActiveFocus() { - Q_D(QQuickTextInput); - bool hadActiveFocus = hasActiveFocus(); forceActiveFocus(); #ifndef QT_NO_IM + Q_D(QQuickTextInput); // re-open input panel on press if already focused if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly) qGuiApp->inputMethod()->show(); +#else + Q_UNUSED(hadActiveFocus); #endif } @@ -1920,13 +1756,13 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData node->deleteContent(); node->setMatrix(QMatrix4x4()); - QPointF offset(0, 0); + QPointF offset(leftPadding(), topPadding()); if (d->autoScroll && d->m_textLayout.lineCount() > 0) { QFontMetricsF fm(d->font); // the y offset is there to keep the baseline constant in case we have script changes in the text. - offset = -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent()); + offset += -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent()); } else { - offset = -QPointF(d->hscroll, d->vscroll); + offset += -QPointF(d->hscroll, d->vscroll); } if (!d->m_textLayout.text().isEmpty() @@ -2672,6 +2508,19 @@ bool QQuickTextInput::isInputMethodComposing() const #endif } +QQuickTextInputPrivate::ExtraData::ExtraData() + : padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) +{ +} + void QQuickTextInputPrivate::init() { Q_Q(QQuickTextInput); @@ -2882,7 +2731,7 @@ qreal QQuickTextInputPrivate::getImplicitWidth() const QTextLine line = layout.createLine(); line.setLineWidth(INT_MAX); - d->implicitWidth = qCeil(line.naturalTextWidth()); + d->implicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding(); layout.endLayout(); } @@ -2890,6 +2739,62 @@ qreal QQuickTextInputPrivate::getImplicitWidth() const return implicitWidth; } +void QQuickTextInputPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->topPadding(); + if (!reset || extra.isAllocated()) { + extra.value().topPadding = value; + extra.value().explicitTopPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateLayout(); + emit q->topPaddingChanged(); + } +} + +void QQuickTextInputPrivate::setLeftPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->leftPadding(); + if (!reset || extra.isAllocated()) { + extra.value().leftPadding = value; + extra.value().explicitLeftPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateLayout(); + emit q->leftPaddingChanged(); + } +} + +void QQuickTextInputPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->rightPadding(); + if (!reset || extra.isAllocated()) { + extra.value().rightPadding = value; + extra.value().explicitRightPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateLayout(); + emit q->rightPaddingChanged(); + } +} + +void QQuickTextInputPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->bottomPadding(); + if (!reset || extra.isAllocated()) { + extra.value().bottomPadding = value; + extra.value().explicitBottomPadding = !reset; + } + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { + updateLayout(); + emit q->bottomPaddingChanged(); + } +} + void QQuickTextInputPrivate::updateLayout() { Q_Q(QQuickTextInput); @@ -2915,12 +2820,12 @@ void QQuickTextInputPrivate::updateLayout() line.setLineWidth(INT_MAX); const bool wasInLayout = inLayout; inLayout = true; - q->setImplicitWidth(qCeil(line.naturalTextWidth())); + q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding()); inLayout = wasInLayout; if (inLayout) // probably the result of a binding loop, but by letting it return; // get this far we'll get a warning to that effect. } - qreal lineWidth = q->widthValid() ? q->width() : INT_MAX; + qreal lineWidth = q->widthValid() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX; qreal height = 0; qreal width = 0; do { @@ -2947,9 +2852,9 @@ void QQuickTextInputPrivate::updateLayout() q->update(); if (!requireImplicitWidth && !q->widthValid()) - q->setImplicitSize(width, height); + q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding()); else - q->setImplicitHeight(height); + q->setImplicitHeight(height + q->topPadding() + q->bottomPadding()); updateBaselineOffset(); @@ -2971,13 +2876,13 @@ void QQuickTextInputPrivate::updateBaselineOffset() QFontMetricsF fm(font); qreal yoff = 0; if (q->heightValid()) { - const qreal surplusHeight = q->height() - contentSize.height(); + const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding(); if (vAlign == QQuickTextInput::AlignBottom) yoff = surplusHeight; else if (vAlign == QQuickTextInput::AlignVCenter) yoff = surplusHeight/2; } - q->setBaselineOffset(fm.ascent() + yoff); + q->setBaselineOffset(fm.ascent() + yoff + q->topPadding()); } #ifndef QT_NO_CLIPBOARD @@ -3345,7 +3250,7 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) m_preeditCursor = event->preeditString().length(); hasImState = !event->preeditString().isEmpty(); bool cursorVisible = true; - QList<QTextLayout::FormatRange> formats; + QVector<QTextLayout::FormatRange> formats; for (int i = 0; i < event->attributes().size(); ++i) { const QInputMethodEvent::Attribute &a = event->attributes().at(i); if (a.type == QInputMethodEvent::Cursor) { @@ -3364,7 +3269,7 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) } } } - m_textLayout.setAdditionalFormats(formats); + m_textLayout.setFormats(formats); updateDisplayText(/*force*/ true); if ((cursorPositionChanged && !emitCursorPositionChanged()) @@ -4273,6 +4178,21 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) return; } + if (m_blinkPeriod > 0) { + if (m_blinkTimer) + q->killTimer(m_blinkTimer); + + m_blinkTimer = q->startTimer(m_blinkPeriod / 2); + + if (m_blinkStatus == 0) { + m_blinkStatus = 1; + + updateType = UpdatePaintNode; + q->polish(); + q->update(); + } + } + if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing && !m_readOnly @@ -4508,5 +4428,126 @@ void QQuickTextInput::ensureVisible(int position) updateCursorRectangle(false); } +/*! + \since 5.6 + \qmlproperty real QtQuick::TextInput::padding + \qmlproperty real QtQuick::TextInput::topPadding + \qmlproperty real QtQuick::TextInput::leftPadding + \qmlproperty real QtQuick::TextInput::bottomPadding + \qmlproperty real QtQuick::TextInput::rightPadding + + These properties hold the padding around the content. This space is reserved + in addition to the contentWidth and contentHeight. +*/ +qreal QQuickTextInput::padding() const +{ + Q_D(const QQuickTextInput); + return d->padding(); +} + +void QQuickTextInput::setPadding(qreal padding) +{ + Q_D(QQuickTextInput); + if (qFuzzyCompare(d->padding(), padding)) + return; + + d->extra.value().padding = padding; + d->updateLayout(); + emit paddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) + emit topPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickTextInput::resetPadding() +{ + setPadding(0); +} + +qreal QQuickTextInput::topPadding() const +{ + Q_D(const QQuickTextInput); + if (d->extra.isAllocated() && d->extra->explicitTopPadding) + return d->extra->topPadding; + return d->padding(); +} + +void QQuickTextInput::setTopPadding(qreal padding) +{ + Q_D(QQuickTextInput); + d->setTopPadding(padding); +} + +void QQuickTextInput::resetTopPadding() +{ + Q_D(QQuickTextInput); + d->setTopPadding(0, true); +} + +qreal QQuickTextInput::leftPadding() const +{ + Q_D(const QQuickTextInput); + if (d->extra.isAllocated() && d->extra->explicitLeftPadding) + return d->extra->leftPadding; + return d->padding(); +} + +void QQuickTextInput::setLeftPadding(qreal padding) +{ + Q_D(QQuickTextInput); + d->setLeftPadding(padding); +} + +void QQuickTextInput::resetLeftPadding() +{ + Q_D(QQuickTextInput); + d->setLeftPadding(0, true); +} + +qreal QQuickTextInput::rightPadding() const +{ + Q_D(const QQuickTextInput); + if (d->extra.isAllocated() && d->extra->explicitRightPadding) + return d->extra->rightPadding; + return d->padding(); +} + +void QQuickTextInput::setRightPadding(qreal padding) +{ + Q_D(QQuickTextInput); + d->setRightPadding(padding); +} + +void QQuickTextInput::resetRightPadding() +{ + Q_D(QQuickTextInput); + d->setRightPadding(0, true); +} + +qreal QQuickTextInput::bottomPadding() const +{ + Q_D(const QQuickTextInput); + if (d->extra.isAllocated() && d->extra->explicitBottomPadding) + return d->extra->bottomPadding; + return d->padding(); +} + +void QQuickTextInput::setBottomPadding(qreal padding) +{ + Q_D(QQuickTextInput); + d->setBottomPadding(padding); +} + +void QQuickTextInput::resetBottomPadding() +{ + Q_D(QQuickTextInput); + d->setBottomPadding(0, true); +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 3bcbe0fa25..b91149f5f3 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -45,13 +45,6 @@ class QValidator; class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem { Q_OBJECT - Q_ENUMS(HAlignment) - Q_ENUMS(VAlignment) - Q_ENUMS(WrapMode) - Q_ENUMS(EchoMode) - Q_ENUMS(SelectionMode) - Q_ENUMS(CursorPosition) - Q_ENUMS(RenderType) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(int length READ length NOTIFY textChanged) @@ -96,6 +89,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem Q_PROPERTY(qreal contentHeight READ contentHeight NOTIFY contentSizeChanged) Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) + Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged REVISION 6) + Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged REVISION 6) + Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged REVISION 6) + Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6) + Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6) + public: QQuickTextInput(QQuickItem * parent=0); ~QQuickTextInput(); @@ -108,18 +107,21 @@ public: Password, PasswordEchoOnEdit }; + Q_ENUM(EchoMode) enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter }; + Q_ENUM(HAlignment) enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; + Q_ENUM(VAlignment) enum WrapMode { NoWrap = QTextOption::NoWrap, @@ -128,20 +130,24 @@ public: WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere }; + Q_ENUM(WrapMode) enum SelectionMode { SelectCharacters, SelectWords }; + Q_ENUM(SelectionMode) enum CursorPosition { CursorBetweenCharacters, CursorOnCharacter }; + Q_ENUM(CursorPosition) enum RenderType { QtRendering, NativeRendering }; + Q_ENUM(RenderType) //Auxilliary functions needed to control the TextInput from QML Q_INVOKABLE void positionAt(QQmlV4Function *args) const; @@ -260,6 +266,26 @@ public: qreal contentWidth() const; qreal contentHeight() const; + qreal padding() const; + void setPadding(qreal padding); + void resetPadding(); + + qreal topPadding() const; + void setTopPadding(qreal padding); + void resetTopPadding(); + + qreal leftPadding() const; + void setLeftPadding(qreal padding); + void resetLeftPadding(); + + qreal rightPadding() const; + void setRightPadding(qreal padding); + void resetRightPadding(); + + qreal bottomPadding() const; + void setBottomPadding(qreal padding); + void resetBottomPadding(); + Q_SIGNALS: void textChanged(); void cursorPositionChanged(); @@ -300,12 +326,19 @@ Q_SIGNALS: void contentSizeChanged(); void inputMethodHintsChanged(); void renderTypeChanged(); + Q_REVISION(6) void paddingChanged(); + Q_REVISION(6) void topPaddingChanged(); + Q_REVISION(6) void leftPaddingChanged(); + Q_REVISION(6) void rightPaddingChanged(); + Q_REVISION(6) void bottomPaddingChanged(); private: void invalidateFontCaches(); void ensureActiveFocus(); protected: + QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent = 0); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; @@ -360,46 +393,8 @@ private: Q_DECLARE_PRIVATE(QQuickTextInput) }; -#ifndef QT_NO_VALIDATOR -class Q_AUTOTEST_EXPORT QQuickIntValidator : public QIntValidator -{ - Q_OBJECT - Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged) -public: - QQuickIntValidator(QObject *parent = 0); - - QString localeName() const; - void setLocaleName(const QString &name); - void resetLocaleName(); - -Q_SIGNALS: - void localeNameChanged(); -}; - -class Q_AUTOTEST_EXPORT QQuickDoubleValidator : public QDoubleValidator -{ - Q_OBJECT - Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged) -public: - QQuickDoubleValidator(QObject *parent = 0); - - QString localeName() const; - void setLocaleName(const QString &name); - void resetLocaleName(); - -Q_SIGNALS: - void localeNameChanged(); -}; -#endif - QT_END_NAMESPACE QML_DECLARE_TYPE(QQuickTextInput) -#ifndef QT_NO_VALIDATOR -QML_DECLARE_TYPE(QValidator) -QML_DECLARE_TYPE(QQuickIntValidator) -QML_DECLARE_TYPE(QQuickDoubleValidator) -QML_DECLARE_TYPE(QRegExpValidator) -#endif #endif // QQUICKTEXTINPUT_P_H diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 3038573bb3..cf0a6f5273 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -47,6 +47,7 @@ #include <QtGui/qpalette.h> #include <QtGui/qtextlayout.h> #include <QtGui/qstylehints.h> +#include <private/qlazilyallocated_p.h> #include "qplatformdefs.h" @@ -64,13 +65,28 @@ QT_BEGIN_NAMESPACE class QQuickTextNode; -class Q_AUTOTEST_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate { public: Q_DECLARE_PUBLIC(QQuickTextInput) typedef QQuickTextInput Public; + struct ExtraData { + ExtraData(); + + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding : 1; + bool explicitLeftPadding : 1; + bool explicitRightPadding : 1; + bool explicitBottomPadding : 1; + }; + QLazilyAllocated<ExtraData> extra; + QQuickTextInputPrivate() : hscroll(0) , vscroll(0) @@ -420,6 +436,12 @@ public: qreal getImplicitWidth() const Q_DECL_OVERRIDE; + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } + void setTopPadding(qreal value, bool reset = false); + void setLeftPadding(qreal value, bool reset = false); + void setRightPadding(qreal value, bool reset = false); + void setBottomPadding(qreal value, bool reset = false); + private: void removeSelectedText(); void internalSetText(const QString &txt, int pos = -1, bool edited = true); diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp index 010a443d18..d40dedd798 100644 --- a/src/quick/items/qquicktextnode.cpp +++ b/src/quick/items/qquicktextnode.cpp @@ -186,17 +186,6 @@ void QQuickTextNode::clearCursor() m_cursorNode = 0; } -void QQuickTextNode::initEngine(const QColor& textColor, const QColor& selectedTextColor, const QColor& selectionColor, const QColor& anchorColor, const QPointF &position) -{ - m_engine.reset(new QQuickTextNodeEngine); - m_engine->m_hasContents = false; - m_engine->setTextColor(textColor); - m_engine->setSelectedTextColor(selectedTextColor); - m_engine->setSelectionColor(selectionColor); - m_engine->setAnchorColor(anchorColor); - m_engine->setPosition(position); -} - void QQuickTextNode::addRectangleNode(const QRectF &rect, const QColor &color) { QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext(); @@ -224,7 +213,12 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex const QColor &selectionColor, const QColor &selectedTextColor, int selectionStart, int selectionEnd) { - initEngine(textColor, selectedTextColor, selectionColor, anchorColor); + QQuickTextNodeEngine engine; + engine.setTextColor(textColor); + engine.setSelectedTextColor(selectedTextColor); + engine.setSelectionColor(selectionColor); + engine.setAnchorColor(anchorColor); + engine.setPosition(position); QList<QTextFrame *> frames; frames.append(textDocument->rootFrame()); @@ -232,7 +226,7 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex QTextFrame *textFrame = frames.takeFirst(); frames.append(textFrame->childFrames()); - m_engine->addFrameDecorations(textDocument, textFrame); + engine.addFrameDecorations(textDocument, textFrame); if (textFrame->firstPosition() > textFrame->lastPosition() && textFrame->frameFormat().position() != QTextFrameFormat::InFlow) { @@ -242,23 +236,23 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex QRectF rect = a->frameBoundingRect(textFrame); QTextBlock block = textFrame->firstCursorPosition().block(); - m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); - m_engine->addTextObject(rect.topLeft(), format, QQuickTextNodeEngine::Unselected, textDocument, + engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); + engine.addTextObject(rect.topLeft(), format, QQuickTextNodeEngine::Unselected, textDocument, pos, textFrame->frameFormat().position()); } else { QTextFrame::iterator it = textFrame->begin(); while (!it.atEnd()) { - Q_ASSERT(!m_engine->currentLine().isValid()); + Q_ASSERT(!engine.currentLine().isValid()); QTextBlock block = it.currentBlock(); - m_engine->addTextBlock(textDocument, block, position, textColor, anchorColor, selectionStart, selectionEnd); + engine.addTextBlock(textDocument, block, position, textColor, anchorColor, selectionStart, selectionEnd); ++it; } } } - m_engine->addToSceneGraph(this, style, styleColor); + engine.addToSceneGraph(this, style, styleColor); } void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLayout, const QColor &color, @@ -268,7 +262,12 @@ void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLay int selectionStart, int selectionEnd, int lineStart, int lineCount) { - initEngine(color, selectedTextColor, selectionColor, anchorColor, position); + QQuickTextNodeEngine engine; + engine.setTextColor(color); + engine.setSelectedTextColor(selectedTextColor); + engine.setSelectionColor(selectionColor); + engine.setAnchorColor(anchorColor); + engine.setPosition(position); #ifndef QT_NO_IM int preeditLength = textLayout->preeditAreaText().length(); @@ -276,7 +275,7 @@ void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLay #endif QVarLengthArray<QTextLayout::FormatRange> colorChanges; - m_engine->mergeFormats(textLayout, &colorChanges); + engine.mergeFormats(textLayout, &colorChanges); lineCount = lineCount >= 0 ? qMin(lineStart + lineCount, textLayout->lineCount()) @@ -297,11 +296,11 @@ void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLay } #endif - m_engine->setCurrentLine(line); - m_engine->addGlyphsForRanges(colorChanges, start, end, selectionStart, selectionEnd); + engine.setCurrentLine(line); + engine.addGlyphsForRanges(colorChanges, start, end, selectionStart, selectionEnd); } - m_engine->addToSceneGraph(this, style, styleColor); + engine.addToSceneGraph(this, style, styleColor); } void QQuickTextNode::deleteContent() diff --git a/src/quick/items/qquicktextnode_p.h b/src/quick/items/qquicktextnode_p.h index c7b9804ea6..31cc23bf2a 100644 --- a/src/quick/items/qquicktextnode_p.h +++ b/src/quick/items/qquicktextnode_p.h @@ -101,14 +101,10 @@ public: void setUseNativeRenderer(bool on) { m_useNativeRenderer = on; } private: - void initEngine(const QColor &textColor, const QColor &selectedTextColor, const QColor &selectionColor, const QColor& anchorColor = QColor() - , const QPointF &position = QPointF()); - QSGRectangleNode *m_cursorNode; QList<QSGTexture *> m_textures; QQuickItem *m_ownerElement; bool m_useNativeRenderer; - QScopedPointer<QQuickTextNodeEngine> m_engine; friend class QQuickTextEdit; friend class QQuickTextEditPrivate; diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index efe79b382e..2b7f94d8bf 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -882,7 +882,7 @@ void QQuickTextNodeEngine::mergeFormats(QTextLayout *textLayout, QVarLengthArray if (textLayout == 0) return; - QList<QTextLayout::FormatRange> additionalFormats = textLayout->additionalFormats(); + QVector<QTextLayout::FormatRange> additionalFormats = textLayout->formats(); for (int i=0; i<additionalFormats.size(); ++i) { QTextLayout::FormatRange additionalFormat = additionalFormats.at(i); if (additionalFormat.format.hasProperty(QTextFormat::ForegroundBrush) diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h index 2f6cacf601..f9ebe43183 100644 --- a/src/quick/items/qquicktextnodeengine_p.h +++ b/src/quick/items/qquicktextnodeengine_p.h @@ -231,8 +231,6 @@ private: QList<TextDecoration> m_lines; QVector<BinaryTreeNode> m_processedNodes; - QList<QPair<QRectF, QImage> > m_images; - bool m_hasSelection : 1; bool m_hasContents : 1; friend class QQuickTextNode; diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 5b5413a4ba..0b3cfa17b5 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -38,8 +38,9 @@ #include "qquickitem_p.h" #include "qquickitemchangelistener_p.h" +#include <private/qqmldebugconnector_p.h> #include <private/qquickprofiler_p.h> -#include <private/qqmlinspectorservice_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include <private/qqmlmemoryprofiler_p.h> #include <QtQml/qqmlengine.h> @@ -86,8 +87,9 @@ void QQuickViewPrivate::init(QQmlEngine* e) rootItemMarker.set(v4, v); } - if (QQmlDebugService::isDebuggingEnabled()) - QQmlInspectorService::instance()->addView(q); + QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>(); + if (service) + service->addView(q); } QQuickViewPrivate::QQuickViewPrivate() @@ -97,8 +99,9 @@ QQuickViewPrivate::QQuickViewPrivate() QQuickViewPrivate::~QQuickViewPrivate() { - if (QQmlDebugService::isDebuggingEnabled()) - QQmlInspectorService::instance()->removeView(q_func()); + QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>(); + if (service) + service->removeView(q_func()); } void QQuickViewPrivate::execute() @@ -345,6 +348,9 @@ QQuickView::Status QQuickView::status() const if (!d->component) return QQuickView::Null; + if (d->component->status() == QQmlComponent::Ready && !d->root) + return QQuickView::Error; + return QQuickView::Status(d->component->status()); } @@ -364,6 +370,10 @@ QList<QQmlError> QQuickView::errors() const QQmlError error; error.setDescription(QLatin1String("QQuickView: invalid qml engine.")); errs << error; + } else if (d->component->status() == QQmlComponent::Ready && !d->root) { + QQmlError error; + error.setDescription(QLatin1String("QQuickView: invalid root object.")); + errs << error; } return errs; @@ -501,14 +511,15 @@ void QQuickViewPrivate::setRootObject(QObject *obj) if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) { root = sgItem; sgItem->setParentItem(q->QQuickWindow::contentItem()); + } else if (qobject_cast<QWindow *>(obj)) { + qWarning() << "QQuickView does not support using windows as a root item." << endl + << endl + << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << endl; } else { qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl << endl - << "If your example is using QML 2, (such as qmlscene) and the .qml file you" << endl - << "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl - << endl - << "To load files with 'import QtQuick 1.0' or 'import Qt 4.7', use the" << endl - << "QDeclarativeView class in the Qt Quick 1 module." << endl; + << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl + << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl; delete obj; root = 0; } diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h index f094c5a216..80da0ba4f1 100644 --- a/src/quick/items/qquickview.h +++ b/src/quick/items/qquickview.h @@ -53,7 +53,6 @@ class Q_QUICK_EXPORT QQuickView : public QQuickWindow Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true) - Q_ENUMS(ResizeMode Status) public: explicit QQuickView(QWindow *parent = 0); QQuickView(QQmlEngine* engine, QWindow *parent); @@ -68,10 +67,12 @@ public: QQuickItem *rootObject() const; enum ResizeMode { SizeViewToRootObject, SizeRootObjectToView }; + Q_ENUM(ResizeMode) ResizeMode resizeMode() const; void setResizeMode(ResizeMode); enum Status { Null, Ready, Loading, Error }; + Q_ENUM(Status) Status status() const; QList<QQmlError> errors() const; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 5958edf29f..99dbf1d83e 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -64,7 +64,6 @@ #include <QtQuick/private/qquickpixmapcache_p.h> -#include <private/qqmlprofilerservice_p.h> #include <private/qqmlmemoryprofiler_p.h> #include <private/qopenglvertexarrayobject_p.h> @@ -83,8 +82,8 @@ bool QQuickWindowPrivate::defaultAlphaBuffer = false; void QQuickWindowPrivate::updateFocusItemTransform() { - Q_Q(QQuickWindow); #ifndef QT_NO_IM + Q_Q(QQuickWindow); QQuickItem *focus = q->activeFocusItem(); if (focus && QGuiApplication::focusObject() == focus) { QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(focus); @@ -259,8 +258,7 @@ void QQuickWindowPrivate::polishItems() // the user. int recursionSafeguard = INT_MAX; while (!itemsToPolish.isEmpty() && --recursionSafeguard > 0) { - QQuickItem *item = *itemsToPolish.begin(); - itemsToPolish.remove(item); + QQuickItem *item = itemsToPolish.takeLast(); QQuickItemPrivate::get(item)->polishScheduled = false; item->updatePolish(); } @@ -2385,7 +2383,9 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem if (target->childMouseEventFilter(item, targetEvent.data())) { qCDebug(DBG_TOUCH) << " - first chance intercepted on childMouseEventFilter by " << target; QVector<int> touchIds; - for (int i = 0; i < targetEvent->touchPoints().size(); ++i) + const int touchPointCount = targetEvent->touchPoints().size(); + touchIds.reserve(touchPointCount); + for (int i = 0; i < touchPointCount; ++i) touchIds.append(targetEvent->touchPoints().at(i).id()); target->grabTouchPoints(touchIds); if (mouseGrabberItem) { @@ -2729,7 +2729,7 @@ static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d) QQuickItem *before = 0; for (int i=0; i<childItems.size(); ++i) { QQuickItemPrivate *dd = QQuickItemPrivate::get(childItems.at(i)); - // Perform the same check as the in buildOrderNodeList below. + // Perform the same check as the in fetchNextNode below. if (dd->z() < 0 && (dd->explicitVisible || (dd->extra.isAllocated() && dd->extra->effectRefCount))) before = childItems.at(i); else @@ -2738,13 +2738,9 @@ static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d) return Q_UNLIKELY(before) ? QQuickItemPrivate::get(before)->itemNode() : 0; } -static QVector<QSGNode *> buildOrderedNodeList(QQuickItemPrivate *itemPriv) +static QSGNode *fetchNextNode(QQuickItemPrivate *itemPriv, int &ii, bool &returnedPaintNode) { QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems(); - QVector<QSGNode *> desiredNodes; - desiredNodes.reserve(orderedChildren.size() + 1); // + 1 for the paintNode - - int ii = 0; for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) { QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii)); @@ -2752,11 +2748,14 @@ static QVector<QSGNode *> buildOrderedNodeList(QQuickItemPrivate *itemPriv) (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) continue; - desiredNodes.append(childPrivate->itemNode()); + ii++; + return childPrivate->itemNode(); } - if (itemPriv->paintNode) - desiredNodes.append(itemPriv->paintNode); + if (itemPriv->paintNode && !returnedPaintNode) { + returnedPaintNode = true; + return itemPriv->paintNode; + } for (; ii < orderedChildren.count(); ++ii) { QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii)); @@ -2764,10 +2763,11 @@ static QVector<QSGNode *> buildOrderedNodeList(QQuickItemPrivate *itemPriv) (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) continue; - desiredNodes.append(childPrivate->itemNode()); + ii++; + return childPrivate->itemNode(); } - return desiredNodes; + return 0; } void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) @@ -2870,7 +2870,10 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) } if (dirty & QQuickItemPrivate::ChildrenUpdateMask) { - QVector<QSGNode *> desiredNodes = buildOrderedNodeList(itemPriv); + int ii = 0; + bool fetchedPaintNode = false; + QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems(); + int desiredNodesSize = orderedChildren.size() + (itemPriv->paintNode ? 1 : 0); // now start making current state match the promised land of // desiredNodes. in the case of our current state matching desiredNodes @@ -2888,14 +2891,9 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) int added = 0; int removed = 0; int replaced = 0; -#if defined(CHILDRENUPDATE_DEBUG) - // This is slow! Do not do this in a normal/profiling build! - int initialCount = groupNode->childCount(); -#endif - - while (currentNode && desiredNodesProcessed < desiredNodes.size()) { - QSGNode *desiredNode = desiredNodes.at(desiredNodesProcessed); + QSGNode *desiredNode = 0; + while (currentNode && (desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) { // uh oh... reality and our utopic paradise are diverging! // we need to reconcile this... if (currentNode != desiredNode) { @@ -2919,9 +2917,8 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) // if we didn't process as many nodes as in the new list, then we have // more nodes at the end of desiredNodes to append to our list. // this will be the case when adding new nodes, for instance. - if (desiredNodesProcessed < desiredNodes.size()) { - for (int i = desiredNodesProcessed; i < desiredNodes.size(); ++i) { - QSGNode *desiredNode = desiredNodes.at(i); + if (desiredNodesProcessed < desiredNodesSize) { + while ((desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) { if (desiredNode->parent()) desiredNode->parent()->removeChildNode(desiredNode); groupNode->appendChildNode(desiredNode); @@ -2938,10 +2935,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) removed++; } } - -#if defined(CHILDRENUPDATE_DEBUG) - qDebug() << "Done children update for " << itemPriv << "- before:" << initialCount << "after:" << groupNode->childCount() << "added:" << added << "removed:" << removed << "replaced:" << replaced; -#endif } if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) { @@ -3307,12 +3300,7 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const QImage QQuickWindow::grabWindow() { Q_D(QQuickWindow); - if (!isVisible()) { - - if (d->context->openglContext()) { - qWarning("QQuickWindow::grabWindow: scene graph already in use"); - return QImage(); - } + if (!isVisible() && !d->context->openglContext()) { if (!handle() || !size().isValid()) { qWarning("QQuickWindow::grabWindow: window must be created and have a valid size"); @@ -3382,6 +3370,11 @@ QQmlIncubationController *QQuickWindow::incubationController() const will delete the GL texture when the texture object is deleted. \value TextureCanUseAtlas The image can be uploaded into a texture atlas. + + \value TextureIsOpaque The texture will return false for + QSGTexture::hasAlphaChannel() and will not be blended. This flag was added + in Qt 5.6. + */ /*! @@ -3586,12 +3579,21 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const The caller of the function is responsible for deleting the returned texture. The actual GL texture will be deleted when the texture object is deleted. - When \a options contains TextureCanUseAtlas the engine may put the image + When \a options contains TextureCanUseAtlas, the engine may put the image into a texture atlas. Textures in an atlas need to rely on QSGTexture::normalizedTextureSubRect() for their geometry and will not support QSGTexture::Repeat. Other values from CreateTextureOption are ignored. + When \a options contains TextureIsOpaque, the engine will create an RGB + texture which returns false for QSGTexture::hasAlphaChannel(). Opaque + textures will in most cases be faster to render. When this flag is not set, + the texture will have an alpha channel based on the image's format. + + When \a options contains TextureHasMipmaps, the engine will create a + texture which can use mipmap filtering. Mipmapped textures can not be in + an atlas. + The returned texture will be using \c GL_TEXTURE_2D as texture target and \c GL_RGBA as internal format. Reimplement QSGTexture to create textures with different parameters. @@ -3613,14 +3615,13 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const { Q_D(const QQuickWindow); - if (d->context) { - if (options & TextureCanUseAtlas) - return d->context->createTexture(image); - else - return d->context->createTextureNoAtlas(image); - } - else - return 0; + if (!d->context) + return 0; + uint flags = 0; + if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; + if (options & TextureHasMipmaps) flags |= QSGRenderContext::CreateTexture_Mipmap; + if (!(options & TextureIsOpaque)) flags |= QSGRenderContext::CreateTexture_Alpha; + return d->context->createTexture(image, flags); } @@ -4115,6 +4116,7 @@ void QQuickWindow::resetOpenGLState() \value BeforeRenderingStage Before rendering. \value AfterRenderingStage After rendering. \value AfterSwapStage After the frame is swapped. + \value NoStage As soon as possible. This value was added in Qt 5.6. \sa {Scene Graph and Rendering} */ @@ -4140,8 +4142,17 @@ void QQuickWindow::resetOpenGLState() If the rendering is happening on a different thread, then the job will happen on the rendering thread. - \note This function does not trigger rendering; the job - will be stored run until rendering is triggered elsewhere. + If \a stage is \l NoStage, \a job will be run at the earliest opportunity + whenever the render thread is not busy rendering a frame. If there is no + OpenGL context available or the window is not exposed at the time the job is + either posted or handled, it is deleted without executing the run() method. + If a non-threaded renderer is in use, the run() method of the job is executed + synchronously. + The OpenGL context is changed to the renderer context before executing a + \l NoStage job. + + \note This function does not trigger rendering; the jobs targeting any other + stage than NoStage will be stored run until rendering is triggered elsewhere. To force the job to run earlier, call QQuickWindow::update(); \sa beforeRendering(), afterRendering(), beforeSynchronizing(), @@ -4153,16 +4164,22 @@ void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage) Q_D(QQuickWindow); d->renderJobMutex.lock(); - if (stage == BeforeSynchronizingStage) + if (stage == BeforeSynchronizingStage) { d->beforeSynchronizingJobs << job; - else if (stage == AfterSynchronizingStage) + } else if (stage == AfterSynchronizingStage) { d->afterSynchronizingJobs << job; - else if (stage == BeforeRenderingStage) + } else if (stage == BeforeRenderingStage) { d->beforeRenderingJobs << job; - else if (stage == AfterRenderingStage) + } else if (stage == AfterRenderingStage) { d->afterRenderingJobs << job; - else if (stage == AfterSwapStage) + } else if (stage == AfterSwapStage) { d->afterSwapJobs << job; + } else if (stage == NoStage) { + if (isExposed()) + d->windowManager->postJob(this, job); + else + delete job; + } d->renderJobMutex.unlock(); } diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index f7a1956120..d5bf9fba81 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -69,7 +69,8 @@ public: TextureHasAlphaChannel = 0x0001, TextureHasMipmaps = 0x0002, TextureOwnsGLTexture = 0x0004, - TextureCanUseAtlas = 0x0008 + TextureCanUseAtlas = 0x0008, + TextureIsOpaque = 0x0010 }; enum RenderStage { @@ -77,7 +78,8 @@ public: AfterSynchronizingStage, BeforeRenderingStage, AfterRenderingStage, - AfterSwapStage + AfterSwapStage, + NoStage }; Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) @@ -85,7 +87,7 @@ public: enum SceneGraphError { ContextNotAvailable = 1 }; - Q_ENUMS(SceneGraphError) + Q_ENUM(SceneGraphError) QQuickWindow(QWindow *parent = 0); explicit QQuickWindow(QQuickRenderControl *renderControl); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 605a36fb1d..0d33d2398a 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -200,7 +200,7 @@ public: QQuickItem *dirtyItemList; QList<QSGNode *> cleanupNodeList; - QSet<QQuickItem *> itemsToPolish; + QVector<QQuickItem *> itemsToPolish; void updateDirtyNodes(); void cleanupNodes(); diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp index 524ee02952..ecf6865895 100644 --- a/src/quick/qtquick2.cpp +++ b/src/quick/qtquick2.cpp @@ -38,7 +38,8 @@ #include <private/qquickitemsmodule_p.h> #include <private/qquickaccessiblefactory_p.h> -#include <private/qqmlenginedebugservice_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include <private/qqmldebugstatesdelegate_p.h> #include <private/qqmlbinding_p.h> #include <private/qqmlcontext_p.h> @@ -133,7 +134,6 @@ void QQmlQtQuick2DebugStatesDelegate::updateBinding(QQmlContext *context, QQmlContextData::get(context), fileName, line, column); newBinding->setTarget(property); - newBinding->setNotifyOnValueChanged(true); } state->changeBindingInRevertList(object, propertyName, newBinding); @@ -187,11 +187,13 @@ void QQmlQtQuick2Module::defineModule() QAccessible::installFactory(&qQuickAccessibleFactory); #endif - if (QQmlDebugService::isDebuggingEnabled()) { - QQmlEngineDebugService::instance()->setStatesDelegate( - new QQmlQtQuick2DebugStatesDelegate); - QQuickProfiler::initialize(); - } + QQmlEngineDebugService *debugService = QQmlDebugConnector::service<QQmlEngineDebugService>(); + if (debugService) + debugService->setStatesDelegate(new QQmlQtQuick2DebugStatesDelegate); + + QQmlProfilerService *profilerService = QQmlDebugConnector::service<QQmlProfilerService>(); + if (profilerService) + QQuickProfiler::initialize(profilerService); } void QQmlQtQuick2Module::undefineModule() diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 42b9f526d0..8632ea0b52 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -198,9 +198,9 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate void ShaderManager::invalidated() { - qDeleteAll(stockShaders.values()); + qDeleteAll(stockShaders); stockShaders.clear(); - qDeleteAll(rewrittenShaders.values()); + qDeleteAll(rewrittenShaders); rewrittenShaders.clear(); delete blitProgram; blitProgram = 0; @@ -487,6 +487,11 @@ void Updater::visitGeometryNode(Node *n) if (e->batch) renderer->invalidateBatchAndOverlappingRenderOrders(e->batch); } + if (n->dirtyState & QSGNode::DirtyMaterial) { + Element *e = n->element(); + if (e->batch && e->batch->isMaterialCompatible(e) == BatchBreaksOnCompare) + renderer->invalidateBatchAndOverlappingRenderOrders(e->batch); + } } SHADOWNODE_TRAVERSE(n) visitNode(*child); @@ -1081,6 +1086,9 @@ void Renderer::nodeWasRemoved(Node *node) if (e) { e->removed = true; m_elementsToDelete.add(e); + + if (m_renderNodeElements.isEmpty()) + m_useDepthBuffer = context()->openglContext()->format().depthBufferSize() > 0; } } @@ -1213,10 +1221,7 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) if (e->isMaterialBlended != blended) { m_rebuild |= Renderer::FullRebuild; e->isMaterialBlended = blended; - } else if (e->batch) { - if (e->batch->isMaterialCompatible(e) == BatchBreaksOnCompare) - invalidateBatchAndOverlappingRenderOrders(e->batch); - } else { + } else if (!e->batch) { m_rebuild |= Renderer::BuildBatches; } } @@ -2554,8 +2559,15 @@ void Renderer::render() QSGNodeDumper::dump(rootNode()); } - if (Q_UNLIKELY(debug_render() || debug_build())) { + QElapsedTimer timer; + quint64 timeRenderLists = 0; + quint64 timePrepareOpaque = 0; + quint64 timePrepareAlpha = 0; + quint64 timeSorting = 0; + quint64 timeUploadOpaque = 0; + quint64 timeUploadAlpha = 0; + if (Q_UNLIKELY(debug_render() || debug_build())) { QByteArray type("rebuild:"); if (m_rebuild == 0) type += " none"; @@ -2571,6 +2583,7 @@ void Renderer::render() } qDebug() << "Renderer::render()" << this << type; + timer.start(); } if (m_vao) @@ -2597,6 +2610,7 @@ void Renderer::render() } } } + if (Q_UNLIKELY(debug_render())) timeRenderLists = timer.restart(); for (int i=0; i<m_opaqueBatches.size(); ++i) m_opaqueBatches.at(i)->cleanupRemovedElements(); @@ -2609,7 +2623,9 @@ void Renderer::render() if (m_rebuild & BuildBatches) { prepareOpaqueBatches(); + if (Q_UNLIKELY(debug_render())) timePrepareOpaque = timer.restart(); prepareAlphaBatches(); + if (Q_UNLIKELY(debug_render())) timePrepareAlpha = timer.restart(); if (Q_UNLIKELY(debug_build())) { qDebug() << "Opaque Batches:"; @@ -2629,8 +2645,11 @@ void Renderer::render() } } } + } else { + if (Q_UNLIKELY(debug_render())) timePrepareOpaque = timePrepareAlpha = timer.restart(); } + deleteRemovedElements(); if (m_rebuild != 0) { @@ -2646,6 +2665,8 @@ void Renderer::render() m_zRange = 1.0 / (m_nextRenderOrder); } + if (Q_UNLIKELY(debug_render())) timeSorting = timer.restart(); + int largestVBO = 0; #ifdef QSG_SEPARATE_INDEX_BUFFER int largestIBO = 0; @@ -2660,6 +2681,8 @@ void Renderer::render() #endif uploadBatch(b); } + if (Q_UNLIKELY(debug_render())) timeUploadOpaque = timer.restart(); + if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Alpha Batches:"; for (int i=0; i<m_alphaBatches.size(); ++i) { @@ -2670,6 +2693,7 @@ void Renderer::render() largestIBO = qMax(b->ibo.size, largestIBO); #endif } + if (Q_UNLIKELY(debug_render())) timeUploadAlpha = timer.restart(); if (largestVBO * 2 < m_vertexUploadPool.size()) m_vertexUploadPool.resize(largestVBO * 2); @@ -2680,6 +2704,15 @@ void Renderer::render() renderBatches(); + if (Q_UNLIKELY(debug_render())) { + qDebug(" -> times: build: %d, prepare(opaque/alpha): %d/%d, sorting: %d, upload(opaque/alpha): %d/%d, render: %d", + (int) timeRenderLists, + (int) timePrepareOpaque, (int) timePrepareAlpha, + (int) timeSorting, + (int) timeUploadOpaque, (int) timeUploadAlpha, + (int) timer.elapsed()); + } + m_rebuild = 0; m_renderOrderRebuildLower = -1; m_renderOrderRebuildUpper = -1; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 6b494dbaeb..d19fa0e17d 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -100,6 +100,7 @@ template <typename Type, int PageSize> class Allocator { public: Allocator() + : m_freePage(0) { pages.push_back(new AllocatorPage<Type, PageSize>()); } @@ -112,14 +113,21 @@ public: Type *allocate() { AllocatorPage<Type, PageSize> *p = 0; - for (int i=0; i<pages.size(); ++i) { + for (int i = m_freePage; i < pages.size(); i++) { if (pages.at(i)->available > 0) { p = pages.at(i); + m_freePage = i; break; } } + + // we couldn't find a free page from m_freePage to the last page. + // either there is no free pages, or there weren't any in the area we + // scanned: rescanning is expensive, so let's just assume there isn't + // one. when an item is released, we'll reset m_freePage anyway. if (!p) { p = new AllocatorPage<Type, PageSize>(); + m_freePage = pages.count(); pages.push_back(p); } uint pos = p->blocks[PageSize - p->available]; @@ -151,6 +159,9 @@ public: delete page; page = pages.back(); } + + // Reset the free page to force a scan for a new free point. + m_freePage = 0; } void release(Type *t) @@ -172,6 +183,7 @@ public: } QVector<AllocatorPage<Type, PageSize> *> pages; + int m_freePage; }; @@ -500,8 +512,8 @@ public: ShaderManager(QSGRenderContext *ctx) : blitProgram(0), visualizeProgram(0), context(ctx) { } ~ShaderManager() { - qDeleteAll(rewrittenShaders.values()); - qDeleteAll(stockShaders.values()); + qDeleteAll(rewrittenShaders); + qDeleteAll(stockShaders); } public Q_SLOTS: diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 4f5c4efe14..bf97133e97 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -165,7 +165,9 @@ void QSGDistanceFieldGlyphCache::update() Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame); QList<QDistanceField> distanceFields; - for (int i = 0; i < m_pendingGlyphs.size(); ++i) { + const int pendingGlyphsSize = m_pendingGlyphs.size(); + distanceFields.reserve(pendingGlyphsSize); + for (int i = 0; i < pendingGlyphsSize; ++i) { GlyphData &gd = glyphData(m_pendingGlyphs.at(i)); distanceFields.append(QDistanceField(gd.path, m_pendingGlyphs.at(i), diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 418d571ae6..150f8475d8 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -41,7 +41,6 @@ #include <QtQuick/private/qsgdefaultglyphnode_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p_p.h> -#include <QtQuick/private/qsgshareddistancefieldglyphcache_p.h> #include <QtQuick/private/qsgatlastexture_p.h> #include <QtQuick/private/qsgrenderloop_p.h> #include <QtQuick/private/qsgdefaultlayer_p.h> @@ -60,15 +59,10 @@ #include <QtQuick/private/qsgtexture_p.h> #include <QtGui/private/qguiapplication_p.h> #include <QtCore/private/qabstractanimation_p.h> -#include <qpa/qplatformintegration.h> - -#include <qpa/qplatformsharedgraphicscache.h> #include <private/qobject_p.h> #include <qmutex.h> -#include <private/qqmlprofilerservice_p.h> - DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) /* @@ -572,35 +566,7 @@ QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRaw QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font); if (!cache) { - QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); - if (platformIntegration != 0 - && platformIntegration->hasCapability(QPlatformIntegration::SharedGraphicsCache)) { - QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine; - if (!fe->faceId().filename.isEmpty()) { - QByteArray keyName = fe->faceId().filename; - if (font.style() != QFont::StyleNormal) - keyName += QByteArray(" I"); - if (font.weight() != QFont::Normal) - keyName += ' ' + QByteArray::number(font.weight()); - keyName += QByteArray(" DF"); - QPlatformSharedGraphicsCache *sharedGraphicsCache = - platformIntegration->createPlatformSharedGraphicsCache(keyName); - - if (sharedGraphicsCache != 0) { - sharedGraphicsCache->ensureCacheInitialized(keyName, - QPlatformSharedGraphicsCache::OpenGLTexture, - QPlatformSharedGraphicsCache::Alpha8); - - cache = new QSGSharedDistanceFieldGlyphCache(keyName, - sharedGraphicsCache, - m_distanceFieldCacheManager, - openglContext(), - font); - } - } - } - if (!cache) - cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); + cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); m_distanceFieldCacheManager->insertCache(font, cache); } @@ -676,7 +642,7 @@ void QSGRenderContext::invalidate() qDeleteAll(m_texturesToDelete); m_texturesToDelete.clear(); - qDeleteAll(m_textures.values()); + qDeleteAll(m_textures); m_textures.clear(); /* The cleanup of the atlas textures is a bit intriguing. @@ -767,22 +733,26 @@ QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager() will be called with \a image as argument. */ -QSGTexture *QSGRenderContext::createTexture(const QImage &image) const +QSGTexture *QSGRenderContext::createTexture(const QImage &image, uint flags) const { - if (!openglContext()) - return 0; - QSGTexture *t = m_atlasManager->create(image); - if (t) - return t; - return createTextureNoAtlas(image); -} + bool atlas = flags & CreateTexture_Atlas; + bool mipmap = flags & CreateTexture_Mipmap; + bool alpha = flags & CreateTexture_Alpha; -QSGTexture *QSGRenderContext::createTextureNoAtlas(const QImage &image) const -{ - QSGPlainTexture *t = new QSGPlainTexture(); - if (!image.isNull()) - t->setImage(image); - return t; + // The atlas implementation is only supported from the render thread and + // does not support mipmaps. + if (!mipmap && atlas && openglContext() && QThread::currentThread() == openglContext()->thread()) { + QSGTexture *t = m_atlasManager->create(image, alpha); + if (t) + return t; + } + + QSGPlainTexture *texture = new QSGPlainTexture(); + texture->setImage(image); + if (texture->hasAlphaChannel() && !alpha) + texture->setHasAlphaChannel(false); + + return texture; } /*! diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index d1897f20f9..49b6f6e2a0 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -88,6 +88,12 @@ class Q_QUICK_PRIVATE_EXPORT QSGRenderContext : public QObject { Q_OBJECT public: + enum CreateTextureFlags { + CreateTexture_Alpha = 0x1, + CreateTexture_Atlas = 0x2, + CreateTexture_Mipmap = 0x4 + }; + QSGRenderContext(QSGContext *context); ~QSGRenderContext(); @@ -107,8 +113,8 @@ public: virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font); QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window); - virtual QSGTexture *createTexture(const QImage &image) const; - virtual QSGTexture *createTextureNoAtlas(const QImage &image) const; + virtual QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const; + virtual QSGRenderer *createRenderer(); virtual void compile(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0); diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index c84e6628a5..14bc0fad07 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -104,8 +104,11 @@ char const *const *QSGTextMaskShader::attributeNames() const } QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat) - : QSGMaterialShader(*new QSGMaterialShaderPrivate), - m_glyphFormat(glyphFormat) + : QSGMaterialShader(*new QSGMaterialShaderPrivate) + , m_matrix_id(-1) + , m_color_id(-1) + , m_textureScale_id(-1) + , m_glyphFormat(glyphFormat) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/textmask.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/textmask.frag")); @@ -435,7 +438,9 @@ void QSGTextMaskMaterial::populate(const QPointF &p, { Q_ASSERT(m_font.isValid()); QVector<QFixedPoint> fixedPointPositions; - for (int i=0; i<glyphPositions.size(); ++i) + const int glyphPositionsSize = glyphPositions.size(); + fixedPointPositions.reserve(glyphPositionsSize); + for (int i=0; i < glyphPositionsSize; ++i) fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i))); QTextureGlyphCache *cache = glyphCache(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 7e602fc0bd..4630e45ecf 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -200,9 +200,11 @@ void QSGDistanceFieldGlyphNode::updateGeometry() const QVector<QPointF> positions = m_glyphs.positions(); qreal fontPixelSize = m_glyphs.rawFont().pixelSize(); - QVector<QSGGeometry::TexturedPoint2D> vp; + // The template parameters here are assuming that most strings are short, 64 + // characters or less. + QVarLengthArray<QSGGeometry::TexturedPoint2D, 256> vp; vp.reserve(indexes.size() * 4); - QVector<ushort> ip; + QVarLengthArray<ushort, 384> ip; ip.reserve(indexes.size() * 6); qreal maxTexMargin = m_glyph_cache->distanceFieldRadius(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp index 422e31ad96..6f4b85a5b9 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -80,6 +80,11 @@ QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader() : QSGMaterialShader(), m_fontScale(1.0) , m_matrixScale(1.0) + , m_matrix_id(-1) + , m_textureScale_id(-1) + , m_alphaMin_id(-1) + , m_alphaMax_id(-1) + , m_color_id(-1) , m_lastAlphaMin(-1) , m_lastAlphaMax(-1) { @@ -260,6 +265,7 @@ protected: DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader() : QSGDistanceFieldTextMaterialShader() + , m_styleColor_id(-1) { } @@ -330,6 +336,8 @@ protected: DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader() : DistanceFieldStyledTextMaterialShader() + , m_outlineAlphaMax0_id(-1) + , m_outlineAlphaMax1_id(-1) { setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldoutlinetext.frag")); } @@ -411,6 +419,7 @@ protected: DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader() : DistanceFieldStyledTextMaterialShader() + , m_shift_id(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.frag")); @@ -489,6 +498,8 @@ private: QSGHiQSubPixelDistanceFieldTextMaterialShader::QSGHiQSubPixelDistanceFieldTextMaterialShader() : QSGDistanceFieldTextMaterialShader() + , m_fontScale_id(-1) + , m_vecDelta_id(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag")); diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 4d3f34c71c..3059b750f2 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -102,6 +102,22 @@ void QSGRenderLoop::cleanup() s_instance = 0; } +/*! + * Non-threaded render loops immediately run the job if there is a context. + */ +void QSGRenderLoop::postJob(QQuickWindow *window, QRunnable *job) +{ + Q_ASSERT(window); + Q_ASSERT(job); + + if (window->openglContext()) { + window->openglContext()->makeCurrent(window); + job->run(); + } + + delete job; +} + class QSGGuiThreadRenderLoop : public QSGRenderLoop { Q_OBJECT diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index 4293015b96..3336731fda 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -45,6 +45,7 @@ class QQuickWindow; class QSGContext; class QSGRenderContext; class QAnimationDriver; +class QRunnable; class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop : public QObject { @@ -72,6 +73,7 @@ public: virtual QSGRenderContext *createRenderContext(QSGContext *) const = 0; virtual void releaseResources(QQuickWindow *window) = 0; + virtual void postJob(QQuickWindow *window, QRunnable *job); void addWindow(QQuickWindow *win) { m_windows.insert(win); } void removeWindow(QQuickWindow *win) { m_windows.remove(win); } diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp deleted file mode 100644 index f1cc9d1a86..0000000000 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp +++ /dev/null @@ -1,655 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#define EGL_EGLEXT_PROTOTYPES -#define GL_GLEXT_PROTOTYPES -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif - -#include "qsgshareddistancefieldglyphcache_p.h" - -#include <QtCore/qhash.h> -#include <QtCore/qthread.h> -#include <QtCore/qcoreapplication.h> - -#include <qpa/qplatformsharedgraphicscache.h> - -#include <QtQuick/qquickwindow.h> - -// #define QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG - -QT_BEGIN_NAMESPACE - -namespace { - - class QSGInvokeEvent: public QEvent - { - public: - QSGInvokeEvent(QPlatformSharedGraphicsCache *cache, - const QByteArray &cacheId = QByteArray(), - const QVector<quint32> &glyphIds = QVector<quint32>(), - bool inSceneGraphUpdate = false) - : QEvent(User) - , m_cache(cache) - , m_cacheId(cacheId) - , m_glyphIds(glyphIds) - , m_inSceneGraphUpdate(inSceneGraphUpdate) - {} - - bool inSceneGraphUpdate() const { return m_inSceneGraphUpdate; } - QPlatformSharedGraphicsCache *cache() const { return m_cache; } - - virtual void invoke() = 0; - protected: - QPlatformSharedGraphicsCache *m_cache; - QByteArray m_cacheId; - QVector<quint32> m_glyphIds; - bool m_inSceneGraphUpdate; - }; - - class QSGReleaseItemsEvent: public QSGInvokeEvent - { - public: - QSGReleaseItemsEvent(QPlatformSharedGraphicsCache *cache, - const QByteArray &cacheId, - const QVector<quint32> &glyphIds, - bool inSceneGraphUpdate) - : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate) - { - } - - void invoke() - { - m_cache->releaseItems(m_cacheId, m_glyphIds); - } - }; - - class QSGRequestItemsEvent: public QSGInvokeEvent - { - public: - QSGRequestItemsEvent(QPlatformSharedGraphicsCache *cache, - const QByteArray &cacheId, - const QVector<quint32> &glyphIds, - bool inSceneGraphUpdate) - : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate) - { - } - - void invoke() - { - m_cache->requestItems(m_cacheId, m_glyphIds); - } - }; - - class QSGInsertItemsEvent: public QSGInvokeEvent - { - public: - QSGInsertItemsEvent(QPlatformSharedGraphicsCache *cache, - const QByteArray &cacheId, - const QVector<quint32> &glyphIds, - const QVector<QImage> &images, - bool inSceneGraphUpdate) - : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate) - , m_images(images) - { - } - - void invoke() - { - m_cache->insertItems(m_cacheId, m_glyphIds, m_images); - } - - private: - QVector<QImage> m_images; - }; - - class QSGEndRequestBatchEvent: public QSGInvokeEvent - { - public: - QSGEndRequestBatchEvent(QPlatformSharedGraphicsCache *cache) - : QSGInvokeEvent(cache) - { - } - - void invoke() - { - if (m_cache->requestBatchStarted()) - m_cache->endRequestBatch(); - } - }; - - class QSGMainThreadInvoker: public QObject - { - public: - bool event(QEvent *e) - { - if (e->type() == QEvent::User) { - Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); - - QSGInvokeEvent *invokeEvent = static_cast<QSGInvokeEvent *>(e); - if (invokeEvent->inSceneGraphUpdate()) { - QPlatformSharedGraphicsCache *cache = invokeEvent->cache(); - if (!cache->requestBatchStarted()) - cache->beginRequestBatch(); - } - - static_cast<QSGInvokeEvent *>(e)->invoke(); - return true; - } - return QObject::event(e); - } - - static QSGMainThreadInvoker *instance() - { - if (m_invoker == 0) { - m_invoker = new QSGMainThreadInvoker; - m_invoker->moveToThread(QCoreApplication::instance()->thread()); - } - - return m_invoker; - } - - private: - static QSGMainThreadInvoker *m_invoker; - }; - - QSGMainThreadInvoker* QSGMainThreadInvoker::m_invoker = 0; -} - -QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteArray &cacheId, - QPlatformSharedGraphicsCache *sharedGraphicsCache, - QSGDistanceFieldGlyphCacheManager *man, - QOpenGLContext *c, - const QRawFont &font) - : QSGDistanceFieldGlyphCache(man, c, font) - , m_cacheId(cacheId) - , m_sharedGraphicsCache(sharedGraphicsCache) - , m_isInSceneGraphUpdate(false) - , m_hasPostedEvents(false) -{ -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache with id %s created in thread %p", - cacheId.constData(), QThread::currentThreadId()); -#endif - - Q_ASSERT(sizeof(glyph_t) == sizeof(quint32)); - Q_ASSERT(sharedGraphicsCache != 0); - - connect(sharedGraphicsCache, SIGNAL(itemsMissing(QByteArray,QVector<quint32>)), - this, SLOT(reportItemsMissing(QByteArray,QVector<quint32>)), - Qt::DirectConnection); - connect(sharedGraphicsCache, SIGNAL(itemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)), - this, SLOT(reportItemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)), - Qt::DirectConnection); - connect(sharedGraphicsCache, SIGNAL(itemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)), - this, SLOT(reportItemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)), - Qt::DirectConnection); - connect(sharedGraphicsCache, SIGNAL(itemsInvalidated(QByteArray,QVector<quint32>)), - this, SLOT(reportItemsInvalidated(QByteArray,QVector<quint32>)), - Qt::DirectConnection); - - Q_ASSERT(c); - QQuickWindow *window = static_cast<QQuickWindow *>(c->surface()); - Q_ASSERT(window != 0); - - connect(window, SIGNAL(beforeSynchronizing()), this, SLOT(sceneGraphUpdateStarted()), - Qt::DirectConnection); - connect(window, SIGNAL(beforeRendering()), this, SLOT(sceneGraphUpdateDone()), - Qt::DirectConnection); -} - -QSGSharedDistanceFieldGlyphCache::~QSGSharedDistanceFieldGlyphCache() -{ - { - QHash<glyph_t, void *>::const_iterator it = m_bufferForGlyph.constBegin(); - while (it != m_bufferForGlyph.constEnd()) { - m_sharedGraphicsCache->dereferenceBuffer(it.value()); - ++it; - } - } - - { - QHash<quint32, PendingGlyph>::const_iterator it = m_pendingReadyGlyphs.constBegin(); - while (it != m_pendingReadyGlyphs.constEnd()) { - m_sharedGraphicsCache->dereferenceBuffer(it.value().buffer); - ++it; - } - } -} - -void QSGSharedDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs) -{ - typedef QSet<glyph_t>::const_iterator GlyphSetConstIt; - - QMutexLocker locker(&m_pendingGlyphsMutex); - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::requestGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - m_requestedGlyphsThatHaveNotBeenReturned.unite(glyphs); - m_requestedGlyphs.unite(glyphs); - - QVector<quint32> glyphsVector; - glyphsVector.reserve(glyphs.size()); - - for (GlyphSetConstIt it = glyphs.constBegin(), cend = glyphs.constEnd(); it != cend; ++it) { - Q_ASSERT(!m_bufferForGlyph.contains(*it)); - glyphsVector.append(*it); - } - - m_hasPostedEvents = true; - QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(invoker, new QSGRequestItemsEvent(m_sharedGraphicsCache, - m_cacheId, - glyphsVector, - m_isInSceneGraphUpdate)); -} - -void QSGSharedDistanceFieldGlyphCache::waitForGlyphs() -{ - Q_ASSERT(!m_isInSceneGraphUpdate); - if (m_isInSceneGraphUpdate) { - qWarning("QSGSharedDistanceFieldGlyphCache::waitForGlyphs: Called from inside " - "scenegraph update. Will freeze."); - } - - { - QMutexLocker locker(&m_pendingGlyphsMutex); - while (!m_requestedGlyphsThatHaveNotBeenReturned.isEmpty()) - m_pendingGlyphsCondition.wait(&m_pendingGlyphsMutex); - } -} - -void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &glyphs) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::storeGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - int glyphCount = glyphs.size(); - QVector<quint32> glyphIds(glyphCount); - QVector<QImage> images(glyphCount); - for (int i = 0; i < glyphs.size(); ++i) { - const QDistanceField &df = glyphs.at(i); - m_requestedGlyphsThatHaveNotBeenReturned.insert(df.glyph()); - glyphIds[i] = df.glyph(); - // ### TODO: Handle QDistanceField in QPlatformSharedGraphicsCache - images[i] = df.toImage(QImage::Format_Indexed8); - } - - m_hasPostedEvents = true; - QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(invoker, new QSGInsertItemsEvent(m_sharedGraphicsCache, - m_cacheId, - glyphIds, - images, - m_isInSceneGraphUpdate)); - } - - processPendingGlyphs(); -} - -void QSGSharedDistanceFieldGlyphCache::referenceGlyphs(const QSet<glyph_t> &glyphs) -{ - Q_UNUSED(glyphs); - - // Intentionally empty. Not required in this implementation, since the glyphs are reference - // counted outside and releaseGlyphs() will only be called when there are no more references. -} - -void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyphs) -{ - typedef QSet<glyph_t>::const_iterator GlyphSetConstIt; - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::releaseGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - m_requestedGlyphs.subtract(glyphs); - - QVector<quint32> glyphsVector; - glyphsVector.reserve(glyphs.size()); - - for (GlyphSetConstIt glyphsIt = glyphs.constBegin(), cend = glyphs.constEnd(); glyphsIt != cend; ++glyphsIt) { - QHash<glyph_t, void *>::iterator bufferIt = m_bufferForGlyph.find(*glyphsIt); - if (bufferIt != m_bufferForGlyph.end()) { - void *buffer = bufferIt.value(); - removeGlyph(*glyphsIt); - m_bufferForGlyph.erase(bufferIt); - Q_ASSERT(!m_bufferForGlyph.contains(*glyphsIt)); - - if (!m_sharedGraphicsCache->dereferenceBuffer(buffer)) { -#if !defined(QT_NO_DEBUG) - bufferIt = m_bufferForGlyph.begin(); - while (bufferIt != m_bufferForGlyph.end()) { - Q_ASSERT(bufferIt.value() != buffer); - ++bufferIt; - } -#endif - } - } - - glyphsVector.append(*glyphsIt); - } - - m_hasPostedEvents = true; - QSGMainThreadInvoker *mainThreadInvoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(mainThreadInvoker, new QSGReleaseItemsEvent(m_sharedGraphicsCache, - m_cacheId, - glyphsVector, - m_isInSceneGraphUpdate)); -} - -void QSGSharedDistanceFieldGlyphCache::registerOwnerElement(QQuickItem *ownerElement) -{ - Owner &owner = m_registeredOwners[ownerElement]; - if (owner.ref == 0) { - owner.item = ownerElement; - - bool ok = connect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess())); - Q_ASSERT_X(ok, Q_FUNC_INFO, "QML element that owns a glyph node must have triggerPreprocess() slot"); - Q_UNUSED(ok); - } - ++owner.ref; -} - -void QSGSharedDistanceFieldGlyphCache::unregisterOwnerElement(QQuickItem *ownerElement) -{ - QHash<QQuickItem *, Owner>::iterator it = m_registeredOwners.find(ownerElement); - if (it != m_registeredOwners.end() && --it->ref <= 0) { - if (it->item) - disconnect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess())); - m_registeredOwners.erase(it); - } -} - -namespace { - struct TextureContent { - QSize size; - QVector<glyph_t> glyphs; - }; -} - -void QSGSharedDistanceFieldGlyphCache::processPendingGlyphs() -{ - Q_ASSERT(QThread::currentThread() == thread()); - - waitForGlyphs(); - - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_pendingMissingGlyphs.isEmpty() - && m_pendingReadyGlyphs.isEmpty() - && m_pendingInvalidatedGlyphs.isEmpty()) { - return; - } - - { - QVector<glyph_t> pendingMissingGlyphs; - pendingMissingGlyphs.reserve(m_pendingMissingGlyphs.size()); - - QSet<glyph_t>::const_iterator it = m_pendingMissingGlyphs.constBegin(); - while (it != m_pendingMissingGlyphs.constEnd()) { - pendingMissingGlyphs.append(*it); - ++it; - } - - markGlyphsToRender(pendingMissingGlyphs); - } - - { - QVector<glyph_t> filteredPendingInvalidatedGlyphs; - filteredPendingInvalidatedGlyphs.reserve(m_pendingInvalidatedGlyphs.size()); - - QSet<glyph_t>::const_iterator it = m_pendingInvalidatedGlyphs.constBegin(); - while (it != m_pendingInvalidatedGlyphs.constEnd()) { - bool rerequestGlyph = false; - - // The glyph was invalidated right after being posted as ready, we throw away - // the ready glyph and rerequest it to be certain - QHash<quint32, PendingGlyph>::iterator pendingGlyphIt = m_pendingReadyGlyphs.find(*it); - if (pendingGlyphIt != m_pendingReadyGlyphs.end()) { - m_sharedGraphicsCache->dereferenceBuffer(pendingGlyphIt.value().buffer); - pendingGlyphIt = m_pendingReadyGlyphs.erase(pendingGlyphIt); - rerequestGlyph = true; - } - - void *bufferId = m_bufferForGlyph.value(*it, 0); - if (bufferId != 0) { - m_sharedGraphicsCache->dereferenceBuffer(bufferId); - m_bufferForGlyph.remove(*it); - rerequestGlyph = true; - } - - if (rerequestGlyph) - filteredPendingInvalidatedGlyphs.append(*it); - - ++it; - } - - // If this cache is still using the glyphs, reset the texture held by them, and mark them - // to be rendered again since they are still needed. - if (!filteredPendingInvalidatedGlyphs.isEmpty()) { - setGlyphsTexture(filteredPendingInvalidatedGlyphs, Texture()); - markGlyphsToRender(filteredPendingInvalidatedGlyphs); - } - } - - { - QList<GlyphPosition> glyphPositions; - - QHash<void *, TextureContent> textureContentForBuffer; - { - QHash<quint32, PendingGlyph>::iterator it = m_pendingReadyGlyphs.begin(); - while (it != m_pendingReadyGlyphs.end()) { - void *currentGlyphBuffer = m_bufferForGlyph.value(it.key(), 0); - if (currentGlyphBuffer != 0) { - if (!m_sharedGraphicsCache->dereferenceBuffer(currentGlyphBuffer)) { - Q_ASSERT(!textureContentForBuffer.contains(currentGlyphBuffer)); - } - } - - PendingGlyph &pendingGlyph = it.value(); - - // We don't ref or deref the buffer here, since it was already referenced when - // added to the pending ready glyphs - m_bufferForGlyph[it.key()] = pendingGlyph.buffer; - - textureContentForBuffer[pendingGlyph.buffer].size = pendingGlyph.bufferSize; - textureContentForBuffer[pendingGlyph.buffer].glyphs.append(it.key()); - - GlyphPosition glyphPosition; - glyphPosition.glyph = it.key(); - glyphPosition.position = pendingGlyph.position; - - glyphPositions.append(glyphPosition); - - ++it; - } - } - - setGlyphsPosition(glyphPositions); - - { - QHash<void *, TextureContent>::const_iterator it = textureContentForBuffer.constBegin(); - while (it != textureContentForBuffer.constEnd()) { - Texture texture; - texture.textureId = m_sharedGraphicsCache->textureIdForBuffer(it.key()); - texture.size = m_sharedGraphicsCache->sizeOfBuffer(it.key()); - - setGlyphsTexture(it.value().glyphs, texture); - - ++it; - } - } - } - - m_pendingMissingGlyphs.clear(); - m_pendingInvalidatedGlyphs.clear(); - m_pendingReadyGlyphs.clear(); - } -} - -void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions) -{ - bool requestedItemsInList = false; - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsAvailable() called for %s (%d glyphs)", - cacheId.constData(), itemIds.size()); -#endif - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphsThatHaveNotBeenReturned.contains(itemIds.at(i))) { - requestedItemsInList = true; - break; - } - } - } - - if (requestedItemsInList) - reportItemsUpdated(cacheId, bufferId,itemIds, positions); -} - -void QSGSharedDistanceFieldGlyphCache::reportItemsUpdated(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - - Q_ASSERT(itemIds.size() == positions.size()); - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsUpdated() called for %s (%d glyphs)", - cacheId.constData(), itemIds.size()); -#endif - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphs.contains(itemIds.at(i))) { - PendingGlyph &pendingGlyph = m_pendingReadyGlyphs[itemIds.at(i)]; - void *oldBuffer = pendingGlyph.buffer; - - pendingGlyph.buffer = bufferId; - pendingGlyph.position = positions.at(i); - - m_sharedGraphicsCache->referenceBuffer(bufferId); - if (oldBuffer != 0) - m_sharedGraphicsCache->dereferenceBuffer(oldBuffer); - - m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i)); - } - } - } - - m_pendingGlyphsCondition.wakeAll(); - emit glyphsPending(); -} - -void QSGSharedDistanceFieldGlyphCache::reportItemsInvalidated(const QByteArray &cacheId, - const QVector<quint32> &itemIds) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphs.contains(itemIds.at(i))) - m_pendingInvalidatedGlyphs.insert(itemIds.at(i)); - } - } - - emit glyphsPending(); -} - - -void QSGSharedDistanceFieldGlyphCache::reportItemsMissing(const QByteArray &cacheId, - const QVector<quint32> &itemIds) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsMissing() called for %s (%d glyphs)", - cacheId.constData(), itemIds.size()); -#endif - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i))) - m_pendingMissingGlyphs.insert(itemIds.at(i)); - } - } - - m_pendingGlyphsCondition.wakeAll(); - emit glyphsPending(); -} - -void QSGSharedDistanceFieldGlyphCache::sceneGraphUpdateStarted() -{ - m_isInSceneGraphUpdate = true; - m_hasPostedEvents = false; -} - -void QSGSharedDistanceFieldGlyphCache::sceneGraphUpdateDone() -{ - m_isInSceneGraphUpdate = false; - - if (m_hasPostedEvents) { - QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(invoker, new QSGEndRequestBatchEvent(m_sharedGraphicsCache)); - m_hasPostedEvents = false; - } -} - -QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h deleted file mode 100644 index aee77c49c6..0000000000 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h +++ /dev/null @@ -1,124 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSGSHAREDDISTANCEFIELDGLYPHCACHE_H -#define QSGSHAREDDISTANCEFIELDGLYPHCACHE_H - -#include <QtCore/qwaitcondition.h> -#include <private/qsgadaptationlayer_p.h> - -QT_BEGIN_NAMESPACE - -class QPlatformSharedGraphicsCache; -class QSGSharedDistanceFieldGlyphCache : public QObject, public QSGDistanceFieldGlyphCache -{ - Q_OBJECT -public: - explicit QSGSharedDistanceFieldGlyphCache(const QByteArray &cacheId, - QPlatformSharedGraphicsCache *sharedGraphicsCache, - QSGDistanceFieldGlyphCacheManager *man, - QOpenGLContext *c, - const QRawFont &font); - ~QSGSharedDistanceFieldGlyphCache(); - - void registerOwnerElement(QQuickItem *ownerElement); - void unregisterOwnerElement(QQuickItem *ownerElement); - void processPendingGlyphs(); - - void requestGlyphs(const QSet<glyph_t> &glyphs); - void referenceGlyphs(const QSet<glyph_t> &glyphs); - void storeGlyphs(const QList<QDistanceField> &glyphs); - void releaseGlyphs(const QSet<glyph_t> &glyphs); - -Q_SIGNALS: - void glyphsPending(); - -private Q_SLOTS: - void reportItemsMissing(const QByteArray &cacheId, const QVector<quint32> &itemIds); - void reportItemsAvailable(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions); - void reportItemsUpdated(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions); - void reportItemsInvalidated(const QByteArray &cacheId, const QVector<quint32> &itemIds); - - void sceneGraphUpdateStarted(); - void sceneGraphUpdateDone(); - -private: - void waitForGlyphs(); - void saveTexture(GLuint textureId, int width, int height); - - QSet<quint32> m_requestedGlyphsThatHaveNotBeenReturned; - QSet<quint32> m_requestedGlyphs; - QWaitCondition m_pendingGlyphsCondition; - QByteArray m_cacheId; - QPlatformSharedGraphicsCache *m_sharedGraphicsCache; - QMutex m_pendingGlyphsMutex; - - QSet<glyph_t> m_pendingInvalidatedGlyphs; - QSet<glyph_t> m_pendingMissingGlyphs; - - struct PendingGlyph - { - PendingGlyph() : buffer(0) {} - - void *buffer; - QSize bufferSize; - QPoint position; - }; - - struct Owner - { - Owner() : ref(0) {} - Owner(const Owner &o) : item(o.item), ref(o.ref) {} - Owner &operator =(const Owner &o) { item = o.item; ref = o.ref; return *this; } - - QPointer<QQuickItem> item; - int ref; - }; - - QHash<quint32, PendingGlyph> m_pendingReadyGlyphs; - QHash<glyph_t, void *> m_bufferForGlyph; - QHash<QQuickItem *, Owner> m_registeredOwners; - - bool m_isInSceneGraphUpdate; - bool m_hasPostedEvents; -}; - -QT_END_NAMESPACE - -#endif // QSGSHAREDDISTANCEFIELDGLYPHCACHE_H diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 2cebbaf484..4b78fefa99 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -54,7 +54,8 @@ #include <private/qquickanimatorcontroller_p.h> #include <private/qquickprofiler_p.h> -#include <private/qqmldebugservice_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> +#include <private/qqmldebugconnector_p.h> #include <private/qquickshadereffectnode_p.h> @@ -147,6 +148,9 @@ const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4); // called. const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5); +// Passed by the window when there is a render job to run +const QEvent::Type WM_PostJob = QEvent::Type(QEvent::User + 6); + template <typename T> T *windowFor(const QList<T> &list, QQuickWindow *window) { for (int i=0; i<list.size(); ++i) { @@ -200,6 +204,14 @@ public: QImage *image; }; +class WMJobEvent : public WMWindowEvent +{ +public: + WMJobEvent(QQuickWindow *c, QRunnable *postedJob) + : WMWindowEvent(c, WM_PostJob), job(postedJob) {} + ~WMJobEvent() { delete job; } + QRunnable *job; +}; class QSGRenderThreadEventQueue : public QQueue<QEvent *> { @@ -345,7 +357,6 @@ bool QSGRenderThread::event(QEvent *e) if (window) { QQuickWindowPrivate::get(window)->fireAboutToStop(); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window removed"; - gl->doneCurrent(); window = 0; } waitCondition.wakeOne(); @@ -396,20 +407,21 @@ bool QSGRenderThread::event(QEvent *e) case WM_Grab: { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_Grab"; WMGrabEvent *ce = static_cast<WMGrabEvent *>(e); - Q_ASSERT(ce->window == window); + Q_ASSERT(ce->window); + Q_ASSERT(ce->window == window || !window); mutex.lock(); - if (window) { - gl->makeCurrent(window); + if (ce->window) { + gl->makeCurrent(ce->window); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- sync scene graph"; - QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); + QQuickWindowPrivate *d = QQuickWindowPrivate::get(ce->window); d->syncSceneGraph(); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering scene graph"; - QQuickWindowPrivate::get(window)->renderSceneGraph(windowSize); + QQuickWindowPrivate::get(ce->window)->renderSceneGraph(ce->window->size()); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result"; - *ce->image = qt_gl_read_framebuffer(windowSize * window->effectiveDevicePixelRatio(), false, false); + *ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), false, false); } qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result"; waitCondition.wakeOne(); @@ -417,6 +429,20 @@ bool QSGRenderThread::event(QEvent *e) return true; } + case WM_PostJob: { + qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_PostJob"; + WMJobEvent *ce = static_cast<WMJobEvent *>(e); + Q_ASSERT(ce->window == window); + if (window) { + gl->makeCurrent(window); + ce->job->run(); + delete ce->job; + ce->job = 0; + qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- job done"; + } + return true; + } + case WM_RequestRepaint: qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_RequestPaint"; // When GUI posts this event, it is followed by a polishAndSync, so we mustn't @@ -666,7 +692,7 @@ void QSGRenderThread::run() qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "run()"; animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0); animatorDriver->install(); - if (QQmlDebugService::isDebuggingEnabled()) + if (QQmlDebugConnector::service<QQmlProfilerService>()) QQuickProfiler::registerAnimationCallback(); while (active) { @@ -993,20 +1019,20 @@ void QSGThreadedRenderLoop::maybeUpdate(Window *w) if (!QCoreApplication::instance()) return; + if (!w || !w->thread->isRunning()) + return; + QThread *current = QThread::currentThread(); if (current != QCoreApplication::instance()->thread() && (current != w->thread || !m_lockedForSync)) { qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()"; return; } - if (!w || !w->thread->isRunning()) { - return; - } qCDebug(QSG_LOG_RENDERLOOP) << "update from item" << w->window; // Call this function from the Gui thread later as startTimer cannot be // called from the render thread. - if (QThread::currentThread() == w->thread) { + if (current == w->thread) { qCDebug(QSG_LOG_RENDERLOOP) << "- on render thread"; w->updateDuringSync = true; return; @@ -1242,6 +1268,18 @@ QImage QSGThreadedRenderLoop::grab(QQuickWindow *window) return result; } +/*! + * Posts a new job event to the render thread. + * Returns true if posting succeeded. + */ +void QSGThreadedRenderLoop::postJob(QQuickWindow *window, QRunnable *job) +{ + Window *w = windowFor(m_windows, window); + if (w && w->thread && w->thread->window) + w->thread->postEvent(new WMJobEvent(window, job)); + else + delete job; +} #include "qsgthreadedrenderloop.moc" diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h index d5ffbf10a3..67df9dcd31 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h +++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h @@ -71,6 +71,7 @@ public: void releaseResources(QQuickWindow *window); bool event(QEvent *); + void postJob(QQuickWindow *window, QRunnable *job); bool interleaveIncubation() const; diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 480ac5e569..84cc2ba135 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -79,7 +79,6 @@ HEADERS += \ $$PWD/qsgdefaultglyphnode_p_p.h \ $$PWD/qsgdefaultimagenode_p.h \ $$PWD/qsgdefaultrectanglenode_p.h \ - $$PWD/qsgshareddistancefieldglyphcache_p.h \ $$PWD/qsgrenderloop_p.h \ $$PWD/qsgthreadedrenderloop_p.h \ $$PWD/qsgwindowsrenderloop_p.h \ @@ -96,7 +95,6 @@ SOURCES += \ $$PWD/qsgdistancefieldglyphnode_p.cpp \ $$PWD/qsgdefaultimagenode.cpp \ $$PWD/qsgdefaultrectanglenode.cpp \ - $$PWD/qsgshareddistancefieldglyphcache.cpp \ $$PWD/qsgrenderloop.cpp \ $$PWD/qsgthreadedrenderloop.cpp \ $$PWD/qsgwindowsrenderloop.cpp \ diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index b862fa6a2b..8c649fb6bd 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -112,13 +112,15 @@ void Manager::invalidate() } } -QSGTexture *Manager::create(const QImage &image) +QSGTexture *Manager::create(const QImage &image, bool hasAlphaChannel) { - QSGTexture *t = 0; + Texture *t = 0; if (image.width() < m_atlas_size_limit && image.height() < m_atlas_size_limit) { if (!m_atlas) m_atlas = new Atlas(m_atlas_size); t = m_atlas->create(image); + if (!hasAlphaChannel && t->hasAlphaChannel()) + t->setHasAlphaChannel(false); } return t; } diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h index 399d5fd669..c0f6ab912d 100644 --- a/src/quick/scenegraph/util/qsgatlastexture_p.h +++ b/src/quick/scenegraph/util/qsgatlastexture_p.h @@ -58,7 +58,7 @@ public: Manager(); ~Manager(); - QSGTexture *create(const QImage &image); + QSGTexture *create(const QImage &image, bool hasAlphaChannel); void invalidate(); private: @@ -114,6 +114,7 @@ public: int textureId() const { return m_atlas->textureId(); } QSize textureSize() const { return atlasSubRectWithoutPadding().size(); } + void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; } bool hasAlphaChannel() const { return m_has_alpha; } bool hasMipmaps() const { return false; } bool isAtlasTexture() const { return true; } diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index c0ddf25765..8622f8edc1 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -150,7 +150,7 @@ QSGAbstractRenderer *QSGEngine::createRenderer() const /*! Creates a texture using the data of \a image - Valid \a options are TextureCanUseAtlas + Valid \a options are TextureCanUseAtlas and TextureIsOpaque. The caller takes ownership of the texture and the texture should only be used with this engine. @@ -160,13 +160,12 @@ QSGAbstractRenderer *QSGEngine::createRenderer() const QSGTexture *QSGEngine::createTextureFromImage(const QImage &image, CreateTextureOptions options) const { Q_D(const QSGEngine); - if (!d->sgRenderContext->isValid()) - return 0; - - if (options & TextureCanUseAtlas) - return d->sgRenderContext->createTexture(image); - else - return d->sgRenderContext->createTextureNoAtlas(image); + if (!d->sgRenderContext->isValid()) + return 0; + uint flags = 0; + if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; + if (!(options & TextureIsOpaque)) flags |= QSGRenderContext::CreateTexture_Alpha; + return d->sgRenderContext->createTexture(image, flags); } /*! diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index 9a74a02aa1..325d3a9ca2 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -52,7 +52,8 @@ public: enum CreateTextureOption { TextureHasAlphaChannel = 0x0001, TextureOwnsGLTexture = 0x0004, - TextureCanUseAtlas = 0x0008 + TextureCanUseAtlas = 0x0008, + TextureIsOpaque = 0x0010 }; Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) diff --git a/src/quick/util/qquickanimation_p.h b/src/quick/util/qquickanimation_p.h index 0f6224a831..c4d5cd20cd 100644 --- a/src/quick/util/qquickanimation_p.h +++ b/src/quick/util/qquickanimation_p.h @@ -57,7 +57,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAbstractAnimation : public QObject, public QQ Q_INTERFACES(QQmlParserStatus) Q_INTERFACES(QQmlPropertyValueSource) - Q_ENUMS(Loops) Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) Q_PROPERTY(bool alwaysRunToEnd READ alwaysRunToEnd WRITE setAlwaysRunToEnd NOTIFY alwaysRunToEndChanged) @@ -75,6 +74,7 @@ public: virtual ~QQuickAbstractAnimation(); enum Loops { Infinite = -2 }; + Q_ENUM(Loops) bool isRunning() const; void setRunning(bool); @@ -367,7 +367,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimation : public QQuickPropertyAnim { Q_OBJECT Q_DECLARE_PRIVATE(QQuickRotationAnimation) - Q_ENUMS(RotationDirection) Q_PROPERTY(qreal from READ from WRITE setFrom) Q_PROPERTY(qreal to READ to WRITE setTo) @@ -384,6 +383,7 @@ public: void setTo(qreal); enum RotationDirection { Numerical, Shortest, Clockwise, Counterclockwise }; + Q_ENUM(RotationDirection) RotationDirection direction() const; void setDirection(RotationDirection direction); diff --git a/src/quick/util/qquickanimation_p_p.h b/src/quick/util/qquickanimation_p_p.h index 4224c6d9ed..b40e198cc1 100644 --- a/src/quick/util/qquickanimation_p_p.h +++ b/src/quick/util/qquickanimation_p_p.h @@ -164,7 +164,7 @@ private: T *m_instance; }; -class QQuickAbstractAnimationPrivate : public QObjectPrivate, public QAnimationJobChangeListener +class Q_QUICK_PRIVATE_EXPORT QQuickAbstractAnimationPrivate : public QObjectPrivate, public QAnimationJobChangeListener { Q_DECLARE_PUBLIC(QQuickAbstractAnimation) public: diff --git a/src/quick/util/qquickanimator_p.h b/src/quick/util/qquickanimator_p.h index 4d3a8e9e4f..7647e582b8 100644 --- a/src/quick/util/qquickanimator_p.h +++ b/src/quick/util/qquickanimator_p.h @@ -136,10 +136,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimator : public QQuickAnimator Q_DECLARE_PRIVATE(QQuickRotationAnimator) Q_PROPERTY(RotationDirection direction READ direction WRITE setDirection NOTIFY directionChanged) - Q_ENUMS(RotationDirection) - public: enum RotationDirection { Numerical, Shortest, Clockwise, Counterclockwise }; + Q_ENUM(RotationDirection) QQuickRotationAnimator(QObject *parent = 0); diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index 2a8e3c281c..0182f8abfb 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -126,9 +126,8 @@ void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, m_controller->startJob(this, m_job); } else if (newState == Stopped) { syncBackCurrentValues(); - if (m_internalState == State_Starting) - m_internalState = State_Stopped; - else if (m_controller) { + m_internalState = State_Stopped; + if (m_controller) { m_controller->stopJob(this, m_job); } } diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h index f8f40b4705..ca70aecb8e 100644 --- a/src/quick/util/qquickanimatorjob_p.h +++ b/src/quick/util/qquickanimatorjob_p.h @@ -151,7 +151,6 @@ protected: int m_duration; - uint m_feedback : 1; uint m_isTransform : 1; uint m_isUniform : 1; uint m_hasBeenRunning : 1; diff --git a/src/quick/util/qquickfontloader_p.h b/src/quick/util/qquickfontloader_p.h index b6ca0b3c94..507d0210ee 100644 --- a/src/quick/util/qquickfontloader_p.h +++ b/src/quick/util/qquickfontloader_p.h @@ -46,7 +46,6 @@ class Q_AUTOTEST_EXPORT QQuickFontLoader : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QQuickFontLoader) - Q_ENUMS(Status) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) @@ -54,6 +53,7 @@ class Q_AUTOTEST_EXPORT QQuickFontLoader : public QObject public: enum Status { Null = 0, Ready, Loading, Error }; + Q_ENUM(Status) QQuickFontLoader(QObject *parent = 0); ~QQuickFontLoader(); diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 6aa7bedc5b..0680a49d6d 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -285,6 +285,7 @@ public: QV4::ScopedValue vbold(scope, obj->get((s = v4->newString(QStringLiteral("bold"))))); QV4::ScopedValue vcap(scope, obj->get((s = v4->newString(QStringLiteral("capitalization"))))); QV4::ScopedValue vfam(scope, obj->get((s = v4->newString(QStringLiteral("family"))))); + QV4::ScopedValue vstyle(scope, obj->get((s = v4->newString(QStringLiteral("styleName"))))); QV4::ScopedValue vital(scope, obj->get((s = v4->newString(QStringLiteral("italic"))))); QV4::ScopedValue vlspac(scope, obj->get((s = v4->newString(QStringLiteral("letterSpacing"))))); QV4::ScopedValue vpixsz(scope, obj->get((s = v4->newString(QStringLiteral("pixelSize"))))); @@ -307,6 +308,10 @@ public: retn.setFamily(vfam->toQString()); if (ok) *ok = true; } + if (vstyle->isString()) { + retn.setStyleName(vstyle->toQString()); + if (ok) *ok = true; + } if (vital->isBoolean()) { retn.setItalic(vital->booleanValue()); if (ok) *ok = true; diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index a231209cd0..89615a2079 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -33,6 +33,9 @@ #include "qquickimageprovider.h" +#include "qquickpixmapcache_p.h" +#include <QtQuick/private/qsgcontext_p.h> + QT_BEGIN_NAMESPACE class QQuickImageProviderPrivate @@ -95,6 +98,23 @@ QImage QQuickTextureFactory::image() const return QImage(); } +/*! + Returns a QQuickTextureFactory holding given the image. + + \since 5.6 + */ + +QQuickTextureFactory *QQuickTextureFactory::textureFactoryForImage(const QImage &image) +{ + if (image.isNull()) + return 0; + QQuickTextureFactory *texture = QSGContext::createTextureFactoryFromImage(image); + if (texture) + return texture; + return new QQuickDefaultTextureFactory(image); +} + + /*! \fn QSGTexture *QQuickTextureFactory::createTexture(QQuickWindow *window) const @@ -118,6 +138,68 @@ QImage QQuickTextureFactory::image() const /*! + \class QQuickImageResponse + \since 5.6 + \brief The QQuickImageResponse class provides an interface for asynchronous image loading in QQuickAsyncImageProvider. + \inmodule QtQuick + + The purpose of an image response is to provide a way for image provider jobs to be executed + in an asynchronous way. + + Responses are deleted via \l deleteLater once the finished() signal has been emitted. + If you are using QRunnable as base for your QQuickImageResponse + ensure automatic deletion is disabled. + + \sa QQuickImageProvider +*/ + +/*! + Constructs the image response +*/ +QQuickImageResponse::QQuickImageResponse() +{ +} + +/*! + Destructs the image response +*/ +QQuickImageResponse::~QQuickImageResponse() +{ +} + +/*! + Returns the error string for the job execution. An empty string means no error. +*/ +QString QQuickImageResponse::errorString() const +{ + return QString(); +} + +/*! + This method is used to communicate that the response is no longer required by the engine. + + It may be reimplemented to cancel a request in the provider side, however, it is not mandatory. +*/ +void QQuickImageResponse::cancel() +{ +} + +/*! + \fn void QQuickImageResponse::finished() + + Signals that the job execution has finished (be it successfully, because an error happened or because it was cancelled). + */ + +/*! + \fn QQuickTextureFactory *QQuickImageResponse::textureFactory() const + + Returns the texture factory for the job. You can use QQuickTextureFactory::textureFactoryForImage + if your provider works with QImage. This method is only called when the error string is not empty and the + engine takes ownership of the returned QQuickTextureFactory. + */ + + +/*! \class QQuickImageProvider \since 5.0 \inmodule QtQuick @@ -213,7 +295,7 @@ QImage QQuickTextureFactory::image() const To force asynchronous image loading, even for image sources that do not have the \c asynchronous property set to \c true, you may pass the - \c QQuickImageProvider::ForceAsynchronousImageLoading flag to the image + \c QQmlImageProviderBase::ForceAsynchronousImageLoading flag to the image provider constructor. This ensures that all image requests for the provider are handled in a separate thread. @@ -223,6 +305,12 @@ QImage QQuickTextureFactory::image() const if \l {Image::}{asynchronous} is set to \c true, the value is ignored and the image is loaded synchronously. + Asynchronous image loading for providers of type other than ImageResponse are + executed on a single thread per engine basis. That means that a slow image provider + will block the loading of any other request. To avoid that we suggest using QQuickAsyncImageProvider + and implement threading on the provider side via a \c QThreadPool or similar. + See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation. + \section2 Image caching @@ -365,5 +453,41 @@ QQuickTextureFactory *QQuickImageProvider::requestTexture(const QString &id, QSi return 0; } +/*! + \class QQuickAsyncImageProvider + \since 5.6 + \inmodule QtQuick + \brief The QQuickAsyncImageProvider class provides an interface for for asynchronous control of QML image requests. + + \sa QQuickImageProvider +*/ +QQuickAsyncImageProvider::QQuickAsyncImageProvider() + : QQuickImageProvider(ImageResponse, ForceAsynchronousImageLoading) + , d(0) // just as a placeholder in case we need it for the future +{ + Q_UNUSED(d); +} + +QQuickAsyncImageProvider::~QQuickAsyncImageProvider() +{ +} + +/*! + \fn QQuickImageResponse *QQuickAsyncImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize) + + Implement this method to return the job that will provide the texture with \a id. + + The \a id is the requested image source, with the "image:" scheme and + provider identifier removed. For example, if the image \l{Image::}{source} + was "image://myprovider/icons/home", the given \a id would be "icons/home". + + The \a requestedSize corresponds to the \l {Image::sourceSize} requested by + an Image item. If \a requestedSize is a valid size, the image + returned should be of that size. + + \note this method may be called by multiple threads, so ensure the + implementation of this method is reentrant. +*/ + QT_END_NAMESPACE diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h index a2b510f606..cc03eb0fa0 100644 --- a/src/quick/util/qquickimageprovider.h +++ b/src/quick/util/qquickimageprovider.h @@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE class QQuickImageProviderPrivate; +class QQuickAsyncImageProviderPrivate; class QSGTexture; class QQuickWindow; @@ -56,6 +57,25 @@ public: virtual QSize textureSize() const = 0; virtual int textureByteCount() const = 0; virtual QImage image() const; + + static QQuickTextureFactory *textureFactoryForImage(const QImage &image); +}; + +class Q_QUICK_EXPORT QQuickImageResponse : public QObject +{ +Q_OBJECT +public: + QQuickImageResponse(); + virtual ~QQuickImageResponse(); + + virtual QQuickTextureFactory *textureFactory() const = 0; + virtual QString errorString() const; + +public Q_SLOTS: + virtual void cancel(); + +Q_SIGNALS: + void finished(); }; class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase @@ -81,6 +101,18 @@ private: QQuickImageProviderPrivate *d; }; +class Q_QUICK_EXPORT QQuickAsyncImageProvider : public QQuickImageProvider +{ +public: + QQuickAsyncImageProvider(); + virtual ~QQuickAsyncImageProvider(); + + virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) = 0; + +private: + QQuickAsyncImageProviderPrivate *d; +}; + QT_END_NAMESPACE #endif // QQUICKIMAGEPROVIDER_H diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index eea313eeb1..5230a3cdea 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -265,7 +265,7 @@ public: : QQuickCurve(parent), _radiusX(0), _radiusY(0), _useLargeArc(false), _direction(Clockwise) {} enum ArcDirection { Clockwise, Counterclockwise }; - Q_ENUMS(ArcDirection) + Q_ENUM(ArcDirection) qreal radiusX() const; void setRadiusX(qreal); diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index ddf2ae2393..6f6e91ec99 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -44,7 +44,6 @@ #include <qpa/qplatformintegration.h> #include <QtQuick/private/qsgtexture_p.h> -#include <QtQuick/private/qsgcontext_p.h> #include <QQuickWindow> #include <QCoreApplication> @@ -67,7 +66,7 @@ #include <private/qquickprofiler_p.h> -#define IMAGEREQUEST_MAX_REQUEST_COUNT 8 +#define IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT 8 #define IMAGEREQUEST_MAX_REDIRECT_RECURSION 16 #define CACHE_EXPIRE_TIME 30 #define CACHE_REMOVAL_FRACTION 4 @@ -115,16 +114,6 @@ QSGTexture *QQuickDefaultTextureFactory::createTexture(QQuickWindow *window) con return t; } -static QQuickTextureFactory *textureFactoryForImage(const QImage &image) -{ - if (image.isNull()) - return 0; - QQuickTextureFactory *texture = QSGContext::createTextureFactoryFromImage(image); - if (texture) - return texture; - return new QQuickDefaultTextureFactory(image); -} - class QQuickPixmapReader; class QQuickPixmapData; class QQuickPixmapReply : public QObject @@ -181,6 +170,7 @@ public: virtual bool event(QEvent *e); private slots: void networkRequestDone(); + void asyncResponseFinished(); private: QQuickPixmapReader *reader; }; @@ -205,8 +195,9 @@ protected: private: friend class QQuickPixmapReaderThreadObject; void processJobs(); - void processJob(QQuickPixmapReply *, const QUrl &, const QSize &, AutoTransform); + void processJob(QQuickPixmapReply *, const QUrl &, const QString &, AutoTransform, QQuickImageProvider::ImageType, QQuickImageProvider *); void networkRequestDone(QNetworkReply *); + void asyncResponseFinished(QQuickImageResponse *); QList<QQuickPixmapReply*> jobs; QList<QQuickPixmapReply*> cancelled; @@ -220,7 +211,8 @@ private: QNetworkAccessManager *networkAccessManager(); QNetworkAccessManager *accessManager; - QHash<QNetworkReply*,QQuickPixmapReply*> replies; + QHash<QNetworkReply*,QQuickPixmapReply*> networkJobs; + QHash<QQuickImageResponse*,QQuickPixmapReply*> asyncResponses; static int replyDownloadProgress; static int replyFinished; @@ -439,8 +431,8 @@ QQuickPixmapReader::~QQuickPixmapReader() delete reply; } jobs.clear(); - QList<QQuickPixmapReply*> activeJobs = replies.values(); - foreach (QQuickPixmapReply *reply, activeJobs) { + QList<QQuickPixmapReply*> activeJobs = networkJobs.values() + asyncResponses.values(); + foreach (QQuickPixmapReply *reply, activeJobs ) { if (reply->loading) { cancelled.append(reply); reply->data = 0; @@ -455,7 +447,7 @@ QQuickPixmapReader::~QQuickPixmapReader() void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) { - QQuickPixmapReply *job = replies.take(reply); + QQuickPixmapReply *job = networkJobs.take(reply); if (job) { job->redirectCount++; @@ -472,7 +464,7 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) QMetaObject::connect(reply, replyDownloadProgress, job, downloadProgress); QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone); - replies.insert(reply, job); + networkJobs.insert(reply, job); return; } } @@ -494,7 +486,7 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) // send completion event to the QQuickPixmapReply mutex.lock(); if (!cancelled.contains(job)) - job->postReply(error, errorString, readSize, textureFactoryForImage(image)); + job->postReply(error, errorString, readSize, QQuickTextureFactory::textureFactoryForImage(image)); mutex.unlock(); } reply->deleteLater(); @@ -503,6 +495,34 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) threadObject->processJobs(); } +void QQuickPixmapReader::asyncResponseFinished(QQuickImageResponse *response) +{ + QQuickPixmapReply *job = asyncResponses.take(response); + + if (job) { + QQuickTextureFactory *t = 0; + QQuickPixmapReply::ReadError error = QQuickPixmapReply::NoError; + QString errorString; + QSize readSize; + if (!response->errorString().isEmpty()) { + error = QQuickPixmapReply::Loading; + errorString = response->errorString(); + } else { + t = response->textureFactory(); + } + mutex.lock(); + if (!cancelled.contains(job)) + job->postReply(error, errorString, t ? t->textureSize() : QSize(), t); + else + delete t; + mutex.unlock(); + } + response->deleteLater(); + + // kick off event loop again incase we have dropped below max request count + threadObject->processJobs(); +} + QQuickPixmapReaderThreadObject::QQuickPixmapReaderThreadObject(QQuickPixmapReader *i) : reader(i) { @@ -529,6 +549,12 @@ void QQuickPixmapReaderThreadObject::networkRequestDone() reader->networkRequestDone(reply); } +void QQuickPixmapReaderThreadObject::asyncResponseFinished() +{ + QQuickImageResponse *response = static_cast<QQuickImageResponse *>(sender()); + reader->asyncResponseFinished(response); +} + void QQuickPixmapReader::processJobs() { QMutexLocker locker(&mutex); @@ -538,16 +564,22 @@ void QQuickPixmapReader::processJobs() return; // Nothing else to do // Clean cancelled jobs - if (cancelled.count()) { + if (!cancelled.isEmpty()) { for (int i = 0; i < cancelled.count(); ++i) { QQuickPixmapReply *job = cancelled.at(i); - QNetworkReply *reply = replies.key(job, 0); + QNetworkReply *reply = networkJobs.key(job, 0); if (reply) { - replies.remove(reply); + networkJobs.remove(reply); if (reply->isRunning()) { // cancel any jobs already started reply->close(); } + } else { + QQuickImageResponse *asyncResponse = asyncResponses.key(job); + if (asyncResponse) { + asyncResponses.remove(asyncResponse); + asyncResponse->cancel(); + } } PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url)); // deleteLater, since not owned by this thread @@ -560,27 +592,34 @@ void QQuickPixmapReader::processJobs() // Find a job we can use bool usableJob = false; for (int i = jobs.count() - 1; !usableJob && i >= 0; i--) { - QQuickPixmapReply *runningJob = jobs[i]; - const QUrl url = runningJob->url; + QQuickPixmapReply *job = jobs[i]; + const QUrl url = job->url; + QString localFile; + QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; + QQuickImageProvider *provider = 0; if (url.scheme() == QLatin1String("image")) { + provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url))); + if (provider) + imageType = provider->imageType(); + usableJob = true; } else { - const QString localFile = QQmlFile::urlToLocalFileOrQrc(url); - usableJob = !localFile.isEmpty() || replies.count() < IMAGEREQUEST_MAX_REQUEST_COUNT; + localFile = QQmlFile::urlToLocalFileOrQrc(url); + usableJob = !localFile.isEmpty() || networkJobs.count() < IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT; } + if (usableJob) { jobs.removeAt(i); - runningJob->loading = true; + job->loading = true; PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url)); - QSize requestSize = runningJob->requestSize; - AutoTransform autoTransform = runningJob->autoTransform; + AutoTransform autoTransform = job->autoTransform; locker.unlock(); - processJob(runningJob, url, requestSize, autoTransform); + processJob(job, url, localFile, autoTransform, imageType, provider); locker.relock(); } } @@ -591,79 +630,97 @@ void QQuickPixmapReader::processJobs() } } -void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, - const QSize &requestSize, AutoTransform autoTransform) +void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile, + AutoTransform autoTransform, QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider) { // fetch if (url.scheme() == QLatin1String("image")) { // Use QQuickImageProvider QSize readSize; - QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; - QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url))); - if (provider) - imageType = provider->imageType(); + switch (imageType) { + case QQuickImageProvider::Invalid: + { + QString errorStr = QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()); + mutex.lock(); + if (!cancelled.contains(runningJob)) + runningJob->postReply(QQuickPixmapReply::Loading, errorStr, readSize, 0); + mutex.unlock(); + break; + } - if (imageType == QQuickImageProvider::Invalid) { - QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::Loading; - QString errorStr = QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()); - QImage image; - mutex.lock(); - if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(image)); - mutex.unlock(); - } else if (imageType == QQuickImageProvider::Image) { - QImage image = provider->requestImage(imageId(url), &readSize, requestSize); - QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; - QString errorStr; - if (image.isNull()) { - errorCode = QQuickPixmapReply::Loading; - errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + case QQuickImageProvider::Image: + { + QImage image = provider->requestImage(imageId(url), &readSize, runningJob->requestSize); + QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; + QString errorStr; + if (image.isNull()) { + errorCode = QQuickPixmapReply::Loading; + errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + } + mutex.lock(); + if (!cancelled.contains(runningJob)) + runningJob->postReply(errorCode, errorStr, readSize, QQuickTextureFactory::textureFactoryForImage(image)); + mutex.unlock(); + break; } - mutex.lock(); - if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(image)); - mutex.unlock(); - } else if (imageType == QQuickImageProvider::Pixmap) { - const QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize); - QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; - QString errorStr; - if (pixmap.isNull()) { - errorCode = QQuickPixmapReply::Loading; - errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + + case QQuickImageProvider::Pixmap: + { + const QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, runningJob->requestSize); + QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; + QString errorStr; + if (pixmap.isNull()) { + errorCode = QQuickPixmapReply::Loading; + errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + } + mutex.lock(); + if (!cancelled.contains(runningJob)) + runningJob->postReply(errorCode, errorStr, readSize, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage())); + mutex.unlock(); + break; } - mutex.lock(); - if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(pixmap.toImage())); - mutex.unlock(); - } else { - QQuickTextureFactory *t = provider->requestTexture(imageId(url), &readSize, requestSize); - QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; - QString errorStr; - if (!t) { - errorCode = QQuickPixmapReply::Loading; - errorStr = QQuickPixmap::tr("Failed to get texture from provider: %1").arg(url.toString()); + + case QQuickImageProvider::Texture: + { + QQuickTextureFactory *t = provider->requestTexture(imageId(url), &readSize, runningJob->requestSize); + QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; + QString errorStr; + if (!t) { + errorCode = QQuickPixmapReply::Loading; + errorStr = QQuickPixmap::tr("Failed to get texture from provider: %1").arg(url.toString()); + } + mutex.lock(); + if (!cancelled.contains(runningJob)) + runningJob->postReply(errorCode, errorStr, readSize, t); + else + delete t; + mutex.unlock(); + break; } - mutex.lock(); - if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, t); - else - delete t; - mutex.unlock(); + case QQuickImageProvider::ImageResponse: + { + QQuickAsyncImageProvider *asyncProvider = static_cast<QQuickAsyncImageProvider*>(provider); + QQuickImageResponse *response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize); + + QObject::connect(response, SIGNAL(finished()), threadObject, SLOT(asyncResponseFinished())); + + asyncResponses.insert(response, runningJob); + break; + } } } else { - QString lf = QQmlFile::urlToLocalFileOrQrc(url); - if (!lf.isEmpty()) { + if (!localFile.isEmpty()) { // Image is local - load/decode immediately QImage image; QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; QString errorStr; - QFile f(lf); + QFile f(localFile); QSize readSize; if (f.open(QIODevice::ReadOnly)) { - if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize, autoTransform)) + if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, autoTransform)) errorCode = QQuickPixmapReply::Loading; } else { errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString()); @@ -671,7 +728,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u } mutex.lock(); if (!cancelled.contains(runningJob)) - runningJob->postReply(errorCode, errorStr, readSize, textureFactoryForImage(image)); + runningJob->postReply(errorCode, errorStr, readSize, QQuickTextureFactory::textureFactoryForImage(image)); mutex.unlock(); } else { // Network resource @@ -682,7 +739,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress); QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone); - replies.insert(reply, runningJob); + networkJobs.insert(reply, runningJob); } } } @@ -775,8 +832,6 @@ inline uint qHash(const QQuickPixmapKey &key) return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.autoTransform * 0x5c5c5c5c); } -class QSGContext; - class QQuickPixmapStore : public QObject { Q_OBJECT @@ -1084,7 +1139,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QImage image = provider->requestImage(imageId(url), &readSize, requestSize); if (!image.isNull()) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(image), readSize, requestSize, autoTransform, UsePluginDefault); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, autoTransform, UsePluginDefault); } } case QQuickImageProvider::Pixmap: @@ -1092,9 +1147,14 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize); if (!pixmap.isNull()) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(pixmap.toImage()), readSize, requestSize, autoTransform, UsePluginDefault); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, autoTransform, UsePluginDefault); } } + case QQuickImageProvider::ImageResponse: + { + // Fall through, ImageResponse providers never get here + Q_ASSERT(imageType != QQuickImageProvider::ImageResponse && "Sync call to ImageResponse provider"); + } } // provider has bad image type, or provider returned null image @@ -1115,7 +1175,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q AutoTransform appliedTransform = autoTransform; if (readImage(url, &f, &image, &errorString, &readSize, requestSize, appliedTransform)) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(image), readSize, requestSize, autoTransform, appliedTransform); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, autoTransform, appliedTransform); } errorString = QQuickPixmap::tr("Invalid image data: %1").arg(url.toString()); @@ -1252,7 +1312,7 @@ void QQuickPixmap::setImage(const QImage &p) clear(); if (!p.isNull()) - d = new QQuickPixmapData(this, textureFactoryForImage(p)); + d = new QQuickPixmapData(this, QQuickTextureFactory::textureFactoryForImage(p)); } void QQuickPixmap::setPixmap(const QQuickPixmap &other) diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp index d9132a9cb2..77ffda474a 100644 --- a/src/quick/util/qquickprofiler.cpp +++ b/src/quick/util/qquickprofiler.cpp @@ -33,8 +33,7 @@ #include "qquickprofiler_p.h" #include <QCoreApplication> -#include <private/qqmldebugservice_p.h> -#include <private/qqmlprofilerservice_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> QT_BEGIN_NAMESPACE @@ -113,18 +112,22 @@ void QQuickProfilerData::toByteArrays(QList<QByteArray> &messages) const qint64 QQuickProfiler::sendMessages(qint64 until, QList<QByteArray> &messages) { QMutexLocker lock(&m_dataMutex); - while (next < m_data.size() && m_data[next].time <= until) { - m_data[next++].toByteArrays(messages); + while (next < m_data.size()) { + if (m_data[next].time <= until) + m_data[next++].toByteArrays(messages); + else + return m_data[next].time; } - return next < m_data.size() ? m_data[next].time : -1; + m_data.clear(); + next = 0; + return -1; } -void QQuickProfiler::initialize() +void QQuickProfiler::initialize(QQmlProfilerService *service) { Q_ASSERT(s_instance == 0); - QQmlProfilerService *service = QQmlProfilerService::instance(); s_instance = new QQuickProfiler(service); - QQmlProfilerService::instance()->addGlobalProfiler(s_instance); + service->addGlobalProfiler(s_instance); } void animationTimerCallback(qint64 delta) @@ -196,17 +199,12 @@ void QQuickProfiler::stopProfilingImpl() { QMutexLocker lock(&m_dataMutex); featuresEnabled = 0; - next = 0; } service->dataReady(this); } void QQuickProfiler::reportDataImpl() { - { - QMutexLocker lock(&m_dataMutex); - next = 0; - } service->dataReady(this); } diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h index aaed4bd60e..6b6e7fa062 100644 --- a/src/quick/util/qquickprofiler_p.h +++ b/src/quick/util/qquickprofiler_p.h @@ -318,7 +318,7 @@ public: return featuresEnabled & (1 << QQuickProfiler::ProfileSceneGraph); } - static void initialize(); + static void initialize(QQmlProfilerService *service); virtual ~QQuickProfiler(); diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index 6c333c6b13..58d78a5d84 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -145,12 +145,12 @@ public: QQmlBoundSignalExpressionPointer reverseExpression; QQmlBoundSignalExpressionPointer rewindExpression; - virtual void execute(Reason) { + virtual void execute() { QQmlPropertyPrivate::setSignalExpression(property, expression); } virtual bool isReversable() { return true; } - virtual void reverse(Reason) { + virtual void reverse() { QQmlPropertyPrivate::setSignalExpression(property, reverseExpression); } @@ -464,10 +464,10 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions() // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString) // so that we can avoid creating then destroying the binding in this case. a.toValue = newBinding->evaluate(); - newBinding->destroy(); + delete newBinding; } else { newBinding->setTarget(prop); - a.toBinding = QQmlAbstractBinding::getPointer(newBinding); + a.toBinding = newBinding; a.deletableToBinding = true; } @@ -558,11 +558,7 @@ void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &val if (entry.name == name) { expressionIterator.remove(); if (state() && state()->isStateActive()) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name)); - if (oldBinding) { - QQmlPropertyPrivate::setBinding(d->property(name), 0); - oldBinding->destroy(); - } + QQmlPropertyPrivate::removeBinding(d->property(name)); d->property(name).write(value); } @@ -624,15 +620,9 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString if (entry.name == name) { entry.expression = expression; if (state() && state()->isStateActive()) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name)); - if (oldBinding) { - QQmlPropertyPrivate::setBinding(d->property(name), 0); - oldBinding->destroy(); - } - QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); newBinding->setTarget(d->property(name)); - QQmlPropertyPrivate::setBinding(d->property(name), newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); } return; } @@ -651,7 +641,7 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this)); newBinding->setTarget(d->property(name)); - QQmlPropertyPrivate::setBinding(d->property(name), newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); } else { QQuickStateAction action; action.restore = restoreEntryValues(); @@ -666,10 +656,10 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString) // so that we can avoid creating then destroying the binding in this case. action.toValue = newBinding->evaluate(); - newBinding->destroy(); + delete newBinding; } else { - newBinding->setTarget(d->property(name)); - action.toBinding = QQmlAbstractBinding::getPointer(newBinding); + newBinding->setTarget(action.property); + action.toBinding = newBinding; action.deletableToBinding = true; state()->addEntryToRevertList(action); @@ -677,7 +667,7 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString if (oldBinding) oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); - QQmlPropertyPrivate::setBinding(action.property, newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); } } } diff --git a/src/quick/util/qquicksmoothedanimation_p.h b/src/quick/util/qquicksmoothedanimation_p.h index 68479aa629..efac9217f5 100644 --- a/src/quick/util/qquicksmoothedanimation_p.h +++ b/src/quick/util/qquicksmoothedanimation_p.h @@ -47,7 +47,6 @@ class Q_AUTOTEST_EXPORT QQuickSmoothedAnimation : public QQuickNumberAnimation { Q_OBJECT Q_DECLARE_PRIVATE(QQuickSmoothedAnimation) - Q_ENUMS(ReversingMode) Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged) Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged) @@ -55,6 +54,7 @@ class Q_AUTOTEST_EXPORT QQuickSmoothedAnimation : public QQuickNumberAnimation public: enum ReversingMode { Eased, Immediate, Sync }; + Q_ENUM(ReversingMode) QQuickSmoothedAnimation(QObject *parent = 0); ~QQuickSmoothedAnimation(); diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp index 98d7a76c7e..be676680a6 100644 --- a/src/quick/util/qquickstate.cpp +++ b/src/quick/util/qquickstate.cpp @@ -78,7 +78,7 @@ QQuickStateActionEvent::~QQuickStateActionEvent() { } -void QQuickStateActionEvent::execute(Reason) +void QQuickStateActionEvent::execute() { } @@ -87,7 +87,7 @@ bool QQuickStateActionEvent::isReversable() return false; } -void QQuickStateActionEvent::reverse(Reason) +void QQuickStateActionEvent::reverse() { } @@ -157,11 +157,6 @@ QQuickState::~QQuickState() Q_D(QQuickState); if (d->group) d->group->removeState(this); - - foreach (const QQuickSimpleAction &action, d->revertList) { - if (action.binding()) - action.binding()->destroy(); - } } /*! @@ -361,8 +356,7 @@ void QQuickState::cancel() void QQuickStateAction::deleteFromBinding() { if (fromBinding) { - QQmlPropertyPrivate::setBinding(property, 0); - fromBinding->destroy(); + QQmlPropertyPrivate::removeBinding(property); fromBinding = 0; } } @@ -413,9 +407,6 @@ bool QQuickState::changeBindingInRevertList(QObject *target, const QString &name while (revertListIterator.hasNext()) { QQuickSimpleAction &simpleAction = revertListIterator.next(); if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) { - if (simpleAction.binding()) - simpleAction.binding()->destroy(); - simpleAction.setBinding(binding); return true; } @@ -435,15 +426,11 @@ bool QQuickState::removeEntryFromRevertList(QObject *target, const QString &name while (revertListIterator.hasNext()) { QQuickSimpleAction &simpleAction = revertListIterator.next(); if (simpleAction.property().object() == target && simpleAction.property().name() == name) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(simpleAction.property()); - if (oldBinding) { - QQmlPropertyPrivate::setBinding(simpleAction.property(), 0); - oldBinding->destroy(); - } + QQmlPropertyPrivate::removeBinding(simpleAction.property()); simpleAction.property().write(simpleAction.value()); if (simpleAction.binding()) - QQmlPropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding()); + QQmlPropertyPrivate::setBinding(simpleAction.binding()); revertListIterator.remove(); return true; @@ -473,15 +460,11 @@ void QQuickState::removeAllEntriesFromRevertList(QObject *target) while (revertListIterator.hasNext()) { QQuickSimpleAction &simpleAction = revertListIterator.next(); if (simpleAction.property().object() == target) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(simpleAction.property()); - if (oldBinding) { - QQmlPropertyPrivate::setBinding(simpleAction.property(), 0); - oldBinding->destroy(); - } + QQmlPropertyPrivate::removeBinding(simpleAction.property()); simpleAction.property().write(simpleAction.value()); if (simpleAction.binding()) - QQmlPropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding()); + QQmlPropertyPrivate::setBinding(simpleAction.binding()); revertListIterator.remove(); } @@ -494,18 +477,15 @@ void QQuickState::addEntriesToRevertList(const QList<QQuickStateAction> &actionL Q_D(QQuickState); if (isStateActive()) { QList<QQuickSimpleAction> simpleActionList; + simpleActionList.reserve(actionList.count()); QListIterator<QQuickStateAction> actionListIterator(actionList); while(actionListIterator.hasNext()) { const QQuickStateAction &action = actionListIterator.next(); QQuickSimpleAction simpleAction(action); action.property.write(action.toValue); - if (!action.toBinding.isNull()) { - QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(simpleAction.property()); - if (oldBinding) - QQmlPropertyPrivate::setBinding(simpleAction.property(), 0); - QQmlPropertyPrivate::setBinding(simpleAction.property(), action.toBinding.data(), QQmlPropertyPrivate::DontRemoveBinding); - } + if (action.toBinding) + QQmlPropertyPrivate::setBinding(action.toBinding.data()); simpleActionList.append(simpleAction); } @@ -619,7 +599,7 @@ void QQuickState::apply(QQuickTransition *trans, QQuickState *revert) for (int jj = 0; jj < d->revertList.count(); ++jj) { if (d->revertList.at(jj).property() == action.property) { found = true; - if (d->revertList.at(jj).binding() != action.fromBinding) { + if (d->revertList.at(jj).binding() != action.fromBinding.data()) { action.deleteFromBinding(); } break; @@ -663,16 +643,13 @@ void QQuickState::apply(QQuickTransition *trans, QQuickState *revert) } if (!found) { QVariant cur = d->revertList.at(ii).property().read(); - QQmlAbstractBinding *delBinding = - QQmlPropertyPrivate::setBinding(d->revertList.at(ii).property(), 0); - if (delBinding) - delBinding->destroy(); + QQmlPropertyPrivate::removeBinding(d->revertList.at(ii).property()); QQuickStateAction a; a.property = d->revertList.at(ii).property(); a.fromValue = cur; a.toValue = d->revertList.at(ii).value(); - a.toBinding = QQmlAbstractBinding::getPointer(d->revertList.at(ii).binding()); + a.toBinding = d->revertList.at(ii).binding(); a.specifiedObject = d->revertList.at(ii).specifiedObject(); a.specifiedProperty = d->revertList.at(ii).specifiedProperty(); a.event = d->revertList.at(ii).event(); diff --git a/src/quick/util/qquickstate_p.h b/src/quick/util/qquickstate_p.h index 0c774635d8..1870b70626 100644 --- a/src/quick/util/qquickstate_p.h +++ b/src/quick/util/qquickstate_p.h @@ -39,13 +39,14 @@ #include <QtCore/qobject.h> #include <QtCore/qsharedpointer.h> #include <private/qtquickglobal_p.h> +#include <private/qqmlabstractbinding_p.h> QT_BEGIN_NAMESPACE class QQuickStateActionEvent; -class QQmlAbstractBinding; class QQmlBinding; class QQmlExpression; + class QQuickStateAction { public: @@ -63,8 +64,8 @@ public: QVariant fromValue; QVariant toValue; - QQmlAbstractBinding *fromBinding; - QWeakPointer<QQmlAbstractBinding> toBinding; + QQmlAbstractBinding::Ptr fromBinding; + QQmlAbstractBinding::Ptr toBinding; QQuickStateActionEvent *event; //strictly for matching @@ -80,13 +81,12 @@ public: virtual ~QQuickStateActionEvent(); enum EventType { Script, SignalHandler, ParentChange, AnchorChanges }; - enum Reason { ActualChange, FastForward }; virtual EventType type() const = 0; - virtual void execute(Reason reason = ActualChange); + virtual void execute(); virtual bool isReversable(); - virtual void reverse(Reason reason = ActualChange); + virtual void reverse(); virtual void saveOriginals() {} virtual bool needsCopy() { return false; } virtual void copyOriginals(QQuickStateActionEvent *) {} diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h index fc589f0d2d..e6ecb424e5 100644 --- a/src/quick/util/qquickstate_p_p.h +++ b/src/quick/util/qquickstate_p_p.h @@ -71,7 +71,7 @@ public: if (state == StartState) { m_value = a.fromValue; if (QQmlPropertyPrivate::binding(m_property)) { - m_binding = QQmlAbstractBinding::getPointer(QQmlPropertyPrivate::binding(m_property)); + m_binding = QQmlPropertyPrivate::binding(m_property); } m_reverseEvent = true; } else { @@ -88,7 +88,7 @@ public: QQuickSimpleAction(const QQuickSimpleAction &other) : m_property(other.m_property), m_value(other.m_value), - m_binding(QQmlAbstractBinding::getPointer(other.binding())), + m_binding(other.binding()), m_specifiedObject(other.m_specifiedObject), m_specifiedProperty(other.m_specifiedProperty), m_event(other.m_event), @@ -100,7 +100,7 @@ public: { m_property = other.m_property; m_value = other.m_value; - m_binding = QQmlAbstractBinding::getPointer(other.binding()); + m_binding = other.binding(); m_specifiedObject = other.m_specifiedObject; m_specifiedProperty = other.m_specifiedProperty; m_event = other.m_event; @@ -131,7 +131,7 @@ public: void setBinding(QQmlAbstractBinding *binding) { - m_binding = QQmlAbstractBinding::getPointer(binding); + m_binding = binding; } QQmlAbstractBinding *binding() const @@ -162,7 +162,7 @@ public: private: QQmlProperty m_property; QVariant m_value; - QQmlAbstractBinding::Pointer m_binding; + QQmlAbstractBinding::Ptr m_binding; QObject *m_specifiedObject; QString m_specifiedProperty; QQuickStateActionEvent *m_event; diff --git a/src/quick/util/qquickstatechangescript.cpp b/src/quick/util/qquickstatechangescript.cpp index 6d25b9791d..c276183d62 100644 --- a/src/quick/util/qquickstatechangescript.cpp +++ b/src/quick/util/qquickstatechangescript.cpp @@ -118,7 +118,7 @@ void QQuickStateChangeScript::setName(const QString &n) d->name = n; } -void QQuickStateChangeScript::execute(Reason) +void QQuickStateChangeScript::execute() { Q_D(QQuickStateChangeScript); if (!d->script.isEmpty()) { diff --git a/src/quick/util/qquickstatechangescript_p.h b/src/quick/util/qquickstatechangescript_p.h index 4ff6f0db3e..6c019a43d2 100644 --- a/src/quick/util/qquickstatechangescript_p.h +++ b/src/quick/util/qquickstatechangescript_p.h @@ -62,7 +62,7 @@ public: QString name() const; void setName(const QString &); - virtual void execute(Reason reason = ActualChange); + virtual void execute(); }; diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp index 6ed32c10e2..c411207121 100644 --- a/src/quick/util/qquickstyledtext.cpp +++ b/src/quick/util/qquickstyledtext.cpp @@ -182,7 +182,7 @@ void QQuickStyledText::parse(const QString &string, QTextLayout &layout, void QQuickStyledTextPrivate::parse() { - QList<QTextLayout::FormatRange> ranges; + QVector<QTextLayout::FormatRange> ranges; QStack<QTextCharFormat> formatStack; QString drawText; @@ -283,7 +283,7 @@ void QQuickStyledTextPrivate::parse() } layout.setText(drawText); - layout.setAdditionalFormats(ranges); + layout.setFormats(ranges); } void QQuickStyledTextPrivate::appendText(const QString &textIn, int start, int length, QString &textOut) diff --git a/src/quick/util/qquicksystempalette_p.h b/src/quick/util/qquicksystempalette_p.h index 143efa1c12..fb898eb1fa 100644 --- a/src/quick/util/qquicksystempalette_p.h +++ b/src/quick/util/qquicksystempalette_p.h @@ -45,7 +45,6 @@ class QQuickSystemPalettePrivate; class Q_AUTOTEST_EXPORT QQuickSystemPalette : public QObject { Q_OBJECT - Q_ENUMS(ColorGroup) Q_DECLARE_PRIVATE(QQuickSystemPalette) Q_PROPERTY(QQuickSystemPalette::ColorGroup colorGroup READ colorGroup WRITE setColorGroup NOTIFY paletteChanged) @@ -69,6 +68,7 @@ public: ~QQuickSystemPalette(); enum ColorGroup { Active = QPalette::Active, Inactive = QPalette::Inactive, Disabled = QPalette::Disabled }; + Q_ENUM(ColorGroup) QColor window() const; QColor windowText() const; diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp index 74754a0bfb..88fc03bba8 100644 --- a/src/quick/util/qquicktimeline.cpp +++ b/src/quick/util/qquicktimeline.cpp @@ -659,7 +659,7 @@ void QQuickTimeLine::complete() */ void QQuickTimeLine::clear() { - for (QQuickTimeLinePrivate::Ops::const_iterator iter = d->ops.begin(), cend = d->ops.end(); iter != cend; ++iter) + for (QQuickTimeLinePrivate::Ops::const_iterator iter = d->ops.cbegin(), cend = d->ops.cend(); iter != cend; ++iter) iter.key()->_t = 0; d->ops.clear(); d->length = 0; diff --git a/src/quick/util/qquicktransitionmanager.cpp b/src/quick/util/qquicktransitionmanager.cpp index 832596d9a2..3992df993c 100644 --- a/src/quick/util/qquicktransitionmanager.cpp +++ b/src/quick/util/qquicktransitionmanager.cpp @@ -101,8 +101,8 @@ void QQuickTransitionManager::complete() void QQuickTransitionManagerPrivate::applyBindings() { foreach(const QQuickStateAction &action, bindingsList) { - if (!action.toBinding.isNull()) { - QQmlPropertyPrivate::setBinding(action.property, action.toBinding.data()); + if (action.toBinding) { + QQmlPropertyPrivate::setBinding(action.toBinding.data()); } else if (action.event) { if (action.reverseEvent) action.event->reverse(); @@ -131,7 +131,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list, if (action.toBinding) d->bindingsList << action; if (action.fromBinding) - QQmlPropertyPrivate::setBinding(action.property, 0); // Disable current binding + QQmlPropertyPrivate::removeBinding(action.property); // Disable current binding if (action.event && action.event->changesBindings()) { //### assume isReversable()? d->bindingsList << action; action.event->clearBindings(); @@ -146,24 +146,21 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list, // // This doesn't catch everything, and it might be a little fragile in // some cases - but whatcha going to do? - // - // Note that we only fast forward if both a transition and bindings are - // present, as it is unnecessary (and potentially expensive) otherwise. if (transition && !d->bindingsList.isEmpty()) { // Apply all the property and binding changes for (int ii = 0; ii < applyList.size(); ++ii) { const QQuickStateAction &action = applyList.at(ii); - if (!action.toBinding.isNull()) { - QQmlPropertyPrivate::setBinding(action.property, action.toBinding.data(), QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + if (action.toBinding) { + QQmlPropertyPrivate::setBinding(action.toBinding.data(), QQmlPropertyPrivate::None, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); } else if (!action.event) { QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); } else if (action.event->isReversable()) { if (action.reverseEvent) - action.event->reverse(QQuickStateActionEvent::FastForward); + action.event->reverse(); else - action.event->execute(QQuickStateActionEvent::FastForward); + action.event->execute(); } } @@ -175,7 +172,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list, continue; } const QQmlProperty &prop = action->property; - if (!action->toBinding.isNull() || !action->toValue.isValid()) { + if (action->toBinding || !action->toValue.isValid()) { action->toValue = prop.read(); } } @@ -192,7 +189,7 @@ void QQuickTransitionManager::transition(const QList<QQuickStateAction> &list, } if (action.toBinding) - QQmlPropertyPrivate::setBinding(action.property, 0); // Make sure this is disabled during the transition + QQmlPropertyPrivate::removeBinding(action.property); // Make sure this is disabled during the transition QQmlPropertyPrivate::write(action.property, action.fromValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); } @@ -269,10 +266,9 @@ void QQuickTransitionManager::cancel() for(int i = 0; i < d->bindingsList.count(); ++i) { QQuickStateAction action = d->bindingsList[i]; - if (!action.toBinding.isNull() && action.deletableToBinding) { - QQmlPropertyPrivate::setBinding(action.property, 0); - action.toBinding.data()->destroy(); - action.toBinding.clear(); + if (action.toBinding && action.deletableToBinding) { + QQmlPropertyPrivate::removeBinding(action.property); + action.toBinding = 0; action.deletableToBinding = false; } else if (action.event) { //### what do we do here? diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index 4d156a2d9a..4f6e49fa7a 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -49,6 +49,7 @@ #include "qquicktransition_p.h" #include "qquickanimator_p.h" #include "qquickshortcut_p.h" +#include "qquickvalidator_p.h" #include <qqmlinfo.h> #include <private/qqmltypenotavailable_p.h> #include <private/qquickanimationcontroller_p.h> @@ -87,6 +88,13 @@ void QQuickUtilModule::defineModule() qmlRegisterType<QQuickTransition>("QtQuick",2,0,"Transition"); qmlRegisterType<QQuickVector3dAnimation>("QtQuick",2,0,"Vector3dAnimation"); +#ifndef QT_NO_VALIDATOR + qmlRegisterType<QValidator>(); + qmlRegisterType<QQuickIntValidator>("QtQuick",2,0,"IntValidator"); + qmlRegisterType<QQuickDoubleValidator>("QtQuick",2,0,"DoubleValidator"); + qmlRegisterType<QRegExpValidator>("QtQuick",2,0,"RegExpValidator"); +#endif + qmlRegisterUncreatableType<QQuickAnimator>("QtQuick", 2, 2, "Animator", QQuickAbstractAnimation::tr("Animator is an abstract class")); qmlRegisterType<QQuickXAnimator>("QtQuick", 2, 2, "XAnimator"); qmlRegisterType<QQuickYAnimator>("QtQuick", 2, 2, "YAnimator"); diff --git a/src/quick/util/qquickvalidator.cpp b/src/quick/util/qquickvalidator.cpp new file mode 100644 index 0000000000..3eebf5d77a --- /dev/null +++ b/src/quick/util/qquickvalidator.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickvalidator_p.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_VALIDATOR + +/*! + \qmltype IntValidator + \instantiates QIntValidator + \inqmlmodule QtQuick + \ingroup qtquick-text-utility + \brief Defines a validator for integer values + + The IntValidator type provides a validator for integer values. + + If no \l locale is set IntValidator uses the \l {QLocale::setDefault()}{default locale} to + interpret the number and will accept locale specific digits, group separators, and positive + and negative signs. In addition, IntValidator is always guaranteed to accept a number + formatted according to the "C" locale. +*/ + +QQuickIntValidator::QQuickIntValidator(QObject *parent) + : QIntValidator(parent) +{ +} + +/*! + \qmlproperty string QtQuick::IntValidator::locale + + This property holds the name of the locale used to interpret the number. + + \sa {QtQml::Qt::locale()}{Qt.locale()} +*/ + +QString QQuickIntValidator::localeName() const +{ + return locale().name(); +} + +void QQuickIntValidator::setLocaleName(const QString &name) +{ + if (locale().name() != name) { + setLocale(QLocale(name)); + emit localeNameChanged(); + } +} + +void QQuickIntValidator::resetLocaleName() +{ + QLocale defaultLocale; + if (locale() != defaultLocale) { + setLocale(defaultLocale); + emit localeNameChanged(); + } +} + +/*! + \qmlproperty int QtQuick::IntValidator::top + + This property holds the validator's highest acceptable value. + By default, this property's value is derived from the highest signed integer available (typically 2147483647). +*/ +/*! + \qmlproperty int QtQuick::IntValidator::bottom + + This property holds the validator's lowest acceptable value. + By default, this property's value is derived from the lowest signed integer available (typically -2147483647). +*/ + +/*! + \qmltype DoubleValidator + \instantiates QDoubleValidator + \inqmlmodule QtQuick + \ingroup qtquick-text-utility + \brief Defines a validator for non-integer numbers + + The DoubleValidator type provides a validator for non-integer numbers. + + Input is accepted if it contains a double that is within the valid range + and is in the correct format. + + Input is accepected but invalid if it contains a double that is outside + the range or is in the wrong format; e.g. with too many digits after the + decimal point or is empty. + + Input is rejected if it is not a double. + + Note: If the valid range consists of just positive doubles (e.g. 0.0 to + 100.0) and input is a negative double then it is rejected. If \l notation + is set to DoubleValidator.StandardNotation, and the input contains more + digits before the decimal point than a double in the valid range may have, + it is also rejected. If \l notation is DoubleValidator.ScientificNotation, + and the input is not in the valid range, it is accecpted but invalid. The + value may yet become valid by changing the exponent. +*/ + +QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent) + : QDoubleValidator(parent) +{ +} + +/*! + \qmlproperty string QtQuick::DoubleValidator::locale + + This property holds the name of the locale used to interpret the number. + + \sa {QtQml::Qt::locale()}{Qt.locale()} +*/ + +QString QQuickDoubleValidator::localeName() const +{ + return locale().name(); +} + +void QQuickDoubleValidator::setLocaleName(const QString &name) +{ + if (locale().name() != name) { + setLocale(QLocale(name)); + emit localeNameChanged(); + } +} + +void QQuickDoubleValidator::resetLocaleName() +{ + QLocale defaultLocale; + if (locale() != defaultLocale) { + setLocale(defaultLocale); + emit localeNameChanged(); + } +} + +/*! + \qmlproperty real QtQuick::DoubleValidator::top + + This property holds the validator's maximum acceptable value. + By default, this property contains a value of infinity. +*/ +/*! + \qmlproperty real QtQuick::DoubleValidator::bottom + + This property holds the validator's minimum acceptable value. + By default, this property contains a value of -infinity. +*/ +/*! + \qmlproperty int QtQuick::DoubleValidator::decimals + + This property holds the validator's maximum number of digits after the decimal point. + By default, this property contains a value of 1000. +*/ +/*! + \qmlproperty enumeration QtQuick::DoubleValidator::notation + This property holds the notation of how a string can describe a number. + + The possible values for this property are: + + \list + \li DoubleValidator.StandardNotation + \li DoubleValidator.ScientificNotation (default) + \endlist + + If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2). +*/ + +/*! + \qmltype RegExpValidator + \instantiates QRegExpValidator + \inqmlmodule QtQuick + \ingroup qtquick-text-utility + \brief Provides a string validator + + The RegExpValidator type provides a validator, which counts as valid any string which + matches a specified regular expression. +*/ +/*! + \qmlproperty regExp QtQuick::RegExpValidator::regExp + + This property holds the regular expression used for validation. + + Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression + matching "a". + + By default, this property contains a regular expression with the pattern .* that matches any string. +*/ + +#endif // QT_NO_VALIDATOR + +QT_END_NAMESPACE + diff --git a/src/quick/util/qquickvalidator_p.h b/src/quick/util/qquickvalidator_p.h new file mode 100644 index 0000000000..59d7884afc --- /dev/null +++ b/src/quick/util/qquickvalidator_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKVALIDATOR_P_H +#define QQUICKVALIDATOR_P_H + +#include <QtGui/qvalidator.h> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_VALIDATOR +class Q_AUTOTEST_EXPORT QQuickIntValidator : public QIntValidator +{ + Q_OBJECT + Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged) +public: + QQuickIntValidator(QObject *parent = 0); + + QString localeName() const; + void setLocaleName(const QString &name); + void resetLocaleName(); + +Q_SIGNALS: + void localeNameChanged(); +}; + +class Q_AUTOTEST_EXPORT QQuickDoubleValidator : public QDoubleValidator +{ + Q_OBJECT + Q_PROPERTY(QString locale READ localeName WRITE setLocaleName RESET resetLocaleName NOTIFY localeNameChanged) +public: + QQuickDoubleValidator(QObject *parent = 0); + + QString localeName() const; + void setLocaleName(const QString &name); + void resetLocaleName(); + +Q_SIGNALS: + void localeNameChanged(); +}; +#endif + +QT_END_NAMESPACE + +#ifndef QT_NO_VALIDATOR +QML_DECLARE_TYPE(QValidator) +QML_DECLARE_TYPE(QQuickIntValidator) +QML_DECLARE_TYPE(QQuickDoubleValidator) +QML_DECLARE_TYPE(QRegExpValidator) +#endif + +#endif // QQUICKVALIDATOR_P_H diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp index fef6dfd1d0..1f0d54e4e7 100644 --- a/src/quick/util/qquickvaluetypes.cpp +++ b/src/quick/util/qquickvaluetypes.cpp @@ -533,6 +533,16 @@ void QQuickFontValueType::setFamily(const QString &family) v.setFamily(family); } +QString QQuickFontValueType::styleName() const +{ + return v.styleName(); +} + +void QQuickFontValueType::setStyleName(const QString &style) +{ + v.setStyleName(style); +} + bool QQuickFontValueType::bold() const { return v.bold(); diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h index f62306ed01..7a2e8888b7 100644 --- a/src/quick/util/qquickvaluetypes_p.h +++ b/src/quick/util/qquickvaluetypes_p.h @@ -266,10 +266,9 @@ class QQuickFontValueType { QFont v; Q_GADGET - Q_ENUMS(FontWeight) - Q_ENUMS(Capitalization) Q_PROPERTY(QString family READ family WRITE setFamily FINAL) + Q_PROPERTY(QString styleName READ styleName WRITE setStyleName FINAL) Q_PROPERTY(bool bold READ bold WRITE setBold FINAL) Q_PROPERTY(FontWeight weight READ weight WRITE setWeight FINAL) Q_PROPERTY(bool italic READ italic WRITE setItalic FINAL) @@ -292,17 +291,22 @@ public: Bold = QFont::Bold, ExtraBold = QFont::ExtraBold, Black = QFont::Black }; + Q_ENUM(FontWeight) enum Capitalization { MixedCase = QFont::MixedCase, AllUppercase = QFont::AllUppercase, AllLowercase = QFont::AllLowercase, SmallCaps = QFont::SmallCaps, Capitalize = QFont::Capitalize }; + Q_ENUM(Capitalization) Q_INVOKABLE QString toString() const; QString family() const; void setFamily(const QString &); + QString styleName() const; + void setStyleName(const QString &); + bool bold() const; void setBold(bool b); diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index 0e0df4e751..ffb31ae75e 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -29,7 +29,8 @@ SOURCES += \ $$PWD/qquickprofiler.cpp \ $$PWD/qquickfontmetrics.cpp \ $$PWD/qquicktextmetrics.cpp \ - $$PWD/qquickshortcut.cpp + $$PWD/qquickshortcut.cpp \ + $$PWD/qquickvalidator.cpp HEADERS += \ $$PWD/qquickapplication_p.h\ @@ -66,4 +67,5 @@ HEADERS += \ $$PWD/qquickprofiler_p.h \ $$PWD/qquickfontmetrics_p.h \ $$PWD/qquicktextmetrics_p.h \ - $$PWD/qquickshortcut_p.h + $$PWD/qquickshortcut_p.h \ + $$PWD/qquickvalidator_p.h |