diff options
52 files changed, 1111 insertions, 143 deletions
diff --git a/.qmake.conf b/.qmake.conf index 7fcbf65fc2..fc13c75da5 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ load(qt_build_config) CONFIG += qt_example_installs CONFIG += warning_clean -MODULE_VERSION = 5.5.0 +MODULE_VERSION = 5.6.0 diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index ef44ca6f4d..5c63ac1728 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -10,7 +10,6 @@ SOURCES += \ $$PWD/qv4lookup.cpp \ $$PWD/qv4identifier.cpp \ $$PWD/qv4identifiertable.cpp \ - $$PWD/qv4mm.cpp \ $$PWD/qv4managed.cpp \ $$PWD/qv4internalclass.cpp \ $$PWD/qv4sparsearray.cpp \ @@ -57,7 +56,6 @@ HEADERS += \ $$PWD/qv4lookup_p.h \ $$PWD/qv4identifier_p.h \ $$PWD/qv4identifiertable_p.h \ - $$PWD/qv4mm_p.h \ $$PWD/qv4managed_p.h \ $$PWD/qv4internalclass_p.h \ $$PWD/qv4sparsearray_p.h \ diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 737c891f9b..bdc33347ca 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -33,7 +33,7 @@ #include "qv4arraydata_p.h" #include "qv4object_p.h" #include "qv4functionobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4runtime_p.h" #include "qv4argumentsobject_p.h" diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 09d7393da9..833e281836 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -36,7 +36,7 @@ #include <qv4context_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include <qv4argumentsobject_p.h> #include "qv4function_p.h" #include "qv4errorobject_p.h" diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 54dd5979cf..0ace88b01f 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -48,7 +48,7 @@ #include <qv4regexp_p.h> #include <qv4variantobject_p.h> #include <qv4runtime_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include <qv4argumentsobject_p.h> #include <qv4dateobject_p.h> #include <qv4jsonobject_p.h> diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 119ad93e63..531786f30d 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -33,11 +33,13 @@ #include "qv4errorobject_p.h" -#include "qv4mm_p.h" +#include <QtCore/qnumeric.h> +#include <QtCore/qmath.h> #include <QtCore/QDateTime> #include <QtCore/QStringList> #include <QtCore/QDebug> +#include <private/qv4mm_p.h> #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index efe6c7c226..8f737c995b 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -37,7 +37,7 @@ #include "qv4value_inl_p.h" #include "qv4engine_p.h" #include "qv4lookup_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 5be638e909..6363993578 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4function_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4arrayobject_p.h" #include "qv4scopedvalue_p.h" diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 3433e7b8ca..ce00dfb340 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -36,7 +36,7 @@ #include "qv4object_p.h" #include "qv4function_p.h" #include "qv4context_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 8e33cec57f..5beb46f574 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4globalobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4value_inl_p.h" #include "qv4context_p.h" #include "qv4function_p.h" diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index c4b9fc597e..a6bce089d0 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4managed_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4errorobject_p.h" using namespace QV4; diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 03dfee3dcf..66864e2dd6 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4memberdata_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> using namespace QV4; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 211fd1812e..8afed2c274 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4lookup_p.h" #include "qv4scopedvalue_p.h" #include "qv4memberdata_p.h" diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 71a997e133..a8bd97b7c1 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -55,7 +55,7 @@ struct Object : Base { Property *propertyAt(uint index) { return reinterpret_cast<Property *>(memberData->data + index); } InternalClass *internalClass; - Heap::Object *prototype; + Pointer<Object> prototype; MemberData *memberData; ArrayData *arrayData; }; diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 9356ea434e..ed659388f3 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -34,7 +34,7 @@ #include "qv4objectproto_p.h" #include "qv4argumentsobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include "qv4runtime_p.h" #include "qv4objectiterator_p.h" diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 88dc1946b8..0889415a28 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4persistent_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4object_p.h" #include "PageAllocation.h" diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index a7019d0558..a67d377063 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4profiling_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 8e18a5fbdd..715df2d666 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -34,7 +34,7 @@ #include "qv4regexp_p.h" #include "qv4engine_p.h" #include "qv4scopedvalue_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> using namespace QV4; diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index f6e88e62b7..1fa5653020 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -37,7 +37,7 @@ #include "qv4objectproto_p.h" #include "qv4regexp_p.h" #include "qv4stringobject_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 4fde0e2445..81ce0db480 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include "qv4script_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4functionobject_p.h" #include "qv4function_p.h" #include "qv4context_p.h" diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index e0b84f6da3..91d5bc3d78 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -36,7 +36,7 @@ #include "qv4regexp_p.h" #include "qv4regexpobject_p.h" #include "qv4objectproto_p.h" -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #include "qv4scopedvalue_p.h" #include "qv4alloca_p.h" #include <QtCore/QDateTime> diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 68228f06bb..0ea4676f47 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -35,7 +35,7 @@ #ifndef V4_BOOTSTRAP #include <qv4object_p.h> #include <qv4objectproto_p.h> -#include "qv4mm_p.h" +#include <private/qv4mm_p.h> #endif #include <wtf/MathExtras.h> diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 2b2d275b58..8ed6c1459c 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -37,6 +37,7 @@ #include <QtCore/QString> #include "qv4global_p.h" +#include <private/qv4heap_p.h> QT_BEGIN_NAMESPACE @@ -44,54 +45,6 @@ namespace QV4 { typedef uint Bool; -namespace Heap { - -struct Q_QML_EXPORT Base { - union { - const ManagedVTable *vtable; - quintptr mm_data; - }; - - inline ReturnedValue asReturnedValue() const; - inline void mark(QV4::ExecutionEngine *engine); - - enum { - MarkBit = 0x1, - NotInUse = 0x2, - PointerMask = ~0x3 - }; - - ManagedVTable *gcGetVtable() const { - return reinterpret_cast<ManagedVTable *>(mm_data & PointerMask); - } - inline bool isMarked() const { - return mm_data & MarkBit; - } - inline void setMarkBit() { - mm_data |= MarkBit; - } - inline void clearMarkBit() { - mm_data &= ~MarkBit; - } - - inline bool inUse() const { - return !(mm_data & NotInUse); - } - - Base *nextFree() { - return reinterpret_cast<Base *>(mm_data & PointerMask); - } - void setNextFree(Base *m) { - mm_data = (reinterpret_cast<quintptr>(m) | NotInUse); - } - - void *operator new(size_t, Managed *m) { return m; } - void *operator new(size_t, Heap::Base *m) { return m; } - void operator delete(void *, Heap::Base *) {} -}; - -} - struct Q_QML_PRIVATE_EXPORT Value { /* diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri new file mode 100644 index 0000000000..04b7566ccc --- /dev/null +++ b/src/qml/memory/memory.pri @@ -0,0 +1,14 @@ +INCLUDEPATH += $$PWD +INCLUDEPATH += $$OUT_PWD + +!qmldevtools_build { +SOURCES += \ + $$PWD/qv4mm.cpp \ + +HEADERS += \ + $$PWD/qv4mm_p.h + +} + +HEADERS += \ + $$PWD/qv4heap_p.h diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h new file mode 100644 index 0000000000..96d73766d0 --- /dev/null +++ b/src/qml/memory/qv4heap_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml 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 QV4HEAP_P_H +#define QV4HEAP_P_H + +#include <QtCore/QString> +#include <private/qv4global_p.h> + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +namespace Heap { + +struct Q_QML_EXPORT Base { + union { + const ManagedVTable *vtable; + quintptr mm_data; + }; + + inline ReturnedValue asReturnedValue() const; + inline void mark(QV4::ExecutionEngine *engine); + + enum { + MarkBit = 0x1, + NotInUse = 0x2, + PointerMask = ~0x3 + }; + + ManagedVTable *gcGetVtable() const { + return reinterpret_cast<ManagedVTable *>(mm_data & PointerMask); + } + inline bool isMarked() const { + return mm_data & MarkBit; + } + inline void setMarkBit() { + mm_data |= MarkBit; + } + inline void clearMarkBit() { + mm_data &= ~MarkBit; + } + + inline bool inUse() const { + return !(mm_data & NotInUse); + } + + Base *nextFree() { + return reinterpret_cast<Base *>(mm_data & PointerMask); + } + void setNextFree(Base *m) { + mm_data = (reinterpret_cast<quintptr>(m) | NotInUse); + } + + void *operator new(size_t, Managed *m) { return m; } + void *operator new(size_t, Heap::Base *m) { return m; } + void operator delete(void *, Heap::Base *) {} +}; + +template <typename T> +struct Pointer { + Pointer() {} + Pointer(T *t) : ptr(t) {} + + T *operator->() const { return static_cast<T *>(ptr); } + operator T *() const { return static_cast<T *>(ptr); } + + Pointer &operator =(T *t) { ptr = t; return *this; } + + // Use Base, not T here, to ensure T inherits from ptr + Base *ptr; +}; + +} + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 07408a343c..07408a343c 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 00b41b796a..422809ba54 100644 --- a/src/qml/jsruntime/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -34,9 +34,9 @@ #ifndef QV4GC_H #define QV4GC_H -#include "qv4global_p.h" -#include "qv4value_inl_p.h" -#include "qv4scopedvalue_p.h" +#include <private/qv4global_p.h> +#include <private/qv4value_p.h> +#include <private/qv4scopedvalue_p.h> //#define DETAILED_MM_STATS diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 6e06fb42ef..cfb08da6a1 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -33,6 +33,7 @@ HEADERS += qtqmlglobal.h \ #modules include(util/util.pri) +include(memory/memory.pri) include(parser/parser.pri) include(compiler/compiler.pri) include(jsapi/jsapi.pri) diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index c9bae8e774..c7654be545 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -123,8 +123,14 @@ public: quint32 parentFrozen:1; quint32 dummy:22; + // When bindingBitsSize < 32, we store the binding bit flags inside + // bindingBitsValue. When we need more than 32 bits, we allocated + // sufficient space and use bindingBits to point to it. int bindingBitsSize; - quint32 *bindingBits; + union { + quint32 *bindingBits; + quint32 bindingBitsValue; + }; struct NotifyList { quint64 connectionMask; @@ -261,19 +267,19 @@ QQmlNotifierEndpoint *QQmlData::notify(int index) bool QQmlData::hasBindingBit(int coreIndex) const { int bit = coreIndex * 2; - if (bindingBitsSize > bit) - return bindingBits[bit / 32] & (1 << (bit % 32)); - else - return false; + + return bindingBitsSize > bit && + ((bindingBitsSize == 32) ? (bindingBitsValue & (1 << bit)) : + (bindingBits[bit / 32] & (1 << (bit % 32)))); } bool QQmlData::hasPendingBindingBit(int coreIndex) const { int bit = coreIndex * 2 + 1; - if (bindingBitsSize > bit) - return bindingBits[bit / 32] & (1 << (bit % 32)); - else - return false; + + return bindingBitsSize > bit && + ((bindingBitsSize == 32) ? (bindingBitsValue & (1 << bit)) : + (bindingBits[bit / 32] & (1 << (bit % 32)))); } void QQmlData::flushPendingBinding(QObject *o, int coreIndex) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 70090bd3f9..92e98e3e84 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1690,7 +1690,7 @@ void QQmlData::destroyed(QObject *object) signalHandler = next; } - if (bindingBits) + if (bindingBitsSize > 32) free(bindingBits); if (propertyCache) @@ -1738,14 +1738,24 @@ void QQmlData::parentChanged(QObject *object, QObject *parent) static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit) { + if (data->bindingBitsSize == 0 && bit < 32) { + data->bindingBitsSize = 32; + } + if (data->bindingBitsSize <= bit) { int props = QQmlMetaObject(obj).propertyCount(); Q_ASSERT(bit < 2 * props); int arraySize = (2 * props + 31) / 32; - int oldArraySize = data->bindingBitsSize / 32; + Q_ASSERT(arraySize > 1); - data->bindingBits = (quint32 *)realloc(data->bindingBits, + // special handling for 32 here is to make sure we wipe the first byte + // when going from bindingBitsValue to bindingBits, and preserve the old + // set bits so we can restore them after the allocation + int oldArraySize = data->bindingBitsSize > 32 ? data->bindingBitsSize / 32 : 0; + quint32 oldValue = data->bindingBitsSize == 32 ? data->bindingBitsValue : 0; + + data->bindingBits = (quint32 *)realloc((data->bindingBitsSize == 32) ? 0 : data->bindingBits, arraySize * sizeof(quint32)); memset(data->bindingBits + oldArraySize, @@ -1753,15 +1763,27 @@ static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit) sizeof(quint32) * (arraySize - oldArraySize)); data->bindingBitsSize = arraySize * 32; + + // reinstate bindingBitsValue after we dropped it + if (oldValue) { + memcpy(data->bindingBits, &oldValue, sizeof(oldValue)); + } } - data->bindingBits[bit / 32] |= (1 << (bit % 32)); + if (data->bindingBitsSize == 32) + data->bindingBitsValue |= (1 << (bit % 32)); + else + data->bindingBits[bit / 32] |= (1 << (bit % 32)); } static void QQmlData_clearBit(QQmlData *data, int bit) { - if (data->bindingBitsSize > bit) - data->bindingBits[bit / 32] &= ~(1 << (bit % 32)); + if (data->bindingBitsSize > bit) { + if (data->bindingBitsSize == 32) + data->bindingBitsValue &= ~(1 << (bit % 32)); + else + data->bindingBits[bit / 32] &= ~(1 << (bit % 32)); + } } void QQmlData::clearBindingBit(int coreIndex) diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro index df1b750282..85f21ce6f6 100644 --- a/src/qmldevtools/qmldevtools.pro +++ b/src/qmldevtools/qmldevtools.pro @@ -19,3 +19,4 @@ include(../3rdparty/masm/masm-defs.pri) include(../qml/parser/parser.pri) include(../qml/jsruntime/jsruntime.pri) include(../qml/compiler/compiler.pri) +include(../qml/memory/memory.pri) diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h index efe83e7026..181efc719f 100644 --- a/src/quick/items/qquickimage_p.h +++ b/src/quick/items/qquickimage_p.h @@ -40,7 +40,7 @@ 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) diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 6c342cc491..01b8a249df 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -267,6 +267,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties")); qmlRegisterType<QQuickPinchArea, 1>(uri, 2, 5,"PinchArea"); + + qmlRegisterType<QQuickTextEdit, 6>(uri, 2, 6, "TextEdit"); + qmlRegisterType<QQuickTextInput, 6>(uri, 2, 6, "TextInput"); } static void initResources() diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index 170072a814..9be167f398 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -43,7 +43,7 @@ class QQuickItemViewTransitionableItem; class QQuickItemViewTransitionJob; -class QQuickItemViewTransitionChangeListener +class Q_QUICK_PRIVATE_EXPORT QQuickItemViewTransitionChangeListener { public: QQuickItemViewTransitionChangeListener() {} @@ -53,7 +53,7 @@ public: }; -class QQuickItemViewTransitioner +class Q_QUICK_PRIVATE_EXPORT QQuickItemViewTransitioner { public: enum TransitionType { @@ -113,7 +113,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/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 03efbd0aa0..29300644b9 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -695,6 +695,62 @@ Qt::InputMethodHints QQuickTextEditPrivate::effectiveInputMethodHints() const } #endif +void QQuickTextEditPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->topPadding(); + topPadding = 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->topPadding(); + leftPadding = value; + explicitLeftPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + q->updateSize(); + emit q->leftPaddingChanged(); + if (q->isComponentComplete()) { + updateType = QQuickTextEditPrivate::UpdatePaintNode; + q->update(); + } + } +} + +void QQuickTextEditPrivate::setRightPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->topPadding(); + rightPadding = value; + explicitRightPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + q->updateSize(); + emit q->rightPaddingChanged(); + if (q->isComponentComplete()) { + updateType = QQuickTextEditPrivate::UpdatePaintNode; + q->update(); + } + } +} + +void QQuickTextEditPrivate::setBottomPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextEdit); + qreal oldPadding = q->topPadding(); + bottomPadding = 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); @@ -2220,7 +2276,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 @@ -2238,13 +2294,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 @@ -2259,12 +2315,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); @@ -2410,10 +2466,13 @@ 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(); } } @@ -2582,6 +2641,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 @@ -2674,7 +2742,131 @@ 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->padding = padding; + updateSize(); + if (isComponentComplete()) { + d->updateType = QQuickTextEditPrivate::UpdatePaintNode; + update(); + } + emit paddingChanged(); + if (!d->explicitTopPadding) + emit topPaddingChanged(); + if (!d->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickTextEdit::resetPadding() +{ + setPadding(0); +} + +qreal QQuickTextEdit::topPadding() const +{ + Q_D(const QQuickTextEdit); + if (d->explicitTopPadding) + return d->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->explicitLeftPadding) + return d->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->explicitRightPadding) + return d->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->explicitBottomPadding) + return d->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..5b6b0c767b 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -93,6 +93,11 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument 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); @@ -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(); diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index 0cf0f46532..20c0d1ca9c 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -84,7 +84,9 @@ public: 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), padding(0), topPadding(0), leftPadding(0), rightPadding(0), bottomPadding(0) + , explicitTopPadding(false), explicitLeftPadding(false), explicitRightPadding(false), explicitBottomPadding(false) + , 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) @@ -131,6 +133,11 @@ public: Qt::InputMethodHints effectiveInputMethodHints() const; #endif + 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; @@ -140,6 +147,15 @@ public: qreal textMargin; qreal xoff; qreal yoff; + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding; + bool explicitLeftPadding; + bool explicitRightPadding; + bool explicitBottomPadding; QString text; QUrl baseUrl; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 1b7552201f..24260c3150 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -776,8 +776,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()); } @@ -1479,8 +1479,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); @@ -1741,7 +1742,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()) { @@ -1804,7 +1805,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; @@ -1900,13 +1901,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() @@ -2861,7 +2862,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(); } @@ -2869,6 +2870,54 @@ qreal QQuickTextInputPrivate::getImplicitWidth() const return implicitWidth; } +void QQuickTextInputPrivate::setTopPadding(qreal value, bool reset) +{ + Q_Q(QQuickTextInput); + qreal oldPadding = q->topPadding(); + topPadding = 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(); + leftPadding = 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(); + rightPadding = 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(); + bottomPadding = value; + explicitBottomPadding = !reset; + if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding))) { + updateLayout(); + emit q->bottomPaddingChanged(); + } +} + void QQuickTextInputPrivate::updateLayout() { Q_Q(QQuickTextInput); @@ -2894,12 +2943,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 { @@ -2926,9 +2975,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(); @@ -2950,13 +2999,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 @@ -4487,5 +4536,125 @@ 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->padding = padding; + d->updateLayout(); + emit paddingChanged(); + if (!d->explicitTopPadding) + emit topPaddingChanged(); + if (!d->explicitLeftPadding) + emit leftPaddingChanged(); + if (!d->explicitRightPadding) + emit rightPaddingChanged(); + if (!d->explicitBottomPadding) + emit bottomPaddingChanged(); +} + +void QQuickTextInput::resetPadding() +{ + setPadding(0); +} + +qreal QQuickTextInput::topPadding() const +{ + Q_D(const QQuickTextInput); + if (d->explicitTopPadding) + return d->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->explicitLeftPadding) + return d->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->explicitRightPadding) + return d->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->explicitBottomPadding) + return d->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 78e6a6be7e..82a9cf9728 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -96,6 +96,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(); @@ -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,6 +326,11 @@ 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(); diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 3038573bb3..25ee2e79ce 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -74,6 +74,15 @@ public: QQuickTextInputPrivate() : hscroll(0) , vscroll(0) + , padding(0) + , topPadding(0) + , leftPadding(0) + , rightPadding(0) + , bottomPadding(0) + , explicitTopPadding(false) + , explicitLeftPadding(false) + , explicitRightPadding(false) + , explicitBottomPadding(false) , cursorItem(0) , textNode(0) , m_maskData(0) @@ -189,6 +198,16 @@ public: qreal hscroll; qreal vscroll; + qreal padding; + qreal topPadding; + qreal leftPadding; + qreal rightPadding; + qreal bottomPadding; + bool explicitTopPadding; + bool explicitLeftPadding; + bool explicitRightPadding; + bool explicitBottomPadding; + QTextLayout m_textLayout; QString m_text; QString m_inputMask; @@ -420,6 +439,11 @@ public: qreal getImplicitWidth() const Q_DECL_OVERRIDE; + 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/qquickview.cpp b/src/quick/items/qquickview.cpp index 5b5413a4ba..6582e3ad40 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -345,6 +345,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 +367,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 +508,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/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 147c449fc8..269928e531 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -531,6 +531,9 @@ QQuickWidget::Status QQuickWidget::status() const if (!d->component) return QQuickWidget::Null; + if (d->component->status() == QQmlComponent::Ready && !d->root) + return QQuickWidget::Error; + return QQuickWidget::Status(d->component->status()); } @@ -552,6 +555,10 @@ QList<QQmlError> QQuickWidget::errors() const QQmlError error; error.setDescription(QLatin1String("QQuickWidget: invalid qml engine.")); errs << error; + } else if (d->component->status() == QQmlComponent::Ready && !d->root) { + QQmlError error; + error.setDescription(QLatin1String("QQuickWidget: invalid root object.")); + errs << error; } return errs; @@ -820,14 +827,15 @@ void QQuickWidgetPrivate::setRootObject(QObject *obj) if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) { root = sgItem; sgItem->setParentItem(offscreenWindow->contentItem()); + } else if (qobject_cast<QWindow *>(obj)) { + qWarning() << "QQuickWidget 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() << "QQuickWidget 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/sync.profile b/sync.profile index f7255bea0a..28d0698da9 100644 --- a/sync.profile +++ b/sync.profile @@ -7,7 +7,7 @@ "QtQmlDevTools" => "$basedir/src/qmldevtools", ); %moduleheaders = ( # restrict the module headers to those found in relative path - "QtQmlDevTools" => "../qml/parser;../qml/jsruntime;../qml/qml/ftw;../qml/compiler;.", + "QtQmlDevTools" => "../qml/parser;../qml/jsruntime;../qml/qml/ftw;../qml/compiler;../qml/memory;.", ); %deprecatedheaders = ( ); diff --git a/tests/auto/qmltest/textedit/tst_textedit_editingfinished.qml b/tests/auto/qmltest/textedit/tst_textedit_editingfinished.qml new file mode 100644 index 0000000000..c9eadde373 --- /dev/null +++ b/tests/auto/qmltest/textedit/tst_textedit_editingfinished.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtTest 1.1 + +Row { + width: 100 + height: 50 + spacing: 10 + + property alias control1: _control1 + property alias control2: _control2 + TextEdit { + id: _control1 + text: 'A' + property bool myeditingfinished: false + onEditingFinished: myeditingfinished = true + activeFocusOnTab: true + } + TextEdit { + id: _control2 + text: 'B' + property bool myeditingfinished: false + onEditingFinished: myeditingfinished = true + activeFocusOnTab: true + } + + TestCase { + name: "TextEdit_editingFinished" + when: windowShown + + function test_editingFinished() { + control1.forceActiveFocus() + verify(control1.activeFocus) + verify(!control2.activeFocus) + + verify(control1.myeditingfinished === false) + verify(control2.myeditingfinished === false) + + keyClick(Qt.Key_Backtab) + verify(!control1.activeFocus) + verify(control2.activeFocus) + verify(control1.myeditingfinished === true) + + keyClick(Qt.Key_Backtab) + verify(control1.activeFocus) + verify(!control2.activeFocus) + verify(control2.myeditingfinished === true) + } + } +} diff --git a/tests/auto/quick/qquicktextedit/data/padding.qml b/tests/auto/quick/qquicktextedit/data/padding.qml new file mode 100644 index 0000000000..f4852bec8b --- /dev/null +++ b/tests/auto/quick/qquicktextedit/data/padding.qml @@ -0,0 +1,12 @@ +import QtQuick 2.6 + +TextEdit { + width: 200; height: 200 + text: "Hello Qt" + + padding: 10 + topPadding: 20 + leftPadding: 30 + rightPadding: 40 + bottomPadding: 50 +} diff --git a/tests/auto/quick/qquicktextedit/data/signal_editingfinished.qml b/tests/auto/quick/qquicktextedit/data/signal_editingfinished.qml new file mode 100644 index 0000000000..b5caab5e7c --- /dev/null +++ b/tests/auto/quick/qquicktextedit/data/signal_editingfinished.qml @@ -0,0 +1,13 @@ +import QtQuick 2.6 + +Item { + property QtObject input1: input1 + property QtObject input2: input2 + + width: 800; height: 600 + + Column{ + TextEdit { id: input1; activeFocusOnTab: true } + TextEdit { id: input2; activeFocusOnTab: true } + } +} diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index da18f9a0df..256e5b4bd5 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -169,6 +169,8 @@ private slots: void implicitSizeBinding_data(); void implicitSizeBinding(); + void signal_editingfinished(); + void preeditCursorRectangle(); void inputMethodComposing(); void cursorRectangleSize_data(); @@ -203,6 +205,8 @@ private slots: void cursorRectangle_QTBUG_38947(); void textCached_QTBUG_41583(); + void padding(); + private: void simulateKeys(QWindow *window, const QList<Key> &keys); void simulateKeys(QWindow *window, const QKeySequence &sequence); @@ -3317,6 +3321,53 @@ void tst_qquicktextedit::implicitSizeBinding() QCOMPARE(textObject->height(), textObject->implicitHeight()); } +void tst_qquicktextedit::signal_editingfinished() +{ + QQuickView *window = new QQuickView(0); + window->setBaseSize(QSize(800,600)); + + window->setSource(testFileUrl("signal_editingfinished.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + + QVERIFY(window->rootObject() != 0); + + QQuickTextEdit *input1 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window->rootObject()->property("input1"))); + QVERIFY(input1); + QQuickTextEdit *input2 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window->rootObject()->property("input2"))); + QVERIFY(input2); + + QSignalSpy editingFinished1Spy(input1, SIGNAL(editingFinished())); + + input1->setFocus(true); + QTRY_VERIFY(input1->hasActiveFocus()); + QTRY_VERIFY(!input2->hasActiveFocus()); + + QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + QTRY_COMPARE(editingFinished1Spy.count(), 1); + + QTRY_VERIFY(!input1->hasActiveFocus()); + QTRY_VERIFY(input2->hasActiveFocus()); + + QSignalSpy editingFinished2Spy(input2, SIGNAL(editingFinished())); + + input2->setFocus(true); + QTRY_VERIFY(!input1->hasActiveFocus()); + QTRY_VERIFY(input2->hasActiveFocus()); + + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + QTRY_COMPARE(editingFinished2Spy.count(), 1); + + QTRY_VERIFY(input1->hasActiveFocus()); + QTRY_VERIFY(!input2->hasActiveFocus()); +} + void tst_qquicktextedit::clipRect() { QQmlComponent component(&engine); @@ -5314,6 +5365,84 @@ void tst_qquicktextedit::textCached_QTBUG_41583() QVERIFY(!textedit->property("empty").toBool()); } +void tst_qquicktextedit::padding() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("padding.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); + QQuickTextEdit *obj = qobject_cast<QQuickTextEdit*>(root); + QVERIFY(obj != 0); + + qreal cw = obj->contentWidth(); + qreal ch = obj->contentHeight(); + + QVERIFY(cw > 0); + QVERIFY(ch > 0); + + QCOMPARE(obj->topPadding(), 20.0); + QCOMPARE(obj->leftPadding(), 30.0); + QCOMPARE(obj->rightPadding(), 40.0); + QCOMPARE(obj->bottomPadding(), 50.0); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setTopPadding(2.25); + QCOMPARE(obj->topPadding(), 2.25); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setLeftPadding(3.75); + QCOMPARE(obj->leftPadding(), 3.75); + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + + obj->setRightPadding(4.4); + QCOMPARE(obj->rightPadding(), 4.4); + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + + obj->setBottomPadding(1.11); + QCOMPARE(obj->bottomPadding(), 1.11); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setText("Qt"); + QVERIFY(obj->contentWidth() < cw); + QCOMPARE(obj->contentHeight(), ch); + cw = obj->contentWidth(); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->setFont(QFont("Courier", 96)); + QVERIFY(obj->contentWidth() > cw); + QVERIFY(obj->contentHeight() > ch); + cw = obj->contentWidth(); + ch = obj->contentHeight(); + + QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding()); + + obj->resetTopPadding(); + QCOMPARE(obj->topPadding(), 10.0); + obj->resetLeftPadding(); + QCOMPARE(obj->leftPadding(), 10.0); + obj->resetRightPadding(); + QCOMPARE(obj->rightPadding(), 10.0); + obj->resetBottomPadding(); + QCOMPARE(obj->bottomPadding(), 10.0); + + obj->resetPadding(); + QCOMPARE(obj->padding(), 0.0); + QCOMPARE(obj->topPadding(), 0.0); + QCOMPARE(obj->leftPadding(), 0.0); + QCOMPARE(obj->rightPadding(), 0.0); + QCOMPARE(obj->bottomPadding(), 0.0); + + delete root; +} + QTEST_MAIN(tst_qquicktextedit) #include "tst_qquicktextedit.moc" diff --git a/tests/auto/quick/qquicktextinput/data/padding.qml b/tests/auto/quick/qquicktextinput/data/padding.qml new file mode 100644 index 0000000000..23bfe20f22 --- /dev/null +++ b/tests/auto/quick/qquicktextinput/data/padding.qml @@ -0,0 +1,12 @@ +import QtQuick 2.6 + +TextInput { + width: 200; height: 200 + text: "Hello Qt" + + padding: 10 + topPadding: 20 + leftPadding: 30 + rightPadding: 40 + bottomPadding: 50 +} diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index 74aba5b4c7..2c6003998e 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -225,6 +225,7 @@ private slots: void baselineOffset(); void ensureVisible(); + void padding(); private: void simulateKey(QWindow *, int key); @@ -6371,25 +6372,25 @@ Q_DECLARE_METATYPE(ExpectedBaseline) static qreal expectedBaselineTop(QQuickTextInput *item) { QFontMetricsF fm(item->font()); - return fm.ascent(); + return fm.ascent() + item->topPadding(); } static qreal expectedBaselineBottom(QQuickTextInput *item) { QFontMetricsF fm(item->font()); - return item->height() - item->contentHeight() + fm.ascent(); + return item->height() - item->contentHeight() - item->bottomPadding() + fm.ascent(); } static qreal expectedBaselineCenter(QQuickTextInput *item) { QFontMetricsF fm(item->font()); - return ((item->height() - item->contentHeight()) / 2) + fm.ascent(); + return ((item->height() - item->contentHeight() - item->topPadding() - item->bottomPadding()) / 2) + fm.ascent() + item->topPadding(); } static qreal expectedBaselineMultilineBottom(QQuickTextInput *item) { QFontMetricsF fm(item->font()); - return item->height() - item->contentHeight() + fm.ascent(); + return item->height() - item->contentHeight() - item->bottomPadding() + fm.ascent(); } void tst_qquicktextinput::baselineOffset_data() @@ -6434,6 +6435,41 @@ void tst_qquicktextinput::baselineOffset_data() << -1. << &expectedBaselineMultilineBottom << &expectedBaselineBottom; + + QTest::newRow("padding") + << "Typography" + << QByteArray("topPadding: 10; bottomPadding: 20") + << -1. + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("top align with padding") + << "Typography" + << QByteArray("height: 200; verticalAlignment: Text.AlignTop; topPadding: 10; bottomPadding: 20") + << -1. + << &expectedBaselineTop + << &expectedBaselineTop; + + QTest::newRow("bottom align with padding") + << "Typography" + << QByteArray("height: 200; verticalAlignment: Text.AlignBottom; topPadding: 10; bottomPadding: 20") + << 100. + << &expectedBaselineBottom + << &expectedBaselineBottom; + + QTest::newRow("center align with padding") + << "Typography" + << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter; topPadding: 10; bottomPadding: 20") + << 100. + << &expectedBaselineCenter + << &expectedBaselineCenter; + + QTest::newRow("multiline bottom aligned with padding") + << "The quick brown fox jumps over the lazy dog" + << QByteArray("height: 200; width: 30; verticalAlignment: Text.AlignBottom; wrapMode: TextInput.WordWrap; topPadding: 10; bottomPadding: 20") + << -1. + << &expectedBaselineMultilineBottom + << &expectedBaselineBottom; } void tst_qquicktextinput::baselineOffset() @@ -6446,7 +6482,7 @@ void tst_qquicktextinput::baselineOffset() QQmlComponent component(&engine); component.setData( - "import QtQuick 2.0\n" + "import QtQuick 2.6\n" "TextInput {\n" + bindings + "\n" "}", QUrl()); @@ -6511,6 +6547,85 @@ void tst_qquicktextinput::ensureVisible() QCOMPARE(input->boundingRect().height(), line.height()); } +void tst_qquicktextinput::padding() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("padding.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); + QQuickTextInput *obj = qobject_cast<QQuickTextInput*>(root); + QVERIFY(obj != 0); + + qreal cw = obj->contentWidth(); + qreal ch = obj->contentHeight(); + + QVERIFY(cw > 0); + QVERIFY(ch > 0); + + QCOMPARE(obj->padding(), 10.0); + QCOMPARE(obj->topPadding(), 20.0); + QCOMPARE(obj->leftPadding(), 30.0); + QCOMPARE(obj->rightPadding(), 40.0); + QCOMPARE(obj->bottomPadding(), 50.0); + + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->setTopPadding(2.25); + QCOMPARE(obj->topPadding(), 2.25); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->setLeftPadding(3.75); + QCOMPARE(obj->leftPadding(), 3.75); + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + + obj->setRightPadding(4.4); + QCOMPARE(obj->rightPadding(), 4.4); + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + + obj->setBottomPadding(1.11); + QCOMPARE(obj->bottomPadding(), 1.11); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->setText("Qt"); + QVERIFY(obj->contentWidth() < cw); + QCOMPARE(obj->contentHeight(), ch); + cw = obj->contentWidth(); + + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->setFont(QFont("Courier", 96)); + QVERIFY(obj->contentWidth() > cw); + QVERIFY(obj->contentHeight() > ch); + cw = obj->contentWidth(); + ch = obj->contentHeight(); + + QCOMPARE(obj->implicitWidth(), qCeil(cw) + obj->leftPadding() + obj->rightPadding()); + QCOMPARE(obj->implicitHeight(), qCeil(ch) + obj->topPadding() + obj->bottomPadding()); + + obj->resetTopPadding(); + QCOMPARE(obj->topPadding(), 10.0); + obj->resetLeftPadding(); + QCOMPARE(obj->leftPadding(), 10.0); + obj->resetRightPadding(); + QCOMPARE(obj->rightPadding(), 10.0); + obj->resetBottomPadding(); + QCOMPARE(obj->bottomPadding(), 10.0); + + obj->resetPadding(); + QCOMPARE(obj->padding(), 0.0); + QCOMPARE(obj->topPadding(), 0.0); + QCOMPARE(obj->leftPadding(), 0.0); + QCOMPARE(obj->rightPadding(), 0.0); + QCOMPARE(obj->bottomPadding(), 0.0); + + delete root; +} + QTEST_MAIN(tst_qquicktextinput) #include "tst_qquicktextinput.moc" diff --git a/tests/auto/quick/qquickview/data/error2.qml b/tests/auto/quick/qquickview/data/error2.qml new file mode 100644 index 0000000000..1d754b64f0 --- /dev/null +++ b/tests/auto/quick/qquickview/data/error2.qml @@ -0,0 +1,4 @@ +import QtQuick.Window 2.0 + +Window { +} diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp index a980c69140..7ee24bf3d4 100644 --- a/tests/auto/quick/qquickview/tst_qquickview.cpp +++ b/tests/auto/quick/qquickview/tst_qquickview.cpp @@ -187,6 +187,15 @@ void tst_QQuickView::errors() QVERIFY(view.status() == QQuickView::Error); QVERIFY(view.errors().count() == 1); } + + { + QQuickView view; + QQmlTestMessageHandler messageHandler; + view.setSource(testFileUrl("error2.qml")); + QVERIFY(view.status() == QQuickView::Error); + QVERIFY(view.errors().count() == 1); + view.show(); + } } void tst_QQuickView::engine() diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 7e59810cd8..02728dfb09 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -64,8 +64,8 @@ #include <cstdlib> #define VERSION_MAJ 1 -#define VERSION_MIN 0 -#define VERSION_STR "1.0" +#define VERSION_MIN 1 +#define VERSION_STR "1.1" #define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms @@ -251,11 +251,10 @@ void printVersion() void printUsage() { - printf("Usage: qml [options] [files]\n"); + printf("Usage: qml [options] [files] [-- args]\n"); printf("\n"); - printf("Any argument ending in .qml will be treated as a QML file to be loaded.\n"); + printf("Any unknown argument before '--' will be treated as a QML file to be loaded.\n"); printf("Any number of QML files can be loaded. They will share the same engine.\n"); - printf("Any argument which is not a recognized option and which does not end in .qml will be ignored.\n"); printf("'gui' application type is only available if the QtGui module is available.\n"); printf("'widget' application type is only available if the QtWidgets module is available.\n"); printf("\n"); @@ -398,7 +397,7 @@ int main(int argc, char *argv[]) //Handle main arguments QStringList argList = app->arguments(); - for (int i = 0; i < argList.count(); i++) { + for (int i = 1; i < argList.count(); i++) { const QString &arg = argList[i]; if (arg == QLatin1String("-quiet")) quietMode = true; @@ -440,9 +439,7 @@ int main(int argc, char *argv[]) dummyDir = argList[i+1]; i++; } else { - //If it ends in .qml, treat it as a file. Else ignore it - if (arg.endsWith(".qml")) - files << arg; + files << arg; } } |