Merge remote-tracking branch 'origin/5.5' into dev
Conflicts: tests/auto/qml/qqmlitemmodels/testtypes.h Change-Id: I2f2f3f47fd873ddd4fd027414654a861b56357f4
This commit is contained in:
commit
c8427a542b
|
@ -36,6 +36,7 @@
|
|||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \class QQmlAbstractProfilerAdapter
|
||||
* \inmodule QtQml
|
||||
* Abstract base class for all adapters between profilers and the QQmlProfilerService. Adapters have
|
||||
|
@ -45,6 +46,7 @@ QT_BEGIN_NAMESPACE
|
|||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::dataRequested()
|
||||
* Signals that data has been requested by the \c QQmlProfilerService. This signal should be
|
||||
* connected to a slot in the profiler and the profiler should then transfer its currently available
|
||||
|
@ -52,6 +54,7 @@ QT_BEGIN_NAMESPACE
|
|||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn qint64 QQmlAbstractProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
|
||||
* Append the messages up to the timestamp \a until, chronologically sorted, to \a messages. Keep
|
||||
* track of the messages already sent and with each subsequent call to this method start with the
|
||||
|
@ -64,10 +67,11 @@ QT_BEGIN_NAMESPACE
|
|||
*/
|
||||
|
||||
/*!
|
||||
* \fn void QQmlAbstractProfilerAdapter::startProfiling()
|
||||
* Emits either \c profilingEnabled() or \c profilingEnabledWhileWaiting(), depending on \c waiting.
|
||||
* If the profiler's thread is waiting for an initial start signal we can emit the signal over a
|
||||
* \c Qt::DirectConnection to avoid the delay of the event loop.
|
||||
* \internal
|
||||
* Emits either \c profilingEnabled(quint64) or \c profilingEnabledWhileWaiting(quint64), depending
|
||||
* on \c waiting. If the profiler's thread is waiting for an initial start signal, we can emit the
|
||||
* signal over a Qt::DirectConnection to avoid the delay of the event loop. The \a features are
|
||||
* passed on to the signal.
|
||||
*/
|
||||
void QQmlAbstractProfilerAdapter::startProfiling(quint64 features)
|
||||
{
|
||||
|
@ -79,10 +83,10 @@ void QQmlAbstractProfilerAdapter::startProfiling(quint64 features)
|
|||
}
|
||||
|
||||
/*!
|
||||
* \fn void QQmlAbstractProfilerAdapter::stopProfiling()
|
||||
* \internal
|
||||
* Emits either \c profilingDisabled() or \c profilingDisabledWhileWaiting(), depending on
|
||||
* \c waiting. If the profiler's thread is waiting for an initial start signal we can emit the
|
||||
* signal over a \c Qt::DirectConnection to avoid the delay of the event loop. This should trigger
|
||||
* \c waiting. If the profiler's thread is waiting for an initial start signal, we can emit the
|
||||
* signal over a Qt::DirectConnection to avoid the delay of the event loop. This should trigger
|
||||
* the profiler to report its collected data and subsequently delete it.
|
||||
*/
|
||||
void QQmlAbstractProfilerAdapter::stopProfiling() {
|
||||
|
@ -94,56 +98,67 @@ void QQmlAbstractProfilerAdapter::stopProfiling() {
|
|||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn bool QQmlAbstractProfilerAdapter::isRunning() const
|
||||
* Returns if the profiler is currently running. The profiler is considered to be running after
|
||||
* \c startProfiling() has been called until \c stopProfiling() is called. That is independent of
|
||||
* \c waiting. The profiler may be running and waiting at the same time.
|
||||
* \c startProfiling(quint64) has been called until \c stopProfiling() is called. That is
|
||||
* independent of \c waiting. The profiler may be running and waiting at the same time.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::profilingDisabled()
|
||||
* This signal is emitted if \c stopProfiling() is called while the profiler is not considered to
|
||||
* be waiting. The profiler is expected to handle the signal asynchronously.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting()
|
||||
* This signal is emitted if \c stopProfiling() is called while the profiler is considered to be
|
||||
* waiting. In many cases this signal can be connected with a \c Qt::DirectConnection.
|
||||
* waiting. In many cases this signal can be connected with a Qt::DirectConnection.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn void QQmlAbstractProfilerAdapter::profilingEnabled()
|
||||
* This signal is emitted if \c startProfiling() is called while the profiler is not considered to
|
||||
* be waiting. The profiler is expected to handle the signal asynchronously.
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::profilingEnabled(quint64 features)
|
||||
* This signal is emitted if \c startProfiling(quint64) is called while the profiler is not
|
||||
* considered to be waiting. The profiler is expected to handle the signal asynchronously. The
|
||||
* \a features are passed on from \c startProfiling(quint64).
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn void QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting()
|
||||
* This signal is emitted if \c startProfiling() is called while the profiler is considered to be
|
||||
* waiting. In many cases this signal can be connected with a \c Qt::DirectConnection. By starting
|
||||
* the profiler synchronously when the QML engine starts instead of waiting for the first iteration
|
||||
* of the event loop the engine startup can be profiled.
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting(quint64 features)
|
||||
* This signal is emitted if \c startProfiling(quint64) is called while the profiler is considered
|
||||
* to be waiting. In many cases this signal can be connected with a Qt::DirectConnection. By
|
||||
* starting the profiler synchronously when the QML engine starts instead of waiting for the first
|
||||
* iteration of the event loop the engine startup can be profiled. The \a features are passed on
|
||||
* from \c startProfiling(quint64).
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::referenceTimeKnown(const QElapsedTimer &timer)
|
||||
* This signal is used to synchronize the profiler's timer to the QQmlProfilerservice's. The
|
||||
* profiler is expected to save \a timer and use it for timestamps on its data.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::synchronize(const QElapsedTimer &timer)
|
||||
* Synchronize the profiler to \a timer. This emits \c referenceTimeKnown().
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::reportData()
|
||||
* Make the profiler report its current data without stopping the collection. The same (and
|
||||
* additional) data can later be requested again with \c stopProfiling() or \c reportData().
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::startWaiting()
|
||||
* Consider the profiler to be waiting from now on. While the profiler is waiting it can be directly
|
||||
* accessed even if it is in a different thread. This method should only be called if it is actually
|
||||
|
@ -151,6 +166,7 @@ void QQmlAbstractProfilerAdapter::stopProfiling() {
|
|||
*/
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \fn void QQmlAbstractProfilerAdapter::stopWaiting()
|
||||
* Consider the profiler not to be waiting anymore. If it lives in a different threads any requests
|
||||
* for it have to be done via a queued connection then.
|
||||
|
|
|
@ -43,17 +43,14 @@ documentation about
|
|||
|
||||
\section1 Contents of a Module Definition qmldir File
|
||||
|
||||
A \c qmldir file which defines a module is a plain-text file which consists
|
||||
of the following commands:
|
||||
A \c qmldir file is a plain-text file that contains
|
||||
the following commands:
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Command
|
||||
\li Syntax
|
||||
\li Usage
|
||||
|
||||
\row
|
||||
\li Module Identifier Directive
|
||||
\li
|
||||
\code
|
||||
module <ModuleIdentifier>
|
||||
|
@ -73,14 +70,14 @@ module ExampleModule
|
|||
\endcode
|
||||
|
||||
\row
|
||||
\li Object Type Declaration
|
||||
\li
|
||||
\code
|
||||
<TypeName> <InitialVersion> <File>
|
||||
[singleton] <TypeName> <InitialVersion> <File>
|
||||
\endcode
|
||||
\li Declares a \l{qtqml-typesystem-objecttypes.html}{QML object type}
|
||||
to be made available by the module.
|
||||
\list
|
||||
\li \c [singleton] Optional. Used to declare a singleton type.
|
||||
\li \c <TypeName> is the type being made available
|
||||
\li \c <InitialVersion> is the module version for which the type is to be made available
|
||||
\li \c <File> is the (relative) file name of the QML file that defines the type
|
||||
|
@ -89,14 +86,36 @@ module ExampleModule
|
|||
Zero or more object type declarations may exist in the \c qmldir
|
||||
file, however each object type must have a unique type name within
|
||||
any particular version of the module.
|
||||
\note To declare a \c singleton type, the QML file defining the
|
||||
type must include the \c {pragma Singleton} statement.
|
||||
|
||||
Example:
|
||||
\code
|
||||
MyCustomType 1.0 MyCustomType.qml
|
||||
//Style.qml with custom singleton type definition
|
||||
pragma Singleton
|
||||
import QtQuick 2.0
|
||||
|
||||
QtObject {
|
||||
property int textSize: 20
|
||||
property color textColor: "green"
|
||||
}
|
||||
|
||||
// qmldir declaring the singleton type
|
||||
module CustomStyles
|
||||
singleton Style 1.0 Style.qml
|
||||
|
||||
// singleton type in use
|
||||
import QtQuick 2.0
|
||||
import CustomStyles 1.0
|
||||
|
||||
Text {
|
||||
font.pixelSize: Style.textSize
|
||||
color: Style.textColor
|
||||
text: "Hello World"
|
||||
}
|
||||
\endcode
|
||||
|
||||
\row
|
||||
\li Internal Object Type Declaration
|
||||
\li
|
||||
\code
|
||||
internal <TypeName> <File>
|
||||
|
@ -119,7 +138,6 @@ internal MyPrivateType MyPrivateType.qml
|
|||
load the non-exported type.
|
||||
|
||||
\row
|
||||
\li JavaScript Resource Declaration
|
||||
\li
|
||||
\code
|
||||
<ResourceIdentifier> <InitialVersion> <File>
|
||||
|
@ -143,7 +161,6 @@ MyScript 1.0 MyScript.js
|
|||
{Importing JavaScript Resources In QML} for more information.
|
||||
|
||||
\row
|
||||
\li C++ Plugin Declaration
|
||||
\li
|
||||
\code
|
||||
plugin <Name> [<Path>]
|
||||
|
@ -178,7 +195,6 @@ plugin <Name> [<Path>]
|
|||
plugin MyPluginLibrary
|
||||
\endcode
|
||||
\row
|
||||
\li C++ Plugin Class
|
||||
\li
|
||||
\code
|
||||
classname <C++ plugin class>
|
||||
|
@ -191,7 +207,6 @@ classname <C++ plugin class>
|
|||
this information.
|
||||
|
||||
\row
|
||||
\li Type Information Description File Declaration
|
||||
\li
|
||||
\code
|
||||
typeinfo <File>
|
||||
|
@ -210,7 +225,6 @@ typeinfo mymodule.qmltypes
|
|||
as code completion for the types defined in your plugins.
|
||||
|
||||
\row
|
||||
\li Dependency Declaration
|
||||
\li
|
||||
\code
|
||||
depends <ModuleIdentifier> <InitialVersion>
|
||||
|
@ -229,7 +243,6 @@ depends MyOtherModule 1.0
|
|||
to include the other modules in application packages.
|
||||
|
||||
\row
|
||||
\li Comment
|
||||
\li
|
||||
\code
|
||||
# <Comment>
|
||||
|
@ -242,10 +255,9 @@ depends MyOtherModule 1.0
|
|||
\endcode
|
||||
|
||||
\row
|
||||
\li designersupported
|
||||
\li
|
||||
\code
|
||||
designersupported
|
||||
\code
|
||||
designersupported
|
||||
\endcode
|
||||
|
||||
\li Set this property if the plugin is supported by Qt Quick Designer.
|
||||
|
|
|
@ -210,7 +210,6 @@ InstructionSelection::~InstructionSelection()
|
|||
void InstructionSelection::run(int functionIndex)
|
||||
{
|
||||
IR::Function *function = irModule->functions[functionIndex];
|
||||
QVector<Lookup> lookups;
|
||||
qSwap(_function, function);
|
||||
|
||||
IR::Optimizer opt(_function);
|
||||
|
|
|
@ -1390,11 +1390,11 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
|
|||
case QMetaType::UShort:
|
||||
return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(ptr));
|
||||
case QMetaType::Char:
|
||||
return QV4::Encode((int)*reinterpret_cast<const char*>(ptr));
|
||||
return newString(QChar::fromLatin1(*reinterpret_cast<const char *>(ptr)))->asReturnedValue();
|
||||
case QMetaType::UChar:
|
||||
return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(ptr));
|
||||
return newString(QChar::fromLatin1(*reinterpret_cast<const unsigned char *>(ptr)))->asReturnedValue();
|
||||
case QMetaType::QChar:
|
||||
return QV4::Encode((int)(*reinterpret_cast<const QChar*>(ptr)).unicode());
|
||||
return newString(*reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
|
||||
case QMetaType::QDateTime:
|
||||
return QV4::Encode(newDateObject(*reinterpret_cast<const QDateTime *>(ptr)));
|
||||
case QMetaType::QDate:
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
#include <private/qv4scopedvalue_p.h>
|
||||
#include "qv4runtime_p.h"
|
||||
#include "qv4objectiterator_p.h"
|
||||
#include <private/qqmlvaluetypewrapper_p.h>
|
||||
#include <private/qqmlmodelindexvaluetype_p.h>
|
||||
#include <QtCore/qabstractitemmodel.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -71,7 +74,9 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
|
|||
F(bool, Bool, QList<bool>, false) \
|
||||
F(QString, String, QList<QString>, QString()) \
|
||||
F(QString, QString, QStringList, QString()) \
|
||||
F(QUrl, Url, QList<QUrl>, QUrl())
|
||||
F(QUrl, Url, QList<QUrl>, QUrl()) \
|
||||
F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
|
||||
F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
|
||||
|
||||
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
|
||||
{
|
||||
|
@ -88,6 +93,19 @@ static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, co
|
|||
return engine->newString(element.toString())->asReturnedValue();
|
||||
}
|
||||
|
||||
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QModelIndex &element)
|
||||
{
|
||||
const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(QMetaType::QModelIndex);
|
||||
return QV4::QQmlValueTypeWrapper::create(engine, QVariant(element), vtmo, QMetaType::QModelIndex);
|
||||
}
|
||||
|
||||
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QItemSelectionRange &element)
|
||||
{
|
||||
int metaTypeId = qMetaTypeId<QItemSelectionRange>();
|
||||
const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(metaTypeId);
|
||||
return QV4::QQmlValueTypeWrapper::create(engine, QVariant::fromValue(element), vtmo, metaTypeId);
|
||||
}
|
||||
|
||||
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *, qreal element)
|
||||
{
|
||||
return QV4::Encode(element);
|
||||
|
@ -113,6 +131,16 @@ static QString convertElementToString(const QUrl &element)
|
|||
return element.toString();
|
||||
}
|
||||
|
||||
static QString convertElementToString(const QModelIndex &element)
|
||||
{
|
||||
return reinterpret_cast<const QQmlModelIndexValueType *>(&element)->toString();
|
||||
}
|
||||
|
||||
static QString convertElementToString(const QItemSelectionRange &element)
|
||||
{
|
||||
return reinterpret_cast<const QQmlItemSelectionRangeValueType *>(&element)->toString();
|
||||
}
|
||||
|
||||
static QString convertElementToString(qreal element)
|
||||
{
|
||||
QString qstr;
|
||||
|
@ -145,6 +173,22 @@ template <> QUrl convertValueToElement(const Value &value)
|
|||
return QUrl(value.toQString());
|
||||
}
|
||||
|
||||
template <> QModelIndex convertValueToElement(const Value &value)
|
||||
{
|
||||
const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>();
|
||||
if (v)
|
||||
return v->toVariant().toModelIndex();
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
template <> QItemSelectionRange convertValueToElement(const Value &value)
|
||||
{
|
||||
const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>();
|
||||
if (v)
|
||||
return v->toVariant().value<QItemSelectionRange>();
|
||||
return QItemSelectionRange();
|
||||
}
|
||||
|
||||
template <> qreal convertValueToElement(const Value &value)
|
||||
{
|
||||
return value.toNumber();
|
||||
|
@ -541,6 +585,12 @@ DEFINE_OBJECT_VTABLE(QQmlIntList);
|
|||
typedef QQmlSequence<QList<QUrl> > QQmlUrlList;
|
||||
template<>
|
||||
DEFINE_OBJECT_VTABLE(QQmlUrlList);
|
||||
typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList;
|
||||
template<>
|
||||
DEFINE_OBJECT_VTABLE(QQmlQModelIndexList);
|
||||
typedef QQmlSequence<QItemSelection> QQmlQItemSelectionRangeList;
|
||||
template<>
|
||||
DEFINE_OBJECT_VTABLE(QQmlQItemSelectionRangeList);
|
||||
typedef QQmlSequence<QList<bool> > QQmlBoolList;
|
||||
template<>
|
||||
DEFINE_OBJECT_VTABLE(QQmlBoolList);
|
||||
|
|
|
@ -78,7 +78,6 @@ class QQmlExpression;
|
|||
class QQmlContext;
|
||||
class QQmlType;
|
||||
class QUrl;
|
||||
class QScriptContext;
|
||||
class QNetworkAccessManager;
|
||||
class QQmlNetworkAccessManagerFactory;
|
||||
class QQmlIncubationController;
|
||||
|
|
|
@ -1387,8 +1387,30 @@ bool QQmlPropertyPrivate::write(QObject *object,
|
|||
|
||||
bool ok = false;
|
||||
QVariant v;
|
||||
if (variantType == QVariant::String)
|
||||
v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
|
||||
if (variantType == QVariant::String) {
|
||||
const QString &str = value.toString();
|
||||
const bool targetIsChar = (propertyType == qMetaTypeId<QChar>()
|
||||
|| propertyType == qMetaTypeId<char>()
|
||||
|| propertyType == qMetaTypeId<unsigned char>());
|
||||
// If the string contains only one character and the target is a char, try converting it.
|
||||
if (targetIsChar) {
|
||||
if (str.size() != 1)
|
||||
return false; // We can only convert if the string contains exactly one character.
|
||||
|
||||
const QChar &qChar = str.at(0);
|
||||
if (propertyType == qMetaTypeId<QChar>()) {
|
||||
v = qChar;
|
||||
ok = true;
|
||||
} else if (propertyType == qMetaTypeId<char>() || propertyType == qMetaTypeId<unsigned char>()) {
|
||||
const char c = qChar.toLatin1();
|
||||
v = c;
|
||||
ok = (qChar == c);
|
||||
}
|
||||
} else {
|
||||
v = QQmlStringConverters::variantFromString(str, propertyType, &ok);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
v = value;
|
||||
if (v.convert(propertyType)) {
|
||||
|
|
|
@ -64,9 +64,7 @@ QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
|
|||
valueTypes[ii] = 0;
|
||||
|
||||
// See types wrapped in qqmlmodelindexvaluetype_p.h
|
||||
qRegisterMetaType<QModelIndexList>();
|
||||
qRegisterMetaType<QItemSelectionRange>();
|
||||
qRegisterMetaType<QItemSelection>();
|
||||
}
|
||||
|
||||
QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
|
||||
|
@ -112,18 +110,14 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
|
|||
case QVariant::PersistentModelIndex:
|
||||
return &QQmlPersistentModelIndexValueType::staticMetaObject;
|
||||
default:
|
||||
if (t == qMetaTypeId<QItemSelectionRange>())
|
||||
return &QQmlItemSelectionRangeValueType::staticMetaObject;
|
||||
|
||||
if (const QMetaObject *mo = QQml_valueTypeProvider()->metaObjectForMetaType(t))
|
||||
return mo;
|
||||
break;
|
||||
}
|
||||
|
||||
if (t == qMetaTypeId<QModelIndexList>())
|
||||
return &QQmlModelIndexListValueType::staticMetaObject;
|
||||
else if (t == qMetaTypeId<QItemSelectionRange>())
|
||||
return &QQmlItemSelectionRangeValueType::staticMetaObject;
|
||||
else if (t == qMetaTypeId<QItemSelection>())
|
||||
return &QQmlItemSelectionValueType::staticMetaObject;
|
||||
|
||||
QMetaType metaType(t);
|
||||
if (metaType.flags() & QMetaType::IsGadget)
|
||||
return metaType.metaObject();
|
||||
|
|
|
@ -60,6 +60,17 @@
|
|||
should not store any QModelIndex. You can, however, store QPersistentModelIndexes
|
||||
in a safe way.
|
||||
|
||||
\section1 QModelIndexList
|
||||
|
||||
\l QModelIndexList is exposed in QML as a JavaScript array. Conversions are
|
||||
automatically made from and to C++. In fact, any JavaScript array can be
|
||||
converted back to QModelIndexList, with non-QModelIndex objects replaced by
|
||||
invalid QModelIndexes.
|
||||
|
||||
\note QModelIndex to QPersistentModelIndex conversion happens when accessing
|
||||
the array elements because any QModelIndexList property retains reference
|
||||
semantics when exposed this way.
|
||||
|
||||
\section1 \l QItemSelectionRange
|
||||
|
||||
\list
|
||||
|
@ -87,29 +98,13 @@
|
|||
\li QItemSelectionRange \b{intersected}(QItemSelectionRange other)
|
||||
\endlist
|
||||
|
||||
\section1 \l QModelIndexList and \l QItemSelection
|
||||
\section1 QItemSelection
|
||||
|
||||
Both \l QModelIndexList and \l QItemSelection expose the following properties
|
||||
and functions as part of their \l QList API:
|
||||
Similarly to QModelIndexList, \l QItemSelection is exposed in QML as a JavaScript
|
||||
array of QItemSelectionRanges. Conversions are automatically made from and to C++.
|
||||
In fact, any JavaScript array can be converted back to QItemSelection, with
|
||||
non-QItemSelectionRange objects replaced by empty QItemSelectionRanges.
|
||||
|
||||
\list
|
||||
\li \b length : int
|
||||
\li object \b{at}(int i)
|
||||
\li void \b{append}(object o)
|
||||
\li void \b{prepend}(o)
|
||||
\li void \b{insert}(int i, object o)
|
||||
\li void \b{removeFirst}()
|
||||
\li void \b{removeLast}()
|
||||
\li void \b{removeAt}(int i)
|
||||
\endlist
|
||||
|
||||
In addition, \l QItemSelection also exposes the following functions:
|
||||
|
||||
\list
|
||||
\li void \b{select}(QModelIndex topLeft, QModelIndex bottomRight)
|
||||
\li bool \b{contains}(QModelIndex index)
|
||||
\li void \b{merge}(QItemSelection other, QItemSelectionModel::SelectionFlags command)
|
||||
\endlist
|
||||
|
||||
\sa ItemSelectionModel
|
||||
*/
|
||||
|
|
|
@ -150,63 +150,6 @@ public:
|
|||
inline bool isEmpty() const { return v.isEmpty(); }
|
||||
};
|
||||
|
||||
template<typename V, typename T>
|
||||
QString q_listToString(const QList<T> &list, const QLatin1String &typeName)
|
||||
{
|
||||
QString result = typeName;
|
||||
result.append(QLatin1Char('('));
|
||||
for (typename QList<T>::size_type i = 0; i < list.count(); ++i) {
|
||||
if (i)
|
||||
result.append(QLatin1String(", "));
|
||||
result.append(reinterpret_cast<const V *>(&list.at(i))->toString());
|
||||
}
|
||||
return result.append(QLatin1Char(')'));
|
||||
}
|
||||
|
||||
// Invokable QList<T> API forwarding for value types
|
||||
#define QLISTVALUETYPE_QML_API(T) \
|
||||
Q_PROPERTY(int length READ length FINAL) \
|
||||
Q_INVOKABLE T at(int i) { return v.at(i); } \
|
||||
Q_INVOKABLE void append(const T &o) { v.append(o); } \
|
||||
Q_INVOKABLE void prepend(const T &o) { v.prepend(o); } \
|
||||
Q_INVOKABLE void insert(int i, const T &o) { v.insert(i, o); } \
|
||||
Q_INVOKABLE void removeFirst() { v.removeFirst(); } \
|
||||
Q_INVOKABLE void removeLast() { v.removeLast(); } \
|
||||
Q_INVOKABLE void removeAt(int i) { v.removeAt(i); } \
|
||||
int length() const { return v.length(); }
|
||||
|
||||
struct QQmlModelIndexListValueType
|
||||
{
|
||||
QModelIndexList v;
|
||||
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QString toString()
|
||||
{ return q_listToString<QQmlModelIndexValueType>(v, QLatin1String("")); }
|
||||
|
||||
QLISTVALUETYPE_QML_API(QModelIndex)
|
||||
};
|
||||
|
||||
struct QQmlItemSelectionValueType
|
||||
{
|
||||
QItemSelection v;
|
||||
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QString toString()
|
||||
{ return q_listToString<QQmlItemSelectionRangeValueType>(v, QLatin1String("QItemSelection")); }
|
||||
Q_INVOKABLE void select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
|
||||
{ v.select(topLeft, bottomRight); }
|
||||
Q_INVOKABLE bool contains(const QModelIndex &index) const
|
||||
{ return v.contains(index); }
|
||||
Q_INVOKABLE void merge(const QItemSelection &other, int command)
|
||||
{ v.merge(other, QItemSelectionModel::SelectionFlags(command)); }
|
||||
|
||||
QLISTVALUETYPE_QML_API(QItemSelectionRange)
|
||||
};
|
||||
|
||||
#undef QLISTVALUETYPE_INVOKABLE_API
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -5,8 +5,8 @@ QT = core
|
|||
QT_PRIVATE = testlib-private quick qml-private gui core-private
|
||||
|
||||
# Testlib is only a private dependency, which results in our users not
|
||||
# inheriting CONFIG+=console transitively. Make it explicit.
|
||||
MODULE_CONFIG = console
|
||||
# inheriting testlibs's MODULE_CONFIG transitively. Make it explicit.
|
||||
MODULE_CONFIG += $${QT.testlib.CONFIG}
|
||||
|
||||
qtHaveModule(widgets) {
|
||||
QT += widgets
|
||||
|
|
|
@ -1010,6 +1010,9 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp
|
|||
bool rejectY = false;
|
||||
bool rejectX = false;
|
||||
|
||||
bool keepY = q->yflick();
|
||||
bool keepX = q->xflick();
|
||||
|
||||
bool stealY = false;
|
||||
bool stealX = false;
|
||||
if (eventType == QEvent::MouseMove) {
|
||||
|
@ -1082,6 +1085,11 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp
|
|||
}
|
||||
if (!rejectY && overThreshold)
|
||||
stealY = true;
|
||||
|
||||
if ((newY >= minY && vData.pressPos == minY && vData.move.value() == minY && dy > 0)
|
||||
|| (newY <= maxY && vData.pressPos == maxY && vData.move.value() == maxY && dy < 0)) {
|
||||
keepY = false;
|
||||
}
|
||||
}
|
||||
vData.previousDragDelta = dy;
|
||||
}
|
||||
|
@ -1144,13 +1152,19 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp
|
|||
|
||||
if (!rejectX && overThreshold)
|
||||
stealX = true;
|
||||
|
||||
if ((newX >= minX && vData.pressPos == minX && vData.move.value() == minX && dx > 0)
|
||||
|| (newX <= maxX && vData.pressPos == maxX && vData.move.value() == maxX && dx < 0)) {
|
||||
keepX = false;
|
||||
}
|
||||
}
|
||||
hData.previousDragDelta = dx;
|
||||
}
|
||||
|
||||
stealMouse = stealX || stealY;
|
||||
if (stealMouse) {
|
||||
q->setKeepMouseGrab(true);
|
||||
if ((stealX && keepX) || (stealY && keepY))
|
||||
q->setKeepMouseGrab(true);
|
||||
clearDelayedPress();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,14 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QQuickTextNodeEngine::BinaryTreeNodeKey::BinaryTreeNodeKey(BinaryTreeNode *node)
|
||||
: fontEngine(QRawFontPrivate::get(node->glyphRun.rawFont())->fontEngine)
|
||||
, clipNode(node->clipNode)
|
||||
, color(node->color.rgba())
|
||||
, selectionState(node->selectionState)
|
||||
{
|
||||
}
|
||||
|
||||
QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
|
||||
SelectionState selState,
|
||||
const QRectF &brect,
|
||||
|
@ -680,35 +688,34 @@ uint qHash(const QQuickTextNodeEngine::BinaryTreeNodeKey &key)
|
|||
void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularNodes,
|
||||
QList<BinaryTreeNode *> *imageNodes)
|
||||
{
|
||||
QMultiHash<BinaryTreeNodeKey, BinaryTreeNode *> map;
|
||||
QHash<BinaryTreeNodeKey, QList<BinaryTreeNode *> > map;
|
||||
|
||||
for (int i = 0; i < m_processedNodes.size(); ++i) {
|
||||
BinaryTreeNode *node = m_processedNodes.data() + i;
|
||||
|
||||
if (node->image.isNull()) {
|
||||
QRawFont rawFont = node->glyphRun.rawFont();
|
||||
QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont);
|
||||
QFontEngine *fontEngine = rawFontD->fontEngine;
|
||||
BinaryTreeNodeKey key(node);
|
||||
|
||||
BinaryTreeNodeKey key(fontEngine,
|
||||
node->clipNode,
|
||||
node->color.rgba(),
|
||||
int(node->selectionState));
|
||||
map.insertMulti(key, node);
|
||||
QList<BinaryTreeNode *> &nodes = map[key];
|
||||
if (nodes.isEmpty())
|
||||
regularNodes->append(node);
|
||||
|
||||
nodes.append(node);
|
||||
} else {
|
||||
imageNodes->append(node);
|
||||
}
|
||||
}
|
||||
|
||||
QMultiHash<BinaryTreeNodeKey, BinaryTreeNode *>::const_iterator it = map.constBegin();
|
||||
while (it != map.constEnd()) {
|
||||
BinaryTreeNode *primaryNode = it.value();
|
||||
regularNodes->append(primaryNode);
|
||||
for (int i = 0; i < regularNodes->size(); ++i) {
|
||||
BinaryTreeNode *primaryNode = regularNodes->at(i);
|
||||
BinaryTreeNodeKey key(primaryNode);
|
||||
|
||||
const QList<BinaryTreeNode *> &nodes = map.value(key);
|
||||
Q_ASSERT(nodes.first() == primaryNode);
|
||||
|
||||
int count = 0;
|
||||
QMultiHash<BinaryTreeNodeKey, BinaryTreeNode *>::const_iterator jt;
|
||||
for (jt = it; jt != map.constEnd() && jt.key() == it.key(); ++jt)
|
||||
count += jt.value()->glyphRun.glyphIndexes().size();
|
||||
for (int j = 0; j < nodes.size(); ++j)
|
||||
count += nodes.at(j)->glyphRun.glyphIndexes().size();
|
||||
|
||||
if (count != primaryNode->glyphRun.glyphIndexes().size()) {
|
||||
QGlyphRun &glyphRun = primaryNode->glyphRun;
|
||||
|
@ -718,24 +725,21 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN
|
|||
QVector<QPointF> glyphPositions = glyphRun.positions();
|
||||
glyphPositions.reserve(count);
|
||||
|
||||
for (jt = it + 1; jt != map.constEnd() && jt.key() == it.key(); ++jt) {
|
||||
BinaryTreeNode *otherNode = jt.value();
|
||||
for (int j = 1; j < nodes.size(); ++j) {
|
||||
BinaryTreeNode *otherNode = nodes.at(j);
|
||||
glyphIndexes += otherNode->glyphRun.glyphIndexes();
|
||||
primaryNode->ranges += otherNode->ranges;
|
||||
|
||||
QVector<QPointF> otherPositions = otherNode->glyphRun.positions();
|
||||
for (int j = 0; j < otherPositions.size(); ++j)
|
||||
glyphPositions += otherPositions.at(j) + (otherNode->position - primaryNode->position);
|
||||
for (int k = 0; k < otherPositions.size(); ++k)
|
||||
glyphPositions += otherPositions.at(k) + (otherNode->position - primaryNode->position);
|
||||
}
|
||||
it = jt;
|
||||
|
||||
Q_ASSERT(glyphPositions.size() == count);
|
||||
Q_ASSERT(glyphIndexes.size() == count);
|
||||
|
||||
glyphRun.setGlyphIndexes(glyphIndexes);
|
||||
glyphRun.setPositions(glyphPositions);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,16 +104,7 @@ public:
|
|||
|
||||
struct BinaryTreeNodeKey
|
||||
{
|
||||
BinaryTreeNodeKey(QFontEngine *fe,
|
||||
QQuickDefaultClipNode *cn,
|
||||
QRgb col,
|
||||
int selState)
|
||||
: fontEngine(fe)
|
||||
, clipNode(cn)
|
||||
, color(col)
|
||||
, selectionState(selState)
|
||||
{
|
||||
}
|
||||
BinaryTreeNodeKey(BinaryTreeNode *node);
|
||||
|
||||
bool operator==(const BinaryTreeNodeKey &otherKey) const
|
||||
{
|
||||
|
|
|
@ -1868,19 +1868,23 @@ void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
|
|||
Qt::TouchPointStates states;
|
||||
for (int i = 0; i < event->touchPoints().count(); ++i) {
|
||||
const QTouchEvent::TouchPoint &tp = tpts.at(i);
|
||||
const QTouchEvent::TouchPoint &tp2 = delayedTouch->touchPoints().at(i);
|
||||
if (tp.id() != tp2.id()) {
|
||||
const QTouchEvent::TouchPoint &tpDelayed = delayedTouch->touchPoints().at(i);
|
||||
if (tp.id() != tpDelayed.id()) {
|
||||
mismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tp2.state() == Qt::TouchPointMoved && tp.state() == Qt::TouchPointStationary)
|
||||
if (tpDelayed.state() == Qt::TouchPointMoved && tp.state() == Qt::TouchPointStationary)
|
||||
tpts[i].setState(Qt::TouchPointMoved);
|
||||
tpts[i].setLastPos(tpDelayed.lastPos());
|
||||
tpts[i].setLastScenePos(tpDelayed.lastScenePos());
|
||||
tpts[i].setLastScreenPos(tpDelayed.lastScreenPos());
|
||||
tpts[i].setLastNormalizedPos(tpDelayed.lastNormalizedPos());
|
||||
|
||||
states |= tpts.at(i).state();
|
||||
}
|
||||
|
||||
// same touch event? then merge if so
|
||||
// matching touch event? then merge the new event into the old one
|
||||
if (!mismatch) {
|
||||
delayedTouch->setTouchPoints(tpts);
|
||||
delayedTouch->setTimestamp(event->timestamp());
|
||||
|
@ -1888,8 +1892,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
// otherwise; we need to deliver the delayed event first, and
|
||||
// then delay this one..
|
||||
// merging wasn't possible, so deliver the delayed event first, and then delay this one
|
||||
reallyDeliverTouchEvent(delayedTouch);
|
||||
delete delayedTouch;
|
||||
delayedTouch = new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints());
|
||||
|
|
|
@ -200,8 +200,8 @@ public:
|
|||
|
||||
protected:
|
||||
QQuickTransformAnimatorJob();
|
||||
void initialize(QQuickAnimatorController *controller);
|
||||
void nodeWasDestroyed();
|
||||
void initialize(QQuickAnimatorController *controller) Q_DECL_OVERRIDE;
|
||||
void nodeWasDestroyed() Q_DECL_OVERRIDE;
|
||||
void targetWasDeleted() Q_DECL_OVERRIDE;
|
||||
|
||||
Helper *m_helper;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import Test 1.0
|
||||
|
||||
ItemModelsTest {
|
||||
property var itemSelection
|
||||
property int count
|
||||
property bool contains: false
|
||||
property var itemSelectionBinding: itemSelection
|
||||
property var itemSelectionRead
|
||||
|
||||
function range(top, bottom, left, right, parent) {
|
||||
if (parent === undefined)
|
||||
|
@ -14,23 +15,15 @@ ItemModelsTest {
|
|||
}
|
||||
|
||||
onModelChanged: {
|
||||
itemSelection = createItemSelection()
|
||||
itemSelection.prepend(range(0, 0, 0, 5))
|
||||
itemSelection.append(range(0, 5, 0, 0))
|
||||
itemSelection = []
|
||||
itemSelection.push(range(0, 0, 0, 5))
|
||||
itemSelection.push(range(0, 5, 0, 0))
|
||||
for (var i = 0; i < 3; i++)
|
||||
itemSelection.insert(i, range(i, i + 1, i + 2, i + 3))
|
||||
itemSelection.splice(i, 0, range(i, i + 1, i + 2, i + 3))
|
||||
|
||||
var itemSelection2 = createItemSelection()
|
||||
for (i = 3; i < 6; i++)
|
||||
itemSelection2.select(model.index(i, i + 1), model.index(i + 2, i + 3))
|
||||
|
||||
itemSelection.merge(itemSelection2, 2 /*ItemSelectionModel.Select*/)
|
||||
itemSelectionRead = itemSelection
|
||||
|
||||
count = itemSelection.length
|
||||
contains = itemSelection.contains(model.index(0, 0))
|
||||
|
||||
itemSelection.removeAt(3)
|
||||
itemSelection.removeFirst()
|
||||
itemSelection.removeLast()
|
||||
contains = itemSelection.some(function (range, idx) { return range.contains(model.index(0, 0)) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
import Test 1.0
|
||||
|
||||
ItemModelsTest {
|
||||
property var modelIndexList
|
||||
property int count
|
||||
property var modelIndexListCopy
|
||||
property var modelIndexListRead
|
||||
property var modelIndexListBinding: modelIndexList
|
||||
property bool varPropIsArray
|
||||
property bool varIsArray
|
||||
property bool propIsArray
|
||||
|
||||
onModelChanged: {
|
||||
modelIndexList = createModelIndexList()
|
||||
modelIndexList.prepend(model.index(0, 0))
|
||||
modelIndexList.append(model.index(1, 1))
|
||||
var jsModelIndexList = []
|
||||
for (var i = 0; i < 3; i++)
|
||||
modelIndexList.insert(i, model.index(2 + i, 2 + i))
|
||||
jsModelIndexList.push(model.index(2 + i, 2 + i))
|
||||
jsModelIndexList.push("Hi Bronsky!")
|
||||
modelIndex = jsModelIndexList[0]
|
||||
|
||||
count = modelIndexList.length
|
||||
modelIndex = modelIndexList.at(0)
|
||||
propIsArray = modelIndexList instanceof Array
|
||||
modelIndexList = jsModelIndexList
|
||||
modelIndexListRead = modelIndexList
|
||||
|
||||
modelIndexList.removeAt(3)
|
||||
modelIndexList.removeFirst()
|
||||
modelIndexList.removeLast()
|
||||
modelIndexListCopy = someModelIndexList()
|
||||
varPropIsArray = modelIndexListCopy instanceof Array
|
||||
|
||||
jsModelIndexList = someModelIndexList()
|
||||
varIsArray = jsModelIndexList instanceof Array
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,11 +45,15 @@ class ItemModelsTest : public QObject
|
|||
Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
|
||||
Q_PROPERTY(QModelIndex modelIndex READ modelIndex WRITE setModelIndex NOTIFY changed)
|
||||
Q_PROPERTY(QPersistentModelIndex persistentModelIndex READ persistentModelIndex WRITE setPersistentModelIndex NOTIFY changed)
|
||||
Q_PROPERTY(QModelIndexList modelIndexList READ modelIndexList WRITE setModelIndexList NOTIFY changed)
|
||||
Q_PROPERTY(QItemSelection itemSelection READ itemSelection WRITE setItemSelection NOTIFY changed)
|
||||
|
||||
public:
|
||||
ItemModelsTest()
|
||||
: m_model(0)
|
||||
{}
|
||||
ItemModelsTest(QObject *parent = 0)
|
||||
: QObject(parent)
|
||||
, m_model(0)
|
||||
{
|
||||
}
|
||||
|
||||
QModelIndex modelIndex() const
|
||||
{
|
||||
|
@ -61,6 +65,31 @@ public:
|
|||
return m_persistentModelIndex;
|
||||
}
|
||||
|
||||
QModelIndexList modelIndexList()
|
||||
{
|
||||
static bool firstTime = true;
|
||||
if (firstTime && m_model && m_modelIndexList.isEmpty()) {
|
||||
firstTime = false;
|
||||
for (int i = 0; i < m_model->rowCount(); i++)
|
||||
m_modelIndexList << m_model->index(i, 0);
|
||||
}
|
||||
return m_modelIndexList;
|
||||
}
|
||||
|
||||
Q_INVOKABLE QModelIndexList someModelIndexList() const
|
||||
{
|
||||
QModelIndexList list;
|
||||
if (m_model)
|
||||
for (int i = 0; i < m_model->rowCount(); i++)
|
||||
list << m_model->index(i, 0);
|
||||
return list;
|
||||
}
|
||||
|
||||
QItemSelection itemSelection() const
|
||||
{
|
||||
return m_itemSelection;
|
||||
}
|
||||
|
||||
void emitChanged()
|
||||
{
|
||||
emit changed();
|
||||
|
@ -86,11 +115,6 @@ public:
|
|||
return QModelIndex();
|
||||
}
|
||||
|
||||
Q_INVOKABLE QModelIndexList createModelIndexList() const
|
||||
{
|
||||
return QModelIndexList();
|
||||
}
|
||||
|
||||
Q_INVOKABLE QItemSelectionRange createItemSelectionRange(const QModelIndex &tl, const QModelIndex &br) const
|
||||
{
|
||||
return QItemSelectionRange(tl, br);
|
||||
|
@ -134,6 +158,24 @@ public slots:
|
|||
emit modelChanged(arg);
|
||||
}
|
||||
|
||||
void setModelIndexList(QModelIndexList arg)
|
||||
{
|
||||
if (m_modelIndexList == arg)
|
||||
return;
|
||||
|
||||
m_modelIndexList = arg;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void setItemSelection(QItemSelection arg)
|
||||
{
|
||||
if (m_itemSelection == arg)
|
||||
return;
|
||||
|
||||
m_itemSelection = arg;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
|
@ -146,6 +188,8 @@ private:
|
|||
QModelIndex m_modelIndex;
|
||||
QPersistentModelIndex m_persistentModelIndex;
|
||||
QAbstractItemModel *m_model;
|
||||
QModelIndexList m_modelIndexList;
|
||||
QItemSelection m_itemSelection;
|
||||
};
|
||||
|
||||
#endif // TESTTYPES_H
|
||||
|
|
|
@ -184,31 +184,53 @@ void tst_qqmlitemmodels::itemSelection()
|
|||
TestModel model(10, 10);
|
||||
|
||||
object->setModel(&model);
|
||||
QCOMPARE(object->property("count").toInt(), 8);
|
||||
QCOMPARE(object->property("count").toInt(), 5);
|
||||
QCOMPARE(object->property("contains").toBool(), true);
|
||||
|
||||
QVariant milVariant = object->property("itemSelection");
|
||||
QCOMPARE(milVariant.userType(), qMetaTypeId<QItemSelection>());
|
||||
const char *propNames[] = { "itemSelectionRead", "itemSelectionBinding", 0 };
|
||||
for (const char **name = propNames; *name; name++) {
|
||||
QVariant isVariant = object->property(*name);
|
||||
QCOMPARE(isVariant.userType(), qMetaTypeId<QItemSelection>());
|
||||
|
||||
const QItemSelection &mil = milVariant.value<QItemSelection>();
|
||||
QCOMPARE(mil.count(), 5);
|
||||
const QItemSelection &sel = isVariant.value<QItemSelection>();
|
||||
QCOMPARE(sel.count(), object->itemSelection().count());
|
||||
QCOMPARE(sel, object->itemSelection());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qqmlitemmodels::modelIndexList()
|
||||
{
|
||||
INIT_TEST_OBJECT("modelindexlist.qml", object);
|
||||
TestModel model(10, 10);
|
||||
model.fetchMore(QModelIndex());
|
||||
|
||||
object->setModel(&model);
|
||||
QCOMPARE(object->property("count").toInt(), 5);
|
||||
QVERIFY(object->property("propIsArray").toBool());
|
||||
QVERIFY(object->property("varPropIsArray").toBool());
|
||||
QVERIFY(object->property("varIsArray").toBool());
|
||||
|
||||
QVariant milVariant = object->property("modelIndexList");
|
||||
QCOMPARE(milVariant.userType(), qMetaTypeId<QModelIndexList>());
|
||||
QCOMPARE(object->property("count").toInt(), 10);
|
||||
const QModelIndexList &mil = object->modelIndexList();
|
||||
QCOMPARE(mil.count(), 4);
|
||||
for (int i = 0; i < 3; i++)
|
||||
QCOMPARE(mil.at(i), model.index(2 + i, 2 + i));
|
||||
QCOMPARE(mil.at(3), QModelIndex()); // The string inserted at the end should result in an invalid index
|
||||
QCOMPARE(mil.at(0), object->modelIndex());
|
||||
|
||||
const QModelIndexList &mil = milVariant.value<QModelIndexList>();
|
||||
QCOMPARE(mil.count(), 2);
|
||||
QCOMPARE(mil.at(0), model.index(3, 3));
|
||||
QCOMPARE(mil.at(1), model.index(4, 4));
|
||||
QVariant cppMILVariant = object->property("modelIndexListCopy");
|
||||
QCOMPARE(cppMILVariant.userType(), qMetaTypeId<QModelIndexList>());
|
||||
QModelIndexList someMIL = object->someModelIndexList();
|
||||
QCOMPARE(cppMILVariant.value<QModelIndexList>(), someMIL);
|
||||
|
||||
const char *propNames[] = { "modelIndexListRead", "modelIndexListBinding", 0 };
|
||||
for (const char **name = propNames; *name; name++) {
|
||||
QVariant milVariant = object->property(*name);
|
||||
QCOMPARE(milVariant.userType(), qMetaTypeId<QModelIndexList>());
|
||||
|
||||
const QModelIndexList &milProp = milVariant.value<QModelIndexList>();
|
||||
QCOMPARE(milProp.count(), mil.count());
|
||||
QCOMPARE(milProp, mil);
|
||||
}
|
||||
}
|
||||
|
||||
#undef INIT_TEST_OBJECT
|
||||
|
|
|
@ -326,10 +326,16 @@ class PropertyObject : public QObject
|
|||
Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal)
|
||||
Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject)
|
||||
Q_PROPERTY(MyQObject *qObject READ qObject WRITE setQObject NOTIFY qObjectChanged)
|
||||
Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
|
||||
Q_PROPERTY(char charProperty READ charProperty WRITE setCharProperty)
|
||||
Q_PROPERTY(QChar qcharProperty READ qcharProperty WRITE setQcharProperty)
|
||||
Q_PROPERTY(QChar constQChar READ constQChar STORED false CONSTANT FINAL)
|
||||
Q_PROPERTY(char constChar READ constChar STORED false CONSTANT FINAL)
|
||||
Q_PROPERTY(int constInt READ constInt STORED false CONSTANT FINAL)
|
||||
|
||||
Q_CLASSINFO("DefaultProperty", "defaultProperty")
|
||||
public:
|
||||
PropertyObject() : m_resetProperty(9), m_qObject(0) {}
|
||||
PropertyObject() : m_resetProperty(9), m_qObject(0), m_stringProperty("foo") {}
|
||||
|
||||
int defaultProperty() { return 10; }
|
||||
QRect rectProperty() { return QRect(10, 10, 1, 209); }
|
||||
|
@ -361,6 +367,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
QString stringProperty() const { return m_stringProperty;}
|
||||
char charProperty() const { return m_charProperty; }
|
||||
QChar qcharProperty() const { return m_qcharProperty; }
|
||||
|
||||
QChar constQChar() const { return 0x25cf; /* Unicode: black circle */ }
|
||||
char constChar() const { return 'A'; }
|
||||
int constInt() const { return 123456; }
|
||||
|
||||
void setStringProperty(QString arg) { m_stringProperty = arg; }
|
||||
void setCharProperty(char arg) { m_charProperty = arg; }
|
||||
void setQcharProperty(QChar arg) { m_qcharProperty = arg; }
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
void oddlyNamedNotifySignal();
|
||||
|
@ -374,6 +392,9 @@ private:
|
|||
int m_propertyWithNotify;
|
||||
MyQmlObject m_qmlObject;
|
||||
MyQObject *m_qObject;
|
||||
QString m_stringProperty;
|
||||
char m_charProperty;
|
||||
QChar m_qcharProperty;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPE(PropertyObject);
|
||||
|
@ -1382,6 +1403,71 @@ void tst_qqmlproperty::write()
|
|||
QCOMPARE(o.url(), result);
|
||||
}
|
||||
|
||||
// Char/string-property
|
||||
{
|
||||
PropertyObject o;
|
||||
QQmlProperty charProperty(&o, "charProperty");
|
||||
QQmlProperty qcharProperty(&o, "qcharProperty");
|
||||
QQmlProperty stringProperty(&o, "stringProperty");
|
||||
|
||||
const int black_circle = 0x25cf;
|
||||
|
||||
QCOMPARE(charProperty.write(QString("foo")), false);
|
||||
QCOMPARE(charProperty.write('Q'), true);
|
||||
QCOMPARE(charProperty.read(), QVariant('Q'));
|
||||
QCOMPARE(charProperty.write(QString("t")), true);
|
||||
QCOMPARE(charProperty.read(), QVariant('t'));
|
||||
|
||||
QCOMPARE(qcharProperty.write(QString("foo")), false);
|
||||
QCOMPARE(qcharProperty.write('Q'), true);
|
||||
QCOMPARE(qcharProperty.read(), QVariant('Q'));
|
||||
QCOMPARE(qcharProperty.write(QString("t")), true);
|
||||
QCOMPARE(qcharProperty.read(), QVariant('t'));
|
||||
QCOMPARE(qcharProperty.write(QChar(black_circle)), true);
|
||||
QCOMPARE(qcharProperty.read(), QVariant(QChar(black_circle)));
|
||||
|
||||
QCOMPARE(o.stringProperty(), QString("foo")); // Default value
|
||||
QCOMPARE(stringProperty.write(QString("bar")), true);
|
||||
QCOMPARE(o.stringProperty(), QString("bar"));
|
||||
QCOMPARE(stringProperty.write(QVariant(1234)), true);
|
||||
QCOMPARE(stringProperty.read().toString(), QString::number(1234));
|
||||
QCOMPARE(stringProperty.write(QChar(black_circle)), true);
|
||||
QCOMPARE(stringProperty.read(), QVariant(QString(QChar(black_circle))));
|
||||
|
||||
{ // char -> QString
|
||||
QQmlComponent component(&engine);
|
||||
component.setData("import Test 1.0\nPropertyObject { stringProperty: constChar }", QUrl());
|
||||
PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
|
||||
QVERIFY(obj != 0);
|
||||
if (obj) {
|
||||
QQmlProperty stringProperty(obj, "stringProperty");
|
||||
QCOMPARE(stringProperty.read(), QVariant(QString(obj->constChar())));
|
||||
}
|
||||
}
|
||||
|
||||
{ // QChar -> QString
|
||||
QQmlComponent component(&engine);
|
||||
component.setData("import Test 1.0\nPropertyObject { stringProperty: constQChar }", QUrl());
|
||||
PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
|
||||
QVERIFY(obj != 0);
|
||||
if (obj) {
|
||||
QQmlProperty stringProperty(obj, "stringProperty");
|
||||
QCOMPARE(stringProperty.read(), QVariant(QString(obj->constQChar())));
|
||||
}
|
||||
}
|
||||
|
||||
{ // int -> QString
|
||||
QQmlComponent component(&engine);
|
||||
component.setData("import Test 1.0\nPropertyObject { stringProperty: constInt }", QUrl());
|
||||
PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
|
||||
QVERIFY(obj != 0);
|
||||
if (obj) {
|
||||
QQmlProperty stringProperty(obj, "stringProperty");
|
||||
QCOMPARE(stringProperty.read(), QVariant(QString::number(obj->constInt())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VariantMap-property
|
||||
QVariantMap vm;
|
||||
vm.insert("key", "value");
|
||||
|
|
|
@ -1427,17 +1427,30 @@ void tst_qquickflickable::nestedStopAtBounds_data()
|
|||
{
|
||||
QTest::addColumn<bool>("transpose");
|
||||
QTest::addColumn<bool>("invert");
|
||||
QTest::addColumn<int>("boundsBehavior");
|
||||
QTest::addColumn<qreal>("margin");
|
||||
|
||||
QTest::newRow("left") << false << false;
|
||||
QTest::newRow("right") << false << true;
|
||||
QTest::newRow("top") << true << false;
|
||||
QTest::newRow("bottom") << true << true;
|
||||
QTest::newRow("left,stop") << false << false << int(QQuickFlickable::StopAtBounds) << qreal(0);
|
||||
QTest::newRow("right,stop") << false << true << int(QQuickFlickable::StopAtBounds) << qreal(0);
|
||||
QTest::newRow("top,stop") << true << false << int(QQuickFlickable::StopAtBounds) << qreal(0);
|
||||
QTest::newRow("bottom,stop") << true << true << int(QQuickFlickable::StopAtBounds) << qreal(0);
|
||||
QTest::newRow("left,over") << false << false << int(QQuickFlickable::DragOverBounds) << qreal(0);
|
||||
QTest::newRow("right,over") << false << true << int(QQuickFlickable::DragOverBounds) << qreal(0);
|
||||
QTest::newRow("top,over") << true << false << int(QQuickFlickable::DragOverBounds) << qreal(0);
|
||||
QTest::newRow("bottom,over") << true << true << int(QQuickFlickable::DragOverBounds) << qreal(0);
|
||||
|
||||
QTest::newRow("left,stop,margin") << false << false << int(QQuickFlickable::StopAtBounds) << qreal(20);
|
||||
QTest::newRow("right,stop,margin") << false << true << int(QQuickFlickable::StopAtBounds) << qreal(20);
|
||||
QTest::newRow("top,stop,margin") << true << false << int(QQuickFlickable::StopAtBounds) << qreal(20);
|
||||
QTest::newRow("bottom,stop,margin") << true << true << int(QQuickFlickable::StopAtBounds) << qreal(20);
|
||||
}
|
||||
|
||||
void tst_qquickflickable::nestedStopAtBounds()
|
||||
{
|
||||
QFETCH(bool, transpose);
|
||||
QFETCH(bool, invert);
|
||||
QFETCH(int, boundsBehavior);
|
||||
QFETCH(qreal, margin);
|
||||
|
||||
QQuickView view;
|
||||
view.setSource(testFileUrl("nestedStopAtBounds.qml"));
|
||||
|
@ -1455,8 +1468,20 @@ void tst_qquickflickable::nestedStopAtBounds()
|
|||
QQuickFlickable *inner = outer->findChild<QQuickFlickable*>("innerFlickable");
|
||||
QVERIFY(inner);
|
||||
inner->setFlickableDirection(transpose ? QQuickFlickable::VerticalFlick : QQuickFlickable::HorizontalFlick);
|
||||
inner->setContentX(invert ? 0 : 100);
|
||||
inner->setContentY(invert ? 0 : 100);
|
||||
inner->setBoundsBehavior(QQuickFlickable::BoundsBehavior(boundsBehavior));
|
||||
|
||||
invert ? inner->setRightMargin(margin) : inner->setLeftMargin(margin);
|
||||
invert ? inner->setBottomMargin(margin) : inner->setTopMargin(margin);
|
||||
|
||||
inner->setContentX(invert ? -margin : 100 - margin);
|
||||
inner->setContentY(invert ? -margin : 100 - margin);
|
||||
inner->setContentWidth(400 - margin);
|
||||
inner->setContentHeight(400 - margin);
|
||||
|
||||
QCOMPARE(inner->isAtXBeginning(), invert);
|
||||
QCOMPARE(inner->isAtXEnd(), !invert);
|
||||
QCOMPARE(inner->isAtYBeginning(), invert);
|
||||
QCOMPARE(inner->isAtYEnd(), !invert);
|
||||
|
||||
const int threshold = qApp->styleHints()->startDragDistance();
|
||||
|
||||
|
@ -1495,10 +1520,10 @@ void tst_qquickflickable::nestedStopAtBounds()
|
|||
QTRY_VERIFY(!outer->isMoving());
|
||||
|
||||
axis = 200;
|
||||
inner->setContentX(0);
|
||||
inner->setContentY(0);
|
||||
inner->setContentWidth(inner->width());
|
||||
inner->setContentHeight(inner->height());
|
||||
inner->setContentX(-margin);
|
||||
inner->setContentY(-margin);
|
||||
inner->setContentWidth(inner->width() - margin);
|
||||
inner->setContentHeight(inner->height() - margin);
|
||||
|
||||
// Drag inner with equal size and contentSize
|
||||
QTest::mousePress(&view, Qt::LeftButton, 0, position);
|
||||
|
@ -1512,8 +1537,8 @@ void tst_qquickflickable::nestedStopAtBounds()
|
|||
QTest::mouseRelease(&view, Qt::LeftButton, 0, position);
|
||||
|
||||
axis = 200;
|
||||
inner->setContentX(0);
|
||||
inner->setContentY(0);
|
||||
inner->setContentX(-margin);
|
||||
inner->setContentY(-margin);
|
||||
inner->setContentWidth(inner->width() - 100);
|
||||
inner->setContentHeight(inner->height() - 100);
|
||||
|
||||
|
|
Loading…
Reference in New Issue