Merge remote-tracking branch 'origin/5.8' into 5.9

Conflicts:
	src/qml/compiler/qv4ssa.cpp
	src/quick/accessible/qaccessiblequickview_p.h
	src/quick/items/qquickmousearea.cpp
	src/quick/util/qquickanimatorjob.cpp
	tools/qmlplugindump/main.cpp

Change-Id: I84474cf39895b9b757403971d2e9196e8c9d1809
This commit is contained in:
Liang Qi 2017-02-24 10:14:57 +01:00
commit b1fa22c168
68 changed files with 57328 additions and 198 deletions

View File

@ -51,37 +51,37 @@ class AsyncImageResponse : public QQuickImageResponse, public QRunnable
{
public:
AsyncImageResponse(const QString &id, const QSize &requestedSize)
: m_id(id), m_requestedSize(requestedSize), m_texture(0)
: m_id(id), m_requestedSize(requestedSize)
{
setAutoDelete(false);
}
QQuickTextureFactory *textureFactory() const
{
return m_texture;
return QQuickTextureFactory::textureFactoryForImage(m_image);
}
void run()
{
QImage image(50, 50, QImage::Format_RGB32);
m_image = QImage(50, 50, QImage::Format_RGB32);
if (m_id == "slow") {
qDebug() << "Slow, red, sleeping for 5 seconds";
QThread::sleep(5);
image.fill(Qt::red);
m_image.fill(Qt::red);
} else {
qDebug() << "Fast, blue, sleeping for 1 second";
QThread::sleep(1);
image.fill(Qt::blue);
m_image.fill(Qt::blue);
}
if (m_requestedSize.isValid())
image = image.scaled(m_requestedSize);
m_texture = QQuickTextureFactory::textureFactoryForImage(image);
m_image = m_image.scaled(m_requestedSize);
emit finished();
}
QString m_id;
QSize m_requestedSize;
QQuickTextureFactory *m_texture;
QImage m_image;
};
class AsyncImageProvider : public QQuickAsyncImageProvider

View File

@ -1,5 +1,7 @@
TEMPLATE = subdirs
QT_FOR_CONFIG += quick-private
SUBDIRS += \
builtins \
qtqml \
@ -18,7 +20,7 @@ qtHaveModule(quick) {
sharedimage \
testlib
qtConfig(opengl(es1|es2)?): \
qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \
SUBDIRS += particles
}

View File

@ -564,7 +564,7 @@ Database connections are automatically closed during Javascript garbage collecti
The API can be used from JavaScript functions in your QML:
\snippet localstorage/localstorage/hello.qml 0
\snippet qml/localstorage/hello.qml 0
The API conforms to the Synchronous API of the HTML5 Web Database API,
\link http://www.w3.org/TR/2009/WD-webdatabase-20091029/ W3C Working Draft 29 October 2009\endlink.

View File

@ -1108,10 +1108,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv
continue;
}
// Try again later and resolve the target alias first.
_objectsWithAliases.append(objectIndex);
// restore
alias->idIndex = idIndex;
// Try again later and resolve the target alias first.
break;
}
}

View File

@ -427,6 +427,7 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
}
#endif
#if QT_CONFIG(temporaryfile)
// Foo.qml -> Foo.qmlc
QSaveFile cacheFile(cacheFilePath(unitUrl));
if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
@ -459,6 +460,10 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
}
return true;
#else
*errorString = QStringLiteral("features.temporaryfile is disabled.");
return false;
#endif // QT_CONFIG(temporaryfile)
}
void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)

View File

