Merge remote-tracking branch 'origin/5.5' into dev

Conflicts:
	tests/auto/qml/qqmlitemmodels/testtypes.h

Change-Id: I2f2f3f47fd873ddd4fd027414654a861b56357f4
This commit is contained in:
Liang Qi 2015-03-24 22:09:49 +01:00
commit c8427a542b
22 changed files with 453 additions and 232 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -78,7 +78,6 @@ class QQmlExpression;
class QQmlContext;
class QQmlType;
class QUrl;
class QScriptContext;
class QNetworkAccessManager;
class QQmlNetworkAccessManagerFactory;
class QQmlIncubationController;

View File

@ -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)) {

View File

@ -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();

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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;
}
}
}

View File

@ -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
{

View File

@ -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());

View File

@ -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;

View File

@ -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)) })
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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);