@ -507,6 +507,16 @@ struct Q_AUTOTEST_EXPORT Temp: Expr {
, memberResolver(0)
{}
Temp(Type type, Kind kind, unsigned index)
: Expr(TempExpr)
, index(index)
, isReadOnly(0)
, kind(kind)
, memberResolver(0)
{
this->type = type;
}
void init(unsigned kind, unsigned index)
{
this->index = index;

View File

@ -3581,16 +3581,43 @@ public:
, _replacement(0)
{}
void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QVector<Stmt *> *newUses = 0)
bool operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QVector<Stmt *> *newUses = 0)
{
Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName());
// qout << "Replacing ";toReplace->dump(qout);qout<<" by ";replacement->dump(qout);qout<<endl;
qSwap(_toReplace, toReplace);
qSwap(_replacement, replacement);
const QVector<Stmt *> &uses = _defUses.uses(*_toReplace);
// Prevent the following:
// L3:
// %1 = phi L1: %2, L2: %3
// %4 = phi L1: %5, L2: %6
// %6 = %1
// From turning into:
// L3:
// %1 = phi L1: %2, L2: %3
// %4 = phi L1: %5, L2: %1
//
// Because both phi nodes are "executed in parallel", we cannot replace %6 by %1 in the
// second phi node. So, if the defining statement for a temp is a phi node, and one of the
// uses of the to-be-replaced statement is a phi node in the same block as the defining
// statement, bail out.
if (Temp *r = _replacement->asTemp()) {
if (_defUses.defStmt(*r)->asPhi()) {
BasicBlock *replacementDefBlock = _defUses.defStmtBlock(*r);
for (Stmt *use : uses) {
if (Phi *usePhi = use->asPhi()) {
if (_defUses.defStmtBlock(*usePhi->targetTemp) == replacementDefBlock)
return false;
}
}
}
}
// qout << "Replacing ";toReplace->dump(qout);qout<<" by ";replacement->dump(qout);qout<<endl;
if (newUses)
newUses->reserve(uses.size());
@ -3606,6 +3633,7 @@ public:
qSwap(_replacement, replacement);
qSwap(_toReplace, toReplace);
return true;
}
private:
@ -4082,11 +4110,12 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df)
// copy propagation:
if (Temp *sourceTemp = m->source->asTemp()) {
QVector<Stmt *> newT2Uses;
replaceUses(targetTemp, sourceTemp, W, &newT2Uses);
defUses.removeUse(s, *sourceTemp);
defUses.addUses(*sourceTemp, newT2Uses);
defUses.removeDef(*targetTemp);
W.remove(s);
if (replaceUses(targetTemp, sourceTemp, W, &newT2Uses)) {
defUses.removeUse(s, *sourceTemp);
defUses.addUses(*sourceTemp, newT2Uses);
defUses.removeDef(*targetTemp);
W.remove(s);
}
continue;
}
@ -5635,25 +5664,97 @@ void MoveMapping::add(Expr *from, Temp *to) {
_moves.append(m);
}
// Order the moves that are generated when resolving edges during register allocation (see [Wimmer1]
// section 6 for details). Now these moves form one or more graphs, so we have to output them in
// such an order that values don't get overwritten:
// r1 <- r0
// r2 <- r1
// That input has to be ordered as follows in order to prevent the value in r1 from being lost:
// r2 <- r1
// r1 <- r0
//
// So, the algorithm is to output the leaves first, and take them out of the input. This will result
// in some moves to become leaves (in the above example: when leaf r2 <- r1 is generated and taken
// away, the r1 <- r0 is now a leaf), so we can output those and take those out, and repeat until
// there are no more leafs.
//
// The tricky part is that there might be cycles:
// r4 <- r5
// r5 <- r4
// These have to be turned into a "register swap":
// r4 <=> r5
//
// So after running the above algorithm where we progressively remove the leaves, we are left with
// zero or more cycles. To resolve those, we break one of the edges of the cycle, and for all other
// edges we generate swaps. Note that the swaps will always occur as the last couple of moves,
// because otherwise they might clobber sources for moves:
// r4 <=> r5
// r6 <- r5
// Here, the value of r5 is already overwritten with the one in r4, so the correct order is:
// r6 <- r5
// r4 <=> r5
void MoveMapping::order()
{
QList<Move> todo = _moves;
QList<Move> output, swaps;
QList<Move> output;
output.reserve(_moves.size());
QList<Move> delayed;
delayed.reserve(_moves.size());
while (!todo.isEmpty()) {
const Move m = todo.first();
todo.removeFirst();
schedule(m, todo, delayed, output, swaps);
while (!_moves.isEmpty()) {
// Take out all leaf edges, because we can output them without any problems.
int nextLeaf = findLeaf();
if (nextLeaf == -1)
break; // No more leafs left, we're done here.
output.append(_moves.takeAt(nextLeaf));
// Now there might be new leaf edges: any move that had the input of the previously found
// leaf as an output, so loop around.
}
output += swaps;
while (!_moves.isEmpty()) {
// We're now left with one or more cycles.
// Step one: break the/a cycle.
_moves.removeFirst();
// Step two: find the other edges of the cycle, starting with the one of that is now a leaf.
while (!_moves.isEmpty()) {
int nextLeaf = findLeaf();
if (nextLeaf == -1)
break; // We're done with this cycle.
Move m = _moves.takeAt(nextLeaf);
// Step three: get the edges from the cycle and turn it into a swap
m.needsSwap = true;
output.append(m);
// Because we took out a leaf, find the next one.
}
// We're done with the cycle, let's see if there are more.
}
Q_ASSERT(todo.isEmpty());
Q_ASSERT(delayed.isEmpty());
qSwap(_moves, output);
_moves = output;
}
int MoveMapping::findLeaf() const
{
for (int i = 0, e = _moves.size(); i != e; ++i) {
// Take an edge from the list...
const Temp *target = _moves.at(i).to;
// ... and see if its target is used as a source...
bool targetUsedAsSource = false;
for (int j = 0; j != e; ++j) {
if (i == j)
continue;
Expr *source = _moves.at(j).from;
if (const Temp *sourceTemp = source->asTemp()) {
if (overlappingStorage(*target, *sourceTemp)) {
targetUsedAsSource = true;
break;
}
}
}
// ... if not, we have a leaf edge ...
if (!targetUsedAsSource)
return i;
// .. otherwise we try the next one.
}
return -1; // No leaf found
}
QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *function, bool atEnd) const
@ -5695,60 +5796,12 @@ void MoveMapping::dump() const
}
}
MoveMapping::Action MoveMapping::schedule(const Move &m, QList<Move> &todo, QList<Move> &delayed,
QList<Move> &output, QList<Move> &swaps) const
{
const Moves usages = sourceUsages(m.to, todo) + sourceUsages(m.to, delayed);
for (const Move &dependency : usages) {
if (!output.contains(dependency)) {
if (delayed.contains(dependency)) {
// We have a cycle! Break it by swapping instead of assigning.
if (DebugMoveMapping) {
delayed += m;
QBuffer buf;
buf.open(QIODevice::WriteOnly);
QTextStream out(&buf);
IRPrinter printer(&out);
out<<"we have a cycle! temps:" << endl;
for (const Move &m : qAsConst(delayed)) {
out<<"\t";
printer.print(m.to);
out<<" <- ";
printer.print(m.from);
out<<endl;
}
qDebug("%s", buf.data().constData());
delayed.removeOne(m);
}
return NeedsSwap;
} else {
delayed.append(m);
todo.removeOne(dependency);
Action action = schedule(dependency, todo, delayed, output, swaps);
delayed.removeOne(m);
Move mm(m);
if (action == NeedsSwap) {
mm.needsSwap = true;
swaps.append(mm);
} else {
output.append(mm);
}
return action;
}
}
}
output.append(m);
return NormalMove;
}
// References:
// [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of
// CGO10, ACM Press, 2010
// CGO'10, ACM Press, 2010
// [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register
// Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual
// Execution Environments, pages 132141. ACM Press, 2005.
// Execution Environments, pages 132-141. ACM Press, 2005.
// [Briggs] P. Briggs, K.D. Cooper, T.J. Harvey, and L.T. Simpson. Practical Improvements to the
// Construction and Destruction of Static Single Assignment Form.
// [Appel] A.W. Appel. Modern Compiler Implementation in Java. Second edition, Cambridge

View File

@ -265,15 +265,18 @@ private:
QHash<BasicBlock *, BasicBlock *> startEndLoops;
};
class MoveMapping
class Q_AUTOTEST_EXPORT MoveMapping
{
#ifdef V4_AUTOTEST
public:
#endif
struct Move {
Expr *from;
Temp *to;
bool needsSwap;
Move(Expr *from, Temp *to)
: from(from), to(to), needsSwap(false)
Move(Expr *from, Temp *to, bool needsSwap = false)
: from(from), to(to), needsSwap(needsSwap)
{}
bool operator==(const Move &other) const
@ -293,9 +296,7 @@ public:
void dump() const;
private:
enum Action { NormalMove, NeedsSwap };
Action schedule(const Move &m, QList<Move> &todo, QList<Move> &delayed, QList<Move> &output,
QList<Move> &swaps) const;
int findLeaf() const;
};
/*

View File

@ -67,13 +67,15 @@ class QQuickWindow;
#ifdef QT_NO_QML_DEBUGGER
struct QV4DebugService
class QV4DebugService
{
public:
void signalEmitted(const QString &) {}
};
struct QQmlProfilerService
class QQmlProfilerService
{
public:
void startProfiling(QJSEngine *engine, quint64 features = std::numeric_limits<quint64>::max())
{
Q_UNUSED(engine);
@ -83,21 +85,23 @@ struct QQmlProfilerService
void stopProfiling(QJSEngine *) {}
};
struct QQmlEngineDebugService
class QQmlEngineDebugService
{
public:
void objectCreated(QJSEngine *, QObject *) {}
virtual void setStatesDelegate(QQmlDebugStatesDelegate *) {}
};
struct QQmlInspectorService {
class QQmlInspectorService {
public:
void addWindow(QQuickWindow *) {}
void setParentWindow(QQuickWindow *, QWindow *) {}
void removeWindow(QQuickWindow *) {}
};
struct QDebugMessageService {};
struct QQmlEngineControlService {};
struct QQmlNativeDebugService {};
class QDebugMessageService {};
class QQmlEngineControlService {};
class QQmlNativeDebugService {};
#else

View File

@ -69,7 +69,7 @@ QT_BEGIN_NAMESPACE
#define Q_QML_PROFILE(feature, profiler, Method)
#define Q_QML_OC_PROFILE(member, Code)
struct QQmlProfiler {};
class QQmlProfiler {};
struct QQmlBindingProfiler
{

View File

@ -168,8 +168,9 @@
from \a uri having version number composed from \a versionMajor and
\a versionMinor.
While the type has a name and a type, it cannot be created, and the
given error \a reason will result if creation is attempted.
While the type has a name and a type, it cannot be created. An error
message with the given \a reason is printed if the user attempts to
create an instance of this type.
This is useful where the type is only intended for providing attached
properties, enum values or an abstract base class with its extension.
@ -189,11 +190,14 @@
from \a uri having version number composed from \a versionMajor and
\a versionMinor.
This function is useful to register Q_NAMESPACE namespaces.
An instance of the meta object cannot be created. An error message with
the given \a reason is printed if the user attempts to create it.
This function is useful for registering Q_NAMESPACE namespaces.
Returns the QML type id.
Example:
For example:
\code
namespace MyNamespace {
@ -209,7 +213,7 @@
qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "io.qt", 1, 0, "MyNamespace", "Access to enums & flags only");
\endcode
Now on QML side you can use the registered enums:
On the QML side, you can now use the registered enums:
\code
Component.onCompleted: console.log(MyNamespace.Key2)
\endcode

View File

@ -1138,6 +1138,8 @@ private:
mapping.add(moveFrom, moveTo);
}
if (DebugRegAlloc)
mapping.dump();
mapping.order();
if (DebugRegAlloc)
mapping.dump();
@ -1958,10 +1960,10 @@ void RegisterAllocator::dump(IR::Function *function) const
// References:
// [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of
// CGO10, ACM Press, 2010
// CGO'10, ACM Press, 2010
// [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register
// Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual
// Execution Environments, pages 132141. ACM Press, 2005.
// Execution Environments, pages 132-141. ACM Press, 2005.
// [Traub] Omri Traub, Glenn Holloway, and Michael D. Smith. Quality and Speed in Linear-scan
// Register Allocation. In Proceedings of the ACM SIGPLAN 1998 Conference on Programming
// Language Design and Implementation, pages 142151, June 1998.
// Language Design and Implementation, pages 142-151, June 1998.

View File

@ -525,7 +525,7 @@ QJSValue QJSEngine::newQObject(QObject *object)
\since 5.8
Creates a JavaScript object that wraps the given QMetaObject
The metaObject must outlive the script engine. It is recommended to only
The \a metaObject must outlive the script engine. It is recommended to only
use this method with static metaobjects.

View File

@ -61,8 +61,9 @@ namespace Debugging {
#ifdef QT_NO_QML_DEBUGGER
struct Debugger
class Debugger
{
public:
bool pauseAtNextOpportunity() const { return false; }
void maybeBreakAtInstruction() {}
void enteringFunction() {}

View File

@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Profiling {
struct Profiler {};
class Profiler {};
}
}

View File

@ -1039,7 +1039,7 @@ QQmlEngine::~QQmlEngine()
/*! \fn void QQmlEngine::exit(int retCode)
This signal is emitted when the QML loaded by the engine would like to exit
from the event loop with the specified return code.
from the event loop with the specified return code \a retCode.
\since 5.8
\sa quit()

View File

@ -202,6 +202,7 @@ QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
*/
QQmlExpression::~QQmlExpression()
{
clearError();
}
/*!

View File

@ -394,8 +394,9 @@ can be very useful while prototyping.
\fn QQmlListProperty::QQmlListProperty(QObject *object, void *data,
CountFunction count, AtFunction at)
Construct a readonly QQmlListProperty from a set of operation functions. An opaque \a data handle
may be passed which can be accessed from within the operation functions. The list property
Construct a readonly QQmlListProperty from a set of operation functions
\a count and \a at. An opaque \a data handle may be passed which can be
accessed from within the operation functions. The list property
remains valid while \a object exists.
*/
@ -404,8 +405,9 @@ remains valid while \a object exists.
CountFunction count, AtFunction at,
ClearFunction clear)
Construct a QQmlListProperty from a set of operation functions. An opaque \a data handle
may be passed which can be accessed from within the operation functions. The list property
Construct a QQmlListProperty from a set of operation functions \a append,
\a count, \a at, and \a clear. An opaque \a data handle may be passed which
can be accessed from within the operation functions. The list property
remains valid while \a object exists.
Null pointers can be passed for any function. If any null pointers are passed in, the list

View File

@ -789,12 +789,12 @@ void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that)
QQmlAbstractBinding *
QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index)
{
findAliasTarget(object, index, &object, &index);
QQmlData *data = QQmlData::get(object);
if (!data)
return 0;
findAliasTarget(object, index, &object, &index);
const int coreIndex = index.coreIndex();
const int valueTypeIndex = index.valueTypeIndex();
@ -1399,9 +1399,9 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi
}
/*!
Sets the property value to \a value and returns true.
Returns false if the property can't be set because the
\a value is the wrong type, for example.
Sets the property value to \a value. Returns \c true on success, or
\c false if the property can't be set because the \a value is the
wrong type, for example.
*/
bool QQmlProperty::write(const QVariant &value) const
{
@ -1416,6 +1416,8 @@ bool QQmlProperty::write(const QVariant &value) const
QQmlProperty p(object, name);
p.write(value);
\endcode
Returns \c true on success, \c false otherwise.
*/
bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
{
@ -1432,6 +1434,8 @@ bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &v
QQmlProperty p(object, name, ctxt);
p.write(value);
\endcode
Returns \c true on success, \c false otherwise.
*/
bool QQmlProperty::write(QObject *object,
const QString &name,
@ -1452,6 +1456,8 @@ bool QQmlProperty::write(QObject *object,
QQmlProperty p(object, name, engine);
p.write(value);
\endcode
Returns \c true on success, \c false otherwise.
*/
bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
QQmlEngine *engine)

View File

@ -129,15 +129,20 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q
return w.asReturnedValue();
}
static int enumForSingleton(String *name, QObject *qobjectSingleton)
static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton,
QQmlType *type)
{
bool ok;
int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
if (ok)
return value;
// ### Optimize
QByteArray enumName = name->toQString().toUtf8();
const QMetaObject *metaObject = qobjectSingleton->metaObject();
for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
QMetaEnum e = metaObject->enumerator(ii);
bool ok;
int value = e.keyToValue(enumName.constData(), &ok);
value = e.keyToValue(enumName.constData(), &ok);
if (ok)
return value;
}
@ -183,7 +188,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
// check for enum value
const bool includeEnums = w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
const int value = enumForSingleton(name, qobjectSingleton);
const int value = enumForSingleton(v4, name, qobjectSingleton, type);
if (value != -1)
return QV4::Primitive::fromInt32(value).asReturnedValue();
}
@ -196,7 +201,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
// Warn when attempting to access a lowercased enum value, singleton case
if (!ok && includeEnums && !name->startsWithUpper()) {
const int value = enumForSingleton(name, qobjectSingleton);
const int value = enumForSingleton(v4, name, qobjectSingleton, type);
if (value != -1)
return throwLowercaseEnumError(v4, name, type);
}

View File

@ -81,6 +81,14 @@ QAccessibleInterface *QAccessibleQuickWindow::child(int index) const
return 0;
}
QAccessibleInterface *QAccessibleQuickWindow::focusChild() const
{
QObject *focusObject = window()->focusObject();
if (focusObject)
return QAccessible::queryAccessibleInterface(focusObject);
return nullptr;
}
QAccessible::Role QAccessibleQuickWindow::role() const
{
return QAccessible::Window; // FIXME

View File

@ -65,6 +65,7 @@ public:
QAccessibleInterface *parent() const override;
QAccessibleInterface *child(int index) const override;
QAccessibleInterface *focusChild() const override;
QAccessible::Role role() const override;
QAccessible::State state() const override;

View File

@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
//![0]
import QtQuick 2.0
Rectangle {
color: "white"
width: 200
height: 100
Text {
text: "?"
anchors.horizontalCenter: parent.horizontalCenter
function findGreetings() {
var db = openDatabaseSync("QDeclarativeExampleDB", "1.0", "The Example QML SQL!", 1000000);
db.transaction(
function(tx) {
// Create the database if it doesn't already exist
tx.executeSql('CREATE TABLE IF NOT EXISTS Greeting(salutation TEXT, salutee TEXT)');
// Add (another) greeting row
tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ]);
// Show all added greetings
var rs = tx.executeSql('SELECT * FROM Greeting');
var r = ""
for (var i = 0; i < rs.rows.length; i++) {
r += rs.rows.item(i).salutation + ", " + rs.rows.item(i).salutee + "\n"
}
text = r
}
)
}
Component.onCompleted: findGreetings()
}
}
//![0]

View File

@ -64,7 +64,7 @@
In addition to the above features, GridLayout adds these features:
\list
\li \l{Layout::row}{Grid coordinates} can be specified with the \l{Layout::row}{Layout.row} and
\l{Layout::column}{Layout.column}.
\l{Layout::column}{Layout.column} properties.
\li \l{GridLayout::flow}{Automatic grid coordinates} used together with the
\l{GridLayout::flow}{flow}, \l{GridLayout::rows}{rows}, and
\l{GridLayout::columns}{columns} properties.

View File

@ -36,10 +36,10 @@
Models can be defined in C++ and then made available to QML. This is useful
for exposing existing C++ data models or otherwise complex datasets to QML.
A C++ model class can be defined as a \l QStringList, a QObjectList or a
\l QAbstractItemModel. The first two are useful for exposing simpler datasets,
while QAbstractItemModel provides a more flexible solution for more complex
models.
A C++ model class can be defined as a \l QStringList, a \l QVariantList, a
QObjectList or a \l QAbstractItemModel. The first three are useful for exposing
simpler datasets, while QAbstractItemModel provides a more flexible solution for
more complex models.
\section2 QStringList-based Model
@ -60,10 +60,20 @@ The complete source code for this example is available in
\l {models/stringlistmodel}{examples/quick/models/stringlistmodel}
within the Qt install directory.
\b{Note:} There is no way for the view to know that the contents of a QStringList
have changed. If the QStringList changes, it will be necessary to reset
\note There is no way for the view to know that the contents of a QStringList
have changed. If the QStringList changes, it will be necessary to reset
the model by calling QQmlContext::setContextProperty() again.
\section2 QVariantList-based Model
A model may be a single \l QVariantList, which provides the contents of the list
via the \e modelData role.
The API works just like with \l QStringList, as shown in the previous section.
\note There is no way for the view to know that the contents of a QVariantList
have changed. If the QVariantList changes, it will be necessary to reset
the model.
\section2 QObjectList-based model

View File

@ -112,7 +112,7 @@ them, and where possible, pristine Anchor layouts should be preferred.
\section1 Anchors
Anchors allows an item to be placed either adjacent to or inside of another,
Anchors allow an item to be placed either adjacent to or inside of another,
by attaching one or more of the item's anchor-points (boundaries) to an
anchor-point of the other. These anchors will remain even if the dimensions
or location of one of the items changes, allowing for highly dynamic

View File

@ -31,18 +31,14 @@
\section1 Scene Graph Adaptations in Qt Quick
Originally Qt Quick only had one available renderer for parsing the scene graph
and rendering the results to a render target. This renderer is now the default
OpenGL Renderer which supports rendering either using the OpenGL ES 2.0 or
OpenGL 2.0 (with framebuffer object extensions) APIs. The Qt Quick APIs have
originally been designed with the assumption that OpenGL is always available.
However, it is now possible to use other graphics API's to render Qt Quick
scenes using the scene graph APIs.
Originally Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) for parsing
the scene graph and rendering the results to a render target. From Qt 5.8 onwards
Qt Quick also supports rendering in software and with Direct3D 12.
\section1 Switching between the adaptation used by the application
The default of the OpenGL, or - in Qt builds with disabled OpenGL support - the
software adaptation, can be overridden either by using an environment variable
The default rendering backend is still OpenGL, or - in Qt builds with disabled OpenGL support -
the software renderer. This can be overridden either by using an environment variable
or a C++ API. The former consists of setting the \c{QT_QUICK_BACKEND} or the
legacy \c{QMLSCENE_DEVICE} environment variable before launching applications.
The latter is done by calling QQuickWindow::setSceneGraphBackend() early in the

View File

@ -125,7 +125,7 @@ the blue rectangle and beneath any of the blue rectangle's children.
Stacking order can be influenced with the \l Item::z property. Z values below 0 will stack below the parent, and if z
values are assigned then siblings will stack in z-order (with creation order used to break ties). Z values only affect
stacking compared to siblings and the parent item. If you have an item who is obscured by a subtree rooted above its
stacking compared to siblings and the parent item. If you have an item which is obscured by a subtree rooted above its
parent item, no z value on that item will increase its stacking order to stack above that subtree. To stack that item
above the other subtree you'll have to alter z values farther up in the hierarchy, or re-arrange the visual item
hierarchy.

View File

@ -48,6 +48,7 @@
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QOpenGLFunctions>
#include <QtGui/private/qopenglextensions_p.h>
#endif
#include <QtCore/QThread>
#include <QtGui/QGuiApplication>
@ -499,9 +500,9 @@ bool QQuickContext2DFBOTexture::doMultisampling() const
static bool multisamplingSupported = false;
if (!extensionsChecked) {
const QSet<QByteArray> extensions = QOpenGLContext::currentContext()->extensions();
multisamplingSupported = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample"))
&& extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit"));
QOpenGLExtensions *e = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
multisamplingSupported = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
&& e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
extensionsChecked = true;
}

View File

@ -2349,8 +2349,11 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickFlickable);
if (!isVisible() || !isEnabled() || !isInteractive())
if (!isVisible() || !isEnabled() || !isInteractive()) {
d->cancelInteraction();
return QQuickItem::childMouseEventFilter(i, e);
}
switch (e->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseMove:

View File

@ -2911,14 +2911,15 @@ void QQuickItemPrivate::addChild(QQuickItem *child)
childItems.append(child);
#if QT_CONFIG(cursor)
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
#if QT_CONFIG(cursor)
// if the added child has a cursor and we do not currently have any children
// with cursors, bubble the notification up
if (childPrivate->subtreeCursorEnabled && !subtreeCursorEnabled)
setHasCursorInChild(true);
#endif
if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled)
setHasHoverInChild(true);
@ -2939,13 +2940,14 @@ void QQuickItemPrivate::removeChild(QQuickItem *child)
childItems.removeOne(child);
Q_ASSERT(!childItems.contains(child));
#if QT_CONFIG(cursor)
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
#if QT_CONFIG(cursor)
// turn it off, if nothing else is using it
if (childPrivate->subtreeCursorEnabled && subtreeCursorEnabled)
setHasCursorInChild(false);
#endif
if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled)
setHasHoverInChild(false);
@ -3807,10 +3809,10 @@ QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
/*!
This function is called when an item should release graphics
resources which are not already managed by the nodes returend from
resources which are not already managed by the nodes returned from
QQuickItem::updatePaintNode().
This happens when the item is about to be removed from window it
This happens when the item is about to be removed from the window it
was previously rendering to. The item is guaranteed to have a
\l {QQuickItem::window()}{window} when the function is called.

View File

@ -689,9 +689,10 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
#endif
setHovered(true);
d->startScene = event->windowPos();
d->pressAndHoldTimer.start(pressAndHoldInterval(), this);
setKeepMouseGrab(d->stealMouse);
event->setAccepted(setPressed(event->button(), true, event->source()));
if (event->isAccepted())
d->pressAndHoldTimer.start(pressAndHoldInterval(), this);
}
}
@ -738,23 +739,34 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
bool dragY = drag()->axis() & QQuickDrag::YAxis;
QPointF dragPos = d->drag->target()->position();
QPointF boundedDragPos = dragPos;
if (dragX) {
dragPos.setX(qBound(
dragPos.setX(startPos.x() + curLocalPos.x() - startLocalPos.x());
boundedDragPos.setX(qBound(
d->drag->xmin(),
startPos.x() + curLocalPos.x() - startLocalPos.x(),
dragPos.x(),
d->drag->xmax()));
}
if (dragY) {
dragPos.setY(qBound(
dragPos.setY(startPos.y() + curLocalPos.y() - startLocalPos.y());
boundedDragPos.setY(qBound(
d->drag->ymin(),
startPos.y() + curLocalPos.y() - startLocalPos.y(),
dragPos.y(),
d->drag->ymax()));
}
if (d->drag->active())
d->drag->target()->setPosition(dragPos);
if (!d->overThreshold && (QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(), Qt::XAxis, event, d->drag->threshold())
|| QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(), Qt::YAxis, event, d->drag->threshold())))
QPointF targetPos = d->drag->target()->position();
if (d->drag->active())
d->drag->target()->setPosition(boundedDragPos);
bool dragOverThresholdX = QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(),
Qt::XAxis, event, d->drag->threshold());
bool dragOverThresholdY = QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(),
Qt::YAxis, event, d->drag->threshold());
if (!d->overThreshold && (((targetPos.x() != boundedDragPos.x()) && dragOverThresholdX) ||
((targetPos.y() != boundedDragPos.y()) && dragOverThresholdY)))
{
d->overThreshold = true;
if (d->drag->smoothed())

View File

@ -256,10 +256,14 @@ void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item,
qWarning("QQuickOpenGLShaderEffect: property '%s' does not have notification method!", d.name.constData());
} else {
auto *mapper = signalMappers[shaderType].at(i);
mapper->setSignalIndex(pd->notifyIndex());
mapper->setSignalIndex(itemMetaObject->property(d.propertyIndex).notifySignal().methodIndex());
Q_ASSERT(item->metaObject() == itemMetaObject);
QObjectPrivate::connectImpl(item, mapper->signalIndex(), item, nullptr, mapper,
Qt::AutoConnection, nullptr, itemMetaObject);
bool ok = QObjectPrivate::connectImpl(item, pd->notifyIndex(), item, nullptr, mapper,
Qt::AutoConnection, nullptr, itemMetaObject);
if (!ok)
qWarning() << "Failed to connect to property" << itemMetaObject->property(d.propertyIndex).name()
<< "(" << d.propertyIndex << ", signal index" << pd->notifyIndex()
<< ") of item" << item;
}
} else {
// If the source is set via a dynamic property, like the layer is, then we need this

View File

@ -873,4 +873,9 @@ void QQuickShaderEffectPrivate::updatePolish()
q->m_impl->maybeUpdateShaders();
}
bool QQuickShaderEffect::isOpenGLShaderEffect() const
{
return m_glImpl != Q_NULLPTR;
}
QT_END_NAMESPACE

View File

@ -117,6 +117,8 @@ public:
bool isComponentComplete() const;
QString parseLog();
bool isOpenGLShaderEffect() const;
Q_SIGNALS:
void fragmentShaderChanged();
void vertexShaderChanged();

View File

@ -635,8 +635,8 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
// FIXME: make this work for mouse events too and get rid of the asTouchEvent in here.
Q_ASSERT(pointerEvent->asPointerTouchEvent());
QTouchEvent *event = pointerEvent->asPointerTouchEvent()->touchEventForItem(item);
if (!event)
QScopedPointer<QTouchEvent> event(pointerEvent->asPointerTouchEvent()->touchEventForItem(item));
if (event.isNull())
return false;
// For each point, check if it is accepted, if not, try the next point.
@ -653,7 +653,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
break;
qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << item;
QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item, false));
QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event.data(), item, false));
// Send a single press and see if that's accepted
QCoreApplication::sendEvent(item, mousePress.data());
@ -667,7 +667,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
pointerEventPoint->setGrabber(item);
if (checkIfDoubleClicked(event->timestamp())) {
QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item, false));
QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event.data(), item, false));
QCoreApplication::sendEvent(item, mouseDoubleClick.data());
event->setAccepted(mouseDoubleClick->isAccepted());
if (!mouseDoubleClick->isAccepted()) {
@ -684,7 +684,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
} else if (touchMouseDevice == device && p.id() == touchMouseId) {
if (p.state() & Qt::TouchPointMoved) {
if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) {
QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem, false));
QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
event->setAccepted(me->isAccepted());
if (me->isAccepted()) {
@ -695,7 +695,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
// no grabber, check if we care about mouse hover
// FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
// hover for touch???
QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item, false));
QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), item, false));
if (lastMousePosition.isNull())
lastMousePosition = me->windowPos();
QPointF last = lastMousePosition;
@ -713,7 +713,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
} else if (p.state() & Qt::TouchPointReleased) {
// currently handled point was released
if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) {
QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem, false));
QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event.data(), mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
if (item->acceptHoverEvents() && p.screenPos() != QGuiApplicationPrivate::lastCursorPosition) {
@ -4495,8 +4495,8 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const
\note The call to the function must happen before constructing the first
QQuickWindow in the application. It cannot be changed afterwards.
If \a backend is invalid or an error occurs, the default backend (OpenGL or
software, depending on the Qt configuration) is used.
If the selected backend is invalid or an error occurs, the default backend
(OpenGL or software, depending on the Qt configuration) is used.
\since 5.8
*/

View File

@ -44,6 +44,7 @@
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/private/qopenglextensions_p.h>
#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
@ -320,9 +321,9 @@ void QSGDefaultLayer::grab()
if (m_context->openglContext()->format().samples() <= 1) {
m_multisampling = false;
} else {
const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
m_multisampling = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample"))
&& extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit"));
QOpenGLExtensions *e = static_cast<QOpenGLExtensions *>(funcs);
m_multisampling = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
&& e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
}
m_multisamplingChecked = true;
}

View File

@ -238,9 +238,9 @@ void QSGDefaultPainterNode::updateGeometry()
void QSGDefaultPainterNode::updateRenderTarget()
{
if (!m_extensionsChecked) {
const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
m_multisamplingSupported = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample"))
&& extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit"));
QOpenGLExtensions *e = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
m_multisamplingSupported = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
&& e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
m_extensionsChecked = true;
}

View File

@ -47,6 +47,7 @@
#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
# include <private/qquickopenglshadereffectnode_p.h>
# include <private/qquickopenglshadereffect_p.h>
# include <private/qquickshadereffect_p.h>
#endif
#include <private/qanimationgroupjob_p.h>
@ -625,7 +626,8 @@ QQuickUniformAnimatorJob::QQuickUniformAnimatorJob()
void QQuickUniformAnimatorJob::setTarget(QQuickItem *target)
{
if (qobject_cast<QQuickOpenGLShaderEffect *>(target) != nullptr)
QQuickShaderEffect* effect = qobject_cast<QQuickShaderEffect*>(target);
if (effect && effect->isOpenGLShaderEffect())
m_target = target;
}

View File

@ -151,6 +151,8 @@ QQuickTextureFactory *QQuickTextureFactory::textureFactoryForImage(const QImage
If you are using QRunnable as base for your QQuickImageResponse
ensure automatic deletion is disabled.
See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation.
\sa QQuickImageProvider
*/
@ -466,6 +468,8 @@ QQuickTextureFactory *QQuickImageProvider::requestTexture(const QString &id, QSi
\inmodule QtQuick
\brief The QQuickAsyncImageProvider class provides an interface for for asynchronous control of QML image requests.
See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation.
\sa QQuickImageProvider
*/
QQuickAsyncImageProvider::QQuickAsyncImageProvider()

View File

@ -5,7 +5,7 @@ QT_FOR_CONFIG += network quick-private
SUBDIRS += \
qml
qtHaveModule(gui) {
qtHaveModule(gui):qtConfig(animation) {
SUBDIRS += \
quick \
qmltest

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -73,7 +73,7 @@ qtHaveModule(widgets) {
SUBDIRS += $$PUBLICTESTS \
qqmlextensionplugin
SUBDIRS += $$METATYPETESTS
!qtConfig(process) {
qtConfig(process) {
!contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger
SUBDIRS += qmllint qmlplugindump
}

View File

@ -0,0 +1,12 @@
import QtQml 2.2
import x.y.z 1.0
QtObject {
function x() {
eval("1");
return ExternalEnums.DocumentsLocation;
}
property var a: ExternalEnums.DocumentsLocation
property var b: x()
}

View File

@ -26,6 +26,7 @@
**
****************************************************************************/
#include <qstandardpaths.h>
#include <qtest.h>
#include <qqml.h>
#include <qqmlprivate.h>
@ -53,6 +54,7 @@ private slots:
void invalidQmlTypeName();
void registrationType();
void compositeType();
void externalEnums();
void isList();
@ -70,6 +72,20 @@ public:
};
QML_DECLARE_TYPE(TestType);
class ExternalEnums : public QObject
{
Q_OBJECT
Q_ENUMS(QStandardPaths::StandardLocation QStandardPaths::LocateOptions)
public:
ExternalEnums(QObject *parent = nullptr) : QObject(parent) {}
static QObject *create(QQmlEngine *engine, QJSEngine *scriptEngine) {
Q_UNUSED(scriptEngine);
return new ExternalEnums(engine);
}
};
QML_DECLARE_TYPE(ExternalEnums);
QObject *testTypeProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
@ -271,6 +287,23 @@ void tst_qqmlmetatype::compositeType()
QCOMPARE(type->sourceUrl(), testFileUrl("ImplicitType.qml"));
}
void tst_qqmlmetatype::externalEnums()
{
QQmlEngine engine;
qmlRegisterSingletonType<ExternalEnums>("x.y.z", 1, 0, "ExternalEnums", ExternalEnums::create);
QQmlComponent c(&engine, testFileUrl("testExternalEnums.qml"));
QObject *obj = c.create();
QVERIFY(obj);
QVariant a = obj->property("a");
QCOMPARE(a.type(), QVariant::Int);
QCOMPARE(a.toInt(), int(QStandardPaths::DocumentsLocation));
QVariant b = obj->property("b");
QCOMPARE(b.type(), QVariant::Int);
QCOMPARE(b.toInt(), int(QStandardPaths::DocumentsLocation));
}
QTEST_MAIN(tst_qqmlmetatype)
#include "tst_qqmlmetatype.moc"

View File

@ -0,0 +1,23 @@
import QtQuick 2.0
Item {
id: root
property real test: 9
property real test2: 3
property alias aliasProperty: innerObject.realProperty
property QtObject innerObject: QtObject {
id: innerObject
property real realProperty: test * test + test
}
states: State {
name: "switch"
PropertyChanges {
target: root
aliasProperty: 32 * test2
}
}
}

View File

@ -135,6 +135,7 @@ private slots:
// Bugs
void crashOnValueProperty();
void aliasPropertyBindings_data();
void aliasPropertyBindings();
void noContext();
void assignEmptyVariantMap();
@ -1833,23 +1834,40 @@ void tst_qqmlproperty::crashOnValueProperty()
QCOMPARE(p.read(), QVariant(20));
}
// QTBUG-13719
void tst_qqmlproperty::aliasPropertyBindings_data()
{
QTest::addColumn<QString>("file");
QTest::addColumn<QString>("subObject");
QTest::newRow("same object") << "aliasPropertyBindings.qml" << "";
QTest::newRow("different objects") << "aliasPropertyBindings2.qml" << "innerObject";
}
// QTBUG-13719, QTBUG-58271
void tst_qqmlproperty::aliasPropertyBindings()
{
QQmlComponent component(&engine, testFileUrl("aliasPropertyBindings.qml"));
QFETCH(QString, file);
QFETCH(QString, subObject);
QQmlComponent component(&engine, testFileUrl(file));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("realProperty").toReal(), 90.);
// the object where realProperty lives
QObject *realPropertyObject = object;
if (!subObject.isEmpty())
realPropertyObject = object->property(subObject.toLatin1()).value<QObject*>();
QCOMPARE(realPropertyObject->property("realProperty").toReal(), 90.);
QCOMPARE(object->property("aliasProperty").toReal(), 90.);
object->setProperty("test", 10);
QCOMPARE(object->property("realProperty").toReal(), 110.);
QCOMPARE(realPropertyObject->property("realProperty").toReal(), 110.);
QCOMPARE(object->property("aliasProperty").toReal(), 110.);
QQmlProperty realProperty(object, QLatin1String("realProperty"));
QQmlProperty realProperty(realPropertyObject, QLatin1String("realProperty"));
QQmlProperty aliasProperty(object, QLatin1String("aliasProperty"));
// Check there is a binding on these two properties
@ -1868,18 +1886,18 @@ void tst_qqmlproperty::aliasPropertyBindings()
QCOMPARE(QQmlPropertyPrivate::binding(realProperty),
QQmlPropertyPrivate::binding(aliasProperty));
QCOMPARE(object->property("realProperty").toReal(), 96.);
QCOMPARE(realPropertyObject->property("realProperty").toReal(), 96.);
QCOMPARE(object->property("aliasProperty").toReal(), 96.);
// Check the old binding really has not effect any more
object->setProperty("test", 4);
QCOMPARE(object->property("realProperty").toReal(), 96.);
QCOMPARE(realPropertyObject->property("realProperty").toReal(), 96.);
QCOMPARE(object->property("aliasProperty").toReal(), 96.);
object->setProperty("test2", 9);
QCOMPARE(object->property("realProperty").toReal(), 288.);
QCOMPARE(realPropertyObject->property("realProperty").toReal(), 288.);
QCOMPARE(object->property("aliasProperty").toReal(), 288.);
// Revert
@ -1890,12 +1908,12 @@ void tst_qqmlproperty::aliasPropertyBindings()
QCOMPARE(QQmlPropertyPrivate::binding(realProperty),
QQmlPropertyPrivate::binding(aliasProperty));
QCOMPARE(object->property("realProperty").toReal(), 20.);
QCOMPARE(realPropertyObject->property("realProperty").toReal(), 20.);
QCOMPARE(object->property("aliasProperty").toReal(), 20.);
object->setProperty("test2", 3);
QCOMPARE(object->property("realProperty").toReal(), 20.);
QCOMPARE(realPropertyObject->property("realProperty").toReal(), 20.);
QCOMPARE(object->property("aliasProperty").toReal(), 20.);
delete object;
@ -1996,7 +2014,7 @@ void tst_qqmlproperty::warnOnInvalidBinding()
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
// V8 error message for invalid binding to anchor
expectedWarning = testUrl.toString() + QString::fromLatin1(":14:33: Unable to assign QQuickItem_QML_6 to QQuickAnchorLine");
expectedWarning = testUrl.toString() + QString::fromLatin1(":14:33: Unable to assign QQuickItem_QML_8 to QQuickAnchorLine");
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
QQmlComponent component(&engine, testUrl);

View File

@ -28,6 +28,7 @@
#include <qtest.h>
#define V4_AUTOTEST
#include <private/qv4ssa_p.h>
class tst_v4misc: public QObject
@ -40,6 +41,9 @@ private slots:
void rangeSplitting_1();
void rangeSplitting_2();
void rangeSplitting_3();
void moveMapping_1();
void moveMapping_2();
};
QT_BEGIN_NAMESPACE
@ -139,6 +143,94 @@ void tst_v4misc::rangeSplitting_3()
QCOMPARE(interval.end(), 71);
}
void tst_v4misc::moveMapping_1()
{
Temp fp2(DoubleType, Temp::PhysicalRegister, 2);
Temp fp3(DoubleType, Temp::PhysicalRegister, 3);
Temp fp4(DoubleType, Temp::PhysicalRegister, 4);
Temp fp5(DoubleType, Temp::PhysicalRegister, 5);
MoveMapping mapping;
mapping.add(&fp2, &fp3);
mapping.add(&fp2, &fp4);
mapping.add(&fp2, &fp5);
mapping.add(&fp3, &fp2);
mapping.order();
// mapping.dump();
QCOMPARE(mapping._moves.size(), 3);
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp2, &fp4, false)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp2, &fp5, false)));
QVERIFY(mapping._moves.last() == MoveMapping::Move(&fp2, &fp3, true) ||
mapping._moves.last() == MoveMapping::Move(&fp3, &fp2, true));
}
void tst_v4misc::moveMapping_2()
{
Temp fp1(DoubleType, Temp::PhysicalRegister, 1);
Temp fp2(DoubleType, Temp::PhysicalRegister, 2);
Temp fp3(DoubleType, Temp::PhysicalRegister, 3);
Temp fp4(DoubleType, Temp::PhysicalRegister, 4);
Temp fp5(DoubleType, Temp::PhysicalRegister, 5);
Temp fp6(DoubleType, Temp::PhysicalRegister, 6);
Temp fp7(DoubleType, Temp::PhysicalRegister, 7);
Temp fp8(DoubleType, Temp::PhysicalRegister, 8);
Temp fp9(DoubleType, Temp::PhysicalRegister, 9);
Temp fp10(DoubleType, Temp::PhysicalRegister, 10);
Temp fp11(DoubleType, Temp::PhysicalRegister, 11);
Temp fp12(DoubleType, Temp::PhysicalRegister, 12);
Temp fp13(DoubleType, Temp::PhysicalRegister, 13);
MoveMapping mapping;
mapping.add(&fp2, &fp1);
mapping.add(&fp2, &fp3);
mapping.add(&fp3, &fp2);
mapping.add(&fp3, &fp4);
mapping.add(&fp9, &fp8);
mapping.add(&fp8, &fp7);
mapping.add(&fp7, &fp6);
mapping.add(&fp7, &fp5);
mapping.add(&fp10, &fp11);
mapping.add(&fp11, &fp12);
mapping.add(&fp12, &fp13);
mapping.add(&fp13, &fp10);
mapping.order();
// mapping.dump();
QCOMPARE(mapping._moves.size(), 10);
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp2, &fp1, false)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp3, &fp4, false)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp7, &fp6, false)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp7, &fp5, false)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp8, &fp7, false)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp9, &fp8, false)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp2, &fp3, true)) ||
mapping._moves.contains(MoveMapping::Move(&fp3, &fp2, true)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp10, &fp13, true)) ||
mapping._moves.contains(MoveMapping::Move(&fp13, &fp10, true)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp12, &fp13, true)) ||
mapping._moves.contains(MoveMapping::Move(&fp13, &fp12, true)));
QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp12, &fp11, true)) ||
mapping._moves.contains(MoveMapping::Move(&fp11, &fp12, true)));
QVERIFY(!mapping._moves.at(0).needsSwap);
QVERIFY(!mapping._moves.at(1).needsSwap);
QVERIFY(!mapping._moves.at(2).needsSwap);
QVERIFY(!mapping._moves.at(3).needsSwap);
QVERIFY(!mapping._moves.at(4).needsSwap);
QVERIFY(!mapping._moves.at(5).needsSwap);
QVERIFY(mapping._moves.at(6).needsSwap);
QVERIFY(mapping._moves.at(7).needsSwap);
QVERIFY(mapping._moves.at(8).needsSwap);
QVERIFY(mapping._moves.at(9).needsSwap);
}
QTEST_MAIN(tst_v4misc)
#include "tst_v4misc.moc"

View File

@ -0,0 +1,13 @@
import QtQuick 2.0
Flickable {
id: flickable
width: 200; height: 200
contentWidth: 400; contentHeight: 400
MouseArea {
objectName: "mouseArea"
width: 400; height: 400
onDoubleClicked: flickable.visible = false
}
}

View File

@ -80,6 +80,7 @@ private slots:
void disabled();
void flickVelocity();
void margins();
void cancelOnHide();
void cancelOnMouseGrab();
void clickAndDragWhenTransformed();
void flickTwiceUsingTouches();
@ -1425,6 +1426,25 @@ void tst_qquickflickable::margins()
delete root;
}
void tst_qquickflickable::cancelOnHide()
{
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("hide.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
QQuickViewTestUtil::centerOnScreen(window.data());
QQuickViewTestUtil::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject());
QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable);
QTest::mouseDClick(window.data(), Qt::LeftButton);
QVERIFY(!flickable->isVisible());
QVERIFY(!QQuickFlickablePrivate::get(flickable)->pressed);
}
void tst_qquickflickable::cancelOnMouseGrab()
{
QScopedPointer<QQuickView> window(new QQuickView);

View File

@ -0,0 +1,24 @@
import QtQuick 2.0
Rectangle {
width: 400
height: 200
MouseArea {
id: mouseArea
objectName: "mouseArea"
width: 200
height: 200
drag.target: mouseArea
drag.axis: Drag.XAxis
drag.minimumX: 0
drag.maximumX: 200
drag.threshold: 200
Rectangle {
anchors.fill: parent
color: "red"
}
}
}

View File

@ -88,6 +88,7 @@ private slots:
void invalidDrag_data() { rejectedButton_data(); }
void invalidDrag();
void cancelDragging();
void availableDistanceLessThanDragThreshold();
void setDragOnPressed();
void updateMouseAreaPosOnClick();
void updateMouseAreaPosOnResize();
@ -585,6 +586,35 @@ void tst_QQuickMouseArea::cancelDragging()
QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(122,122));
}
// QTBUG-58347
void tst_QQuickMouseArea::availableDistanceLessThanDragThreshold()
{
QQuickView view;
QByteArray errorMessage;
QVERIFY2(initView(view, testFileUrl("availableDistanceLessThanDragThreshold.qml"), true, &errorMessage),
errorMessage.constData());
view.show();
view.requestActivate();
QVERIFY(QTest::qWaitForWindowExposed(&view));
QVERIFY(view.rootObject());
QQuickMouseArea *mouseArea = view.rootObject()->findChild<QQuickMouseArea*>("mouseArea");
QVERIFY(mouseArea);
QPoint position(100, 100);
QTest::mousePress(&view, Qt::LeftButton, 0, position);
QTest::qWait(10);
position.setX(301);
QTest::mouseMove(&view, position);
position.setX(501);
QTest::mouseMove(&view, position);
QVERIFY(mouseArea->drag()->active());
QTest::mouseRelease(&view, Qt::LeftButton, 0, position);
QVERIFY(!mouseArea->drag()->active());
QCOMPARE(mouseArea->x(), 200.0);
}
void tst_QQuickMouseArea::setDragOnPressed()
{
QQuickView window;

View File

@ -6,6 +6,15 @@ HEADERS += conf.h
SOURCES += main.cpp
RESOURCES += qml.qrc
QMAKE_TARGET_PRODUCT = qml
QMAKE_TARGET_DESCRIPTION = Utility that loads and displays QML documents
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
mac {
OTHER_FILES += Info.plist
QMAKE_INFO_PLIST = Info.plist

View File

@ -17,4 +17,13 @@ FORMS += \
pane.ui \
import.ui
QMAKE_TARGET_PRODUCT = qmleasing
QMAKE_TARGET_DESCRIPTION = QML easing curve editor
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_app)

View File

@ -5,4 +5,13 @@ DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
SOURCES += main.cpp
QMAKE_TARGET_PRODUCT = qmlimportscanner
QMAKE_TARGET_DESCRIPTION = Tool to scan projects for QML imports
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_tool)

View File

@ -5,4 +5,13 @@ SOURCES = qmljs.cpp
include($$PWD/../../src/3rdparty/masm/masm-defs.pri)
QMAKE_TARGET_PRODUCT = qmljs
QMAKE_TARGET_DESCRIPTION = QML Javascript tool
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_tool)

View File

@ -4,4 +4,13 @@ QT = core qmldevtools-private
SOURCES += main.cpp
QMAKE_TARGET_PRODUCT = qmllint
QMAKE_TARGET_DESCRIPTION = QML syntax verifier
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_tool)

View File

@ -2,4 +2,13 @@ option(host_build)
QT = core qmldevtools-private
SOURCES += main.cpp
QMAKE_TARGET_PRODUCT = qmlmin
QMAKE_TARGET_DESCRIPTION = QML/JS minifier
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_tool)

View File

@ -33,6 +33,10 @@
#include <QtQuick/private/qquickevents_p_p.h>
#include <QtQuick/private/qquickpincharea_p.h>
#ifdef QT_WIDGETS_LIB
#include <QApplication>
#endif // QT_WIDGETS_LIB
#include <QtGui/QGuiApplication>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
@ -741,8 +745,8 @@ void sigSegvHandler(int) {
void printUsage(const QString &appName)
{
std::cerr << qPrintable(QString(
"Usage: %1 [-v] [-noinstantiate] [-defaultplatform] [-[non]relocatable] [-dependencies <dependencies.json>] [-merge <file-to-merge.qmltypes>] [-output <output-file.qmltypes>] [-noforceqtquick] module.uri version [module/import/path]\n"
" %1 [-v] [-noinstantiate] -path path/to/qmldir/directory [version]\n"
"Usage: %1 [-v] [-qapp] [-noinstantiate] [-defaultplatform] [-[non]relocatable] [-dependencies <dependencies.json>] [-merge <file-to-merge.qmltypes>] [-output <output-file.qmltypes>] [-noforceqtquick] module.uri version [module/import/path]\n"
" %1 [-v] [-qapp] [-noinstantiate] -path path/to/qmldir/directory [version]\n"
" %1 [-v] -builtins\n"
"Example: %1 Qt.labs.folderlistmodel 2.0 /home/user/dev/qt-install/imports").arg(
appName)) << std::endl;
@ -866,7 +870,7 @@ static bool getDependencies(const QQmlEngine &engine, const QString &pluginImpor
QByteArray depencenciesData = importScanner.readAllStandardOutput();
if (!readDependenciesData(QLatin1String("<outputOfQmlimportscanner>"), depencenciesData,
dependencies, QStringList(pluginImportUri), forceQtQuickDependency)) {
std::cerr << "failed to proecess output of qmlimportscanner" << std::endl;
std::cerr << "failed to process output of qmlimportscanner" << std::endl;
if (importScanner.exitCode() != 0)
std::cerr << importScanner.readAllStandardError().toStdString();
return false;
@ -992,10 +996,25 @@ int main(int argc, char *argv[])
else
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
QGuiApplication app(argc, argv);
// Check which kind of application should be instantiated.
bool useQApplication = false;
for (int i = 0; i < argc; ++i) {
QString arg = QLatin1String(argv[1]);
if (arg == QLatin1String("--qapp") || arg == QLatin1String("-qapp"))
useQApplication = true;
}
#ifdef QT_WIDGETS_LIB
QScopedPointer<QCoreApplication> app(useQApplication
? new QApplication(argc, argv)
: new QGuiApplication(argc, argv));
#else
QScopedPointer<QCoreApplication> app(new QGuiApplication(argc, argv));
#endif // QT_WIDGETS_LIB
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
const QStringList args = app.arguments();
const QString appName = QFileInfo(app.applicationFilePath()).baseName();
const QStringList args = app->arguments();
const QString appName = QFileInfo(app->applicationFilePath()).baseName();
if (args.size() < 2) {
printUsage(appName);
return EXIT_INVALIDARGUMENTS;
@ -1065,6 +1084,9 @@ int main(int argc, char *argv[])
} else if (arg == QLatin1String("--defaultplatform")
|| arg == QLatin1String("-defaultplatform")) {
continue;
} else if (arg == QLatin1String("--qapp")
|| arg == QLatin1String("-qapp")) {
continue;
} else {
std::cerr << "Invalid argument: " << qPrintable(arg) << std::endl;
return EXIT_INVALIDARGUMENTS;
@ -1331,8 +1353,8 @@ int main(int argc, char *argv[])
QTimer timer;
timer.setSingleShot(true);
timer.setInterval(0);
QObject::connect(&timer, SIGNAL(timeout()), &app, SLOT(quit()));
QObject::connect(&timer, SIGNAL(timeout()), app.data(), SLOT(quit()));
timer.start();
return app.exec();
return app->exec();
}

View File

@ -1,4 +1,5 @@
QT += qml qml-private quick-private core-private
qtHaveModule(widgets): QT += widgets
CONFIG += no_import_scan
@ -21,4 +22,13 @@ macx {
CONFIG -= app_bundle
}
QMAKE_TARGET_PRODUCT = qmlplugindump
QMAKE_TARGET_DESCRIPTION = QML plugin dump tool
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_tool)

View File

@ -14,4 +14,13 @@ HEADERS += \
qmlprofilerdata.h \
qmlprofilerclient.h
QMAKE_TARGET_PRODUCT = qmlprofiler
QMAKE_TARGET_DESCRIPTION = QML profiler
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_tool)

View File

@ -7,4 +7,13 @@ SOURCES += main.cpp
DEFINES += QML_RUNTIME_TESTING
!contains(QT_CONFIG, no-qml-debug): DEFINES += QT_QML_DEBUG_NO_WARNING
QMAKE_TARGET_PRODUCT = qmlscene
QMAKE_TARGET_DESCRIPTION = Utility that loads and displays QML documents
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_tool)

View File

@ -3,4 +3,13 @@ SOURCES += main.cpp
QT += qml qmltest
CONFIG += no_import_scan
QMAKE_TARGET_PRODUCT = qmltestrunner
QMAKE_TARGET_DESCRIPTION = QML test runner
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
load(qt_tool)

View File

@ -4,4 +4,13 @@ QT += qml quick
QT += quick-private
macx:CONFIG -= app_bundle
QMAKE_TARGET_PRODUCT = qmltime
QMAKE_TARGET_DESCRIPTION = Tool for benchmarking the instantiation of a QML component
win32 {
VERSION = $${QT_VERSION}.0
} else {
VERSION = $${QT_VERSION}
}
SOURCES += qmltime.cpp

View File

@ -16,8 +16,12 @@ SUBDIRS += \
!static: {
SUBDIRS += \
qmlscene \
qmlplugindump \
qmltime
qtConfig(regularexpression) {
SUBDIRS += \
qmlplugindump
}
}
qtHaveModule(widgets): SUBDIRS += qmleasing
}