From ea6675374fa6e94bd4cf10613c85cee2c724bcdc Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 23 Jan 2018 10:25:54 -0800 Subject: [PATCH 01/20] QString: fix comparisons to null strings in ucstricmp Commit 8f52ad9fe084eee26869e4a94a678076845a6f58 ("ucstricmp: compare null and empty strings equal") made sure empties and nulls would compare equally, but may have broken the null vs non-empty comparison (which was not tested). The commit message also said that it expected all callers to handle null before calling into those functions, but that's not the case for QStringView created from a null QString: the incoming "a" pointer was null. So just remove the checks for null pointers and rely on the size checks doing the right thing. [ChangeLog][QtCore][QString] Fixed a regression from 5.9 that caused comparing default-constructed QStrings to be sorted after non-empty strings. Task-number: QTBUG-65939 Change-Id: I56b444f9d6274221a3b7fffd150c83ad46c599b6 Reviewed-by: Lars Knoll --- src/corelib/tools/qstring.cpp | 9 --------- tests/auto/corelib/tools/qstring/tst_qstring.cpp | 8 +++++++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 30f8948eec..80c8510fa4 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -423,10 +423,6 @@ static int ucstricmp(const QChar *a, const QChar *ae, const QChar *b, const QCha { if (a == b) return (ae - be); - if (a == 0) - return be - b; - if (b == 0) - return a - ae; const QChar *e = ae; if (be - b < ae - a) @@ -455,11 +451,6 @@ static int ucstricmp(const QChar *a, const QChar *ae, const QChar *b, const QCha // Case-insensitive comparison between a Unicode string and a QLatin1String static int ucstricmp(const QChar *a, const QChar *ae, const char *b, const char *be) { - if (!a) - return be - b; - if (!b) - return a - ae; - auto e = ae; if (be - b < ae - a) e = a + (be - b); diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index 70ccc72630..a028391b06 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -6043,8 +6043,14 @@ void tst_QString::compare_data() QTest::addColumn("csr"); // case sensitive result QTest::addColumn("cir"); // case insensitive result - // null strings + QTest::newRow("null-null") << QString() << QString() << 0 << 0; + QTest::newRow("text-null") << QString("a") << QString() << 1 << 1; + QTest::newRow("null-text") << QString() << QString("a") << -1 << -1; + QTest::newRow("null-empty") << QString() << QString("") << 0 << 0; + QTest::newRow("empty-null") << QString("") << QString() << 0 << 0; + + // empty strings QTest::newRow("data0") << QString("") << QString("") << 0 << 0; QTest::newRow("data1") << QString("a") << QString("") << 1 << 1; QTest::newRow("data2") << QString("") << QString("a") << -1 << -1; From 75c22d459872aca47ac2bb9e0e88d63f4f0b5d38 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 7 Feb 2018 14:08:17 +0100 Subject: [PATCH 02/20] QCocoaWindow: be more careful when flushing events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flushing the QPA event queue is problematic since we can then end up delivering several events to Qt (or the app) at the same time on the call stack. This again can easily leave objects in an inconsistent state if they receive callbacks from subsequent events while being occupied processing the first. This is also what happens in the listed report. A QMenu shows a sub menu when the mouse enters a menu item. The show leads to QPA flushing events, which in some cases also includes flushing another pending move event. The move event is delivered to the same QMenu, which will clear a private variable (currentAction). When the show returns, the state of QMenu has unexpectedly changed, which causes a crash to happen since currentAction is null. This patch will fix the root cause of the problem by stopping QCocoaWindow from flushing user input events when the call location does a flush to deliver geometry events. Task-number: QTBUG-66093 Change-Id: Id277550b0a080ad98c81e8c30dc7098dc73723d5 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index af2931c747..683834c1a0 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1131,7 +1131,7 @@ void QCocoaWindow::handleGeometryChange() // Guard against processing window system events during QWindow::setGeometry // calls, which Qt and Qt applications do not expect. if (!m_inSetGeometry) - QWindowSystemInterface::flushWindowSystemEvents(); + QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); } void QCocoaWindow::handleExposeEvent(const QRegion ®ion) From 41bcb31ab9538328ca05efcb4a01569c9803198c Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Tue, 30 Jan 2018 15:41:42 +0200 Subject: [PATCH 03/20] Add changes file for Qt 5.10.1 Done-with: Thiago Macieira Done-with: Oswald Buddenhagen Change-Id: I9f3c5a830d210e1224ffbc69979733ec7cf629c6 Reviewed-by: Thiago Macieira --- dist/changes-5.10.1 | 154 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 dist/changes-5.10.1 diff --git a/dist/changes-5.10.1 b/dist/changes-5.10.1 new file mode 100644 index 0000000000..1c9854fa64 --- /dev/null +++ b/dist/changes-5.10.1 @@ -0,0 +1,154 @@ +Qt 5.10.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.10.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.10 series is binary compatible with the 5.9.x series. +Applications compiled for 5.9 will continue to run with 5.10. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +This release contains all fixes included in the Qt 5.9.4 release. + +**************************************************************************** +* Library * +**************************************************************************** + +QtCore +------ + + - [QTBUG-64529] Fixed a compilation issue with qfloat16 if AVX2 support is + enabled in the compiler. Since all processors that support AVX2 also + support F16C, for GCC and Clang it is recommended to either add -mf16c + to your build or to use the corresponding -march= switch. + + - QCoreApplication: + * [QTBUG-58919] Fixed a crash if QCoreApplication is recreated on Windows + and the passed argv parameter is different. + + - QFile: + * [QTBUG-64103] Fixed a regression in doing rename() on Android + Marshmallow. + + - QFileInfo: + * [QTBUG-30148] Fixed isWritable() on Windows to return whether the given + file is writable only under current privilege levels. Previously, the + result would take into account privilege elevation. + + - QMetaObject: + * [QTBUG-65462] Fixed a memory leak that happened when the new-style + call to invokeMethod() was used. + + - QObject: + * [QTBUG-65712] Improved performance of QObject::deleteLater. + * Fixed a crash that could happen if the context QObject pointer passed to + new-style connect() was null. + + - QPluginLoader: + * [QTBUG-65197] Fixed a bug that would cause the Qt plugin scanning + system to allocate too much memory and possibly crash the process. + + - QProcess: + * [QTBUG-65076] Fixed a regression that made QProcess be unable to find + executables when the PATH environment variable on some Unix systems + wasn't set. This behavior should not be relied upon since many systems + do not have sensible fallback values for PATH. + + - QRandomGenerator: + * [QTBUG-65414] Fixed compilation on Windows if the windows.h header was + included before this qrandom.h. + + - QSettings: + * [QTBUG-64121] Fixed reading from NTFS symbolic links. + + - QStandardPaths: + * [QTBUG-65076] findExecutable() will now apply the default value for + the PATH environment variable (as returned by the POSIX confstr(3) + function or found in ) if the variable isn't set in the + environment. + * [QTBUG-65687] Fixed a memory leak with displayName() on Apple platforms. + * On Windows, it is now possible to resolve configuration paths even + without QCoreApplication created. + + - QString: + * [QTBUG-65939] Fixed a regression from 5.9 that caused comparing + default-constructed QStrings to be sorted after non-empty strings. + + - QTextBoundaryFinder: + * [QTBUG-63191] Fixed a bug in the generating of Unicode data, affecting + the joining properties of characters like U+200C ZWNJ. + + - QXmlStreamWriter: + * [QTBUG-63538] Empty namespace URIs are now possible. + + - State Machine: + * [QTBUG-61463] Fixed a failed assertion that could happen when emitting a + signal from another thread. + +QtGui +----- + + - Text: + * [QTBUG-61882] Fixed a bug where mixing different writing systems with + emojis could lead to missing glyphs. + * [QTBUG-65519] Fixed ZWJ and ZWNJ control characters when fallback + fonts are in use. + +**************************************************************************** +* Platform-specific Changes * +**************************************************************************** + + - QNX: + * [QTBUG-64033] Fixed the detection of slog2 with QNX 7.0 + + - Windows: + * Named pipes internally created by QProcess now contain the PID in their + name to ensure uniqueness. + * [QTBUG-65940] Fixed asserts and crashes in QWinEventNotifier. + + - WinRT: + * -qdevel and -qdebug are removed from the command line arguments and + not passed to the application. + +**************************************************************************** +* Third-Party Code * +**************************************************************************** + + - libjpeg-turbo was updated to version 1.5.3 + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - [QTBUG-65753] Fixed installation of resource sources in some examples. + - Qt's pkg-config .pc files now add -DQT_{module}_LIB to CFLAGS. + +qmake +----- + + - [QTBUG-65106] The value of QT is now silently ignored when the sub- + project already failed requires()/REQUIRES. + - [QTBUG-63442] Fixed an issue that would cause warnings with CMake 3.10 + for projects that used AUTOMOC. + - [QTBUG-63637][MinGW] Fixed cross compilation from Linux. + - [QTBUG-65103] Introduced precompile_header_c CONFIG option for MSVC to + enable precompiled header for C sources. + - [QTBUG-65477][Darwin] Added escaping to @BUNDLEIDENTIFIER@. + - [Darwin] Rewrote handling of placeholders in Info.plist; the preferred + style is now ${} and is consistent between Xcode and Makefile generators. + - [Windows] Fixed path separators when setting working directory in + "make check". + - [Windows] Paths which are relative to the current drive's root are not + treated as absolute any more. From 6c6ace9d23f90845fd424e474d38fe30f070775e Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 8 Jan 2018 15:48:01 +0100 Subject: [PATCH 04/20] psql: Improve performance of record() In order to save having to always run a query to get the tablename for a known oid then we cache the result on the driver side. The oid stays the same while the table exists, so only on dropping it would it change. Recreating the table causes it to get a new oid, so there is no risk of the old one being associated with the wrong table when this happens, if the driver is still open at that point. The benchmark added shows the improvement from the previous code, before the results for PostgreSQL was: RESULT : tst_QSqlRecord::benchmarkRecord():"0_QPSQL@localhost": 259 msecs per iteration (total: 259, iterations: 1) whereas now it is: RESULT : tst_QSqlRecord::benchmarkRecord():"0_QPSQL@localhost": 0.000014 msecs per iteration (total: 59, iterations: 4194304) Task-number: QTBUG-65226 Change-Id: Ic290cff719102743da84e2044cd23e540f20c96c Reviewed-by: Christian Ehrlicher Reviewed-by: Robert Szefner Reviewed-by: Edward Welbourne --- src/plugins/sqldrivers/psql/qsql_psql.cpp | 14 +- .../sql/kernel/qsqlquery/tst_qsqlquery.cpp | 46 ++++- tests/benchmarks/sql/kernel/kernel.pro | 1 + .../sql/kernel/qsqlrecord/qsqlrecord.pro | 5 + .../sql/kernel/qsqlrecord/tst_qsqlrecord.cpp | 191 ++++++++++++++++++ 5 files changed, 252 insertions(+), 5 deletions(-) create mode 100644 tests/benchmarks/sql/kernel/qsqlrecord/qsqlrecord.pro create mode 100644 tests/benchmarks/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 35b0f9a3e3..c381572713 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -183,6 +183,7 @@ public: void setDatestyle(); void setByteaOutput(); void detectBackslashEscape(); + mutable QHash oidToTable; }; void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) @@ -553,11 +554,16 @@ QSqlRecord QPSQLResult::record() const f.setName(QString::fromUtf8(PQfname(d->result, i))); else f.setName(QString::fromLocal8Bit(PQfname(d->result, i))); - QSqlQuery qry(driver()->createResult()); - if (qry.exec(QStringLiteral("SELECT relname FROM pg_class WHERE pg_class.oid = %1") - .arg(PQftable(d->result, i))) && qry.next()) { - f.setTableName(qry.value(0).toString()); + const int tableOid = PQftable(d->result, i); + auto &tableName = d->drv_d_func()->oidToTable[tableOid]; + if (tableName.isEmpty()) { + QSqlQuery qry(driver()->createResult()); + if (qry.exec(QStringLiteral("SELECT relname FROM pg_class WHERE pg_class.oid = %1") + .arg(tableOid)) && qry.next()) { + tableName = qry.value(0).toString(); + } } + f.setTableName(tableName); int ptype = PQftype(d->result, i); f.setType(qDecodePSQLType(ptype)); int len = PQfsize(d->result, i); diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index 1a0340f153..58b87180c8 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -363,7 +363,8 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) << qTableName("task_234422", __FILE__, db) << qTableName("test141895", __FILE__, db) << qTableName("qtest_oraOCINumber", __FILE__, db) - << qTableName("bug2192", __FILE__, db); + << qTableName("bug2192", __FILE__, db) + << qTableName("tst_record", __FILE__, db); if (dbType == QSqlDriver::PostgreSQL) tablenames << qTableName("task_233829", __FILE__, db); @@ -978,6 +979,29 @@ void tst_QSqlQuery::value() } } +#define SETUP_RECORD_TABLE \ + do { \ + QVERIFY_SQL(q, exec("CREATE TABLE " + tst_record + " (id integer, extra varchar(50))")); \ + for (int i = 0; i < 3; ++i) \ + QVERIFY_SQL(q, exec(QString("INSERT INTO " + tst_record + " VALUES(%1, 'extra%1')").arg(i))); \ + } while (0) + +#define CHECK_RECORD \ + do { \ + QVERIFY_SQL(q, exec(QString("select %1.id, %1.t_varchar, %1.t_char, %2.id, %2.extra from %1, %2 where " \ + "%1.id = %2.id order by %1.id").arg(lowerQTest).arg(tst_record))); \ + QCOMPARE(q.record().fieldName(0).toLower(), QString("id")); \ + QCOMPARE(q.record().field(0).tableName().toLower(), lowerQTest); \ + QCOMPARE(q.record().fieldName(1).toLower(), QString("t_varchar")); \ + QCOMPARE(q.record().field(1).tableName().toLower(), lowerQTest); \ + QCOMPARE(q.record().fieldName(2).toLower(), QString("t_char")); \ + QCOMPARE(q.record().field(2).tableName().toLower(), lowerQTest); \ + QCOMPARE(q.record().fieldName(3).toLower(), QString("id")); \ + QCOMPARE(q.record().field(3).tableName().toLower(), tst_record); \ + QCOMPARE(q.record().fieldName(4).toLower(), QString("extra")); \ + QCOMPARE(q.record().field(4).tableName().toLower(), tst_record); \ + } while (0) + void tst_QSqlQuery::record() { QFETCH( QString, dbName ); @@ -999,6 +1023,26 @@ void tst_QSqlQuery::record() QCOMPARE( q.record().fieldName( 0 ).toLower(), QString( "id" ) ); QCOMPARE( q.value( 0 ).toInt(), 2 ); + + const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); + if (dbType == QSqlDriver::Oracle) + QSKIP("Getting the tablename is not supported in Oracle"); + const auto lowerQTest = qtest.toLower(); + for (int i = 0; i < 3; ++i) + QCOMPARE(q.record().field(i).tableName().toLower(), lowerQTest); + q.clear(); + const auto tst_record = qTableName("tst_record", __FILE__, db).toLower(); + SETUP_RECORD_TABLE; + CHECK_RECORD; + q.clear(); + + // Recreate the tables, in a different order + const QStringList tables = { qtest, tst_record, qTableName("qtest_null", __FILE__, db) }; + tst_Databases::safeDropTables(db, tables); + SETUP_RECORD_TABLE; + createTestTables(db); + populateTestTables(db); + CHECK_RECORD; } void tst_QSqlQuery::isValid() diff --git a/tests/benchmarks/sql/kernel/kernel.pro b/tests/benchmarks/sql/kernel/kernel.pro index f907feeeac..63887daf5f 100644 --- a/tests/benchmarks/sql/kernel/kernel.pro +++ b/tests/benchmarks/sql/kernel/kernel.pro @@ -1,3 +1,4 @@ TEMPLATE = subdirs SUBDIRS = \ qsqlquery \ + qsqlrecord diff --git a/tests/benchmarks/sql/kernel/qsqlrecord/qsqlrecord.pro b/tests/benchmarks/sql/kernel/qsqlrecord/qsqlrecord.pro new file mode 100644 index 0000000000..840a11bfbe --- /dev/null +++ b/tests/benchmarks/sql/kernel/qsqlrecord/qsqlrecord.pro @@ -0,0 +1,5 @@ +TARGET = tst_bench_qsqlrecord + +SOURCES += tst_qsqlrecord.cpp + +QT = core sql testlib core-private sql-private diff --git a/tests/benchmarks/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp b/tests/benchmarks/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp new file mode 100644 index 0000000000..465dabca0e --- /dev/null +++ b/tests/benchmarks/sql/kernel/qsqlrecord/tst_qsqlrecord.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** + ** + ** Copyright (C) 2018 The Qt Company Ltd. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the test suite of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and The Qt Company. For licensing terms + ** and conditions see https://www.qt.io/terms-conditions. For further + ** information use the contact form at https://www.qt.io/contact-us. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3 as published by the Free Software + ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT + ** included in the packaging of this file. Please review the following + ** information to ensure the GNU General Public License requirements will + ** be met: https://www.gnu.org/licenses/gpl-3.0.html. + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include +#include + +#include "../../../../auto/sql/kernel/qsqldatabase/tst_databases.h" + +const QString qtest(qTableName("qtest", __FILE__, QSqlDatabase())); + +class tst_QSqlRecord : public QObject +{ + Q_OBJECT + +public: + tst_QSqlRecord(); + virtual ~tst_QSqlRecord(); + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void benchmarkRecord_data() { generic_data(); } + void benchmarkRecord(); + +private: + void generic_data(const QString &engine = QString()); + void dropTestTables(QSqlDatabase db); + void createTestTables(QSqlDatabase db); + void populateTestTables(QSqlDatabase db); + + tst_Databases dbs; +}; + +QTEST_MAIN(tst_QSqlRecord) + +tst_QSqlRecord::tst_QSqlRecord() +{ +} + +tst_QSqlRecord::~tst_QSqlRecord() +{ +} + +void tst_QSqlRecord::initTestCase() +{ + dbs.open(); + for (const auto &dbName : qAsConst(dbs.dbNames)) { + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + dropTestTables(db); // In case of leftovers + createTestTables(db); + populateTestTables(db); + } +} + +void tst_QSqlRecord::cleanupTestCase() +{ + for (const auto &dbName : qAsConst(dbs.dbNames)) { + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + dropTestTables(db); + } + dbs.close(); +} + +void tst_QSqlRecord::init() +{ +} + +void tst_QSqlRecord::cleanup() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); + + if (QTest::currentTestFailed() && (dbType == QSqlDriver::Oracle || + db.driverName().startsWith("QODBC"))) { + // Since Oracle ODBC has a problem when encountering an error, we init again + db.close(); + db.open(); + } +} + +void tst_QSqlRecord::generic_data(const QString &engine) +{ + if (dbs.fillTestTable(engine) == 0) { + if (engine.isEmpty()) + QSKIP("No database drivers are available in this Qt configuration"); + else + QSKIP(QString("No database drivers of type %1 are available in this Qt configuration").arg(engine).toLocal8Bit()); + } +} + +void tst_QSqlRecord::dropTestTables(QSqlDatabase db) +{ + QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); + QStringList tablenames; + // drop all the tables in case a testcase failed + tablenames << qtest + << qTableName("record", __FILE__, db); + tst_Databases::safeDropTables(db, tablenames); + + if (dbType == QSqlDriver::Oracle) { + QSqlQuery q(db); + q.exec("DROP PACKAGE " + qTableName("pkg", __FILE__, db)); + } +} + +void tst_QSqlRecord::createTestTables(QSqlDatabase db) +{ + QSqlQuery q(db); + switch (tst_Databases::getDatabaseType(db)) { + case QSqlDriver::PostgreSQL: + QVERIFY_SQL(q, exec("set client_min_messages='warning'")); + QVERIFY_SQL(q, exec("create table " + qtest + " (id serial NOT NULL, t_varchar varchar(20), " + "t_char char(20), primary key(id)) WITH OIDS")); + break; + case QSqlDriver::MySqlServer: + QVERIFY_SQL(q, exec("set table_type=innodb")); + Q_FALLTHROUGH(); + default: + QVERIFY_SQL(q, exec("create table " + qtest + " (id int " + tst_Databases::autoFieldName(db) + + " NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id))")); + break; + } +} + +void tst_QSqlRecord::populateTestTables(QSqlDatabase db) +{ + QSqlQuery q(db); + QVERIFY_SQL(q, exec("delete from " + qtest)); + QVERIFY_SQL(q, exec("insert into " + qtest + " values (1, 'VarChar1', 'Char1')")); + QVERIFY_SQL(q, exec("insert into " + qtest + " values (2, 'VarChar2', 'Char2')")); + QVERIFY_SQL(q, exec("insert into " + qtest + " values (3, 'VarChar3', 'Char3')")); + QVERIFY_SQL(q, exec("insert into " + qtest + " values (4, 'VarChar4', 'Char4')")); + QVERIFY_SQL(q, exec("insert into " + qtest + " values (5, 'VarChar5', 'Char5')")); +} + +void tst_QSqlRecord::benchmarkRecord() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + const auto tableName = qTableName("record", __FILE__, db); + { + QSqlQuery qry(db); + QVERIFY_SQL(qry, exec("create table " + tableName + " (id int NOT NULL, t_varchar varchar(20), " + "t_char char(20), primary key(id))")); + for (int i = 0; i < 1000; i++) + QVERIFY_SQL(qry, exec(QString("INSERT INTO " + tableName + + " VALUES (%1, 'VarChar%1', 'Char%1')").arg(i))); + QVERIFY_SQL(qry, exec(QString("SELECT * from ") + tableName)); + QBENCHMARK { + while (qry.next()) + qry.record(); + } + } + tst_Databases::safeDropTables(db, QStringList() << tableName); +} + +#include "tst_qsqlrecord.moc" From feba2a68b18d4d47c0c3e2644ab996e76c97da56 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Fri, 16 Feb 2018 11:27:01 +0100 Subject: [PATCH 05/20] Fix incorrect documentation for -platform, QT_QPA_PLATFORM and friends This makes the documentation match the implementation. -platform overrides QT_QPA_PLATFORM, not the other way around. Similarly for the other arguments. Change-Id: Iffaf8bb1134bc57e5b682f37b9cc1a713872ede1 Reviewed-by: Martin Smith Reviewed-by: Gatis Paeglis Reviewed-by: Leena Miettinen --- src/gui/kernel/qguiapplication.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index f7da94d111..b4bc4b85d0 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -525,21 +525,21 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME \li \c{-platform} \e {platformName[:options]}, specifies the \l{Qt Platform Abstraction} (QPA) plugin. - Overridden by the \c QT_QPA_PLATFORM environment variable. + Overrides the \c QT_QPA_PLATFORM environment variable. \li \c{-platformpluginpath} \e path, specifies the path to platform plugins. - Overridden by the \c QT_QPA_PLATFORM_PLUGIN_PATH environment - variable. + Overrides the \c QT_QPA_PLATFORM_PLUGIN_PATH environment variable. \li \c{-platformtheme} \e platformTheme, specifies the platform theme. - Overridden by the \c QT_QPA_PLATFORMTHEME environment variable. + Overrides the \c QT_QPA_PLATFORMTHEME environment variable. \li \c{-plugin} \e plugin, specifies additional plugins to load. The argument may appear multiple times. - Overridden by the \c QT_QPA_GENERIC_PLUGINS environment variable. + Concatenated with the plugins in the \c QT_QPA_GENERIC_PLUGINS environment + variable. \li \c{-qmljsdebugger=}, activates the QML/JS debugger with a specified port. The value must be of format \c{port:1234}\e{[,block]}, where From acbed6802e5a1fe3f80425124696246dd6836c12 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Fri, 16 Feb 2018 12:40:07 +0100 Subject: [PATCH 06/20] Add Wayland in the documentation for QGuiApplication::platformName Change-Id: Ie19dbeeba6cd9664ad546dd2b2ae0bf6cbd199a0 Reviewed-by: Gatis Paeglis --- src/gui/kernel/qguiapplication.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index b4bc4b85d0..183ecc3117 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1125,6 +1125,8 @@ QWindow *QGuiApplication::topLevelAt(const QPoint &pos) \li \c openwfd \li \c qnx \li \c windows + \li \c wayland is a platform plugin for modern Linux desktops and some + embedded systems. \li \c xcb is the X11 plugin used on regular desktop Linux platforms. \endlist From fa0906bc5664913f232721d611e6e7906892d766 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 19 Feb 2018 09:35:51 +0100 Subject: [PATCH 07/20] xcb: Fix developer build Add Q_UNUSED, fixing: qxcbbackingstore.cpp:344:45: error: unused parameter 'segmentSize' [-Werror=unused-parameter] on Kubuntu 17.10. Amends 24adaa9a742e6f95ff897d0eb9a2bce0527dd042. Task-number: QTBUG-46017 Change-Id: I64f21d8f1d1ac21340cfbba66b97768140ce23a8 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index eae0ee7613..6ae52d9fd3 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -343,6 +343,9 @@ void QXcbShmImage::createShmSegment(size_t segmentSize) void QXcbShmImage::destroyShmSegment(size_t segmentSize) { +#ifndef XCB_USE_SHM_FD + Q_UNUSED(segmentSize) +#endif auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) From 195b2321d22bbf94ed4f40441687a97dbd975916 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 30 Nov 2017 14:13:46 +0100 Subject: [PATCH 08/20] Doc: complete Border Layout Example Task-number: QTBUG-60635 Change-Id: Icc605e5bad96aaad0233d4b05ab1ed46972bd725 Reviewed-by: Frederik Gladhorn --- doc/src/images/borderlayout-example.png | Bin 6163 -> 9126 bytes examples/widgets/doc/src/borderlayout.qdoc | 28 +++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/doc/src/images/borderlayout-example.png b/doc/src/images/borderlayout-example.png index e856e065720e4eca1e625675fdb1d53c042d7316..27b939bc2e2acea1b510081b5cb8d644d1b9d11a 100644 GIT binary patch literal 9126 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 NK~`0!?Cpn7{{zW(yXpV{ literal 6163 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 MiW>JzoGXMYp diff --git a/examples/widgets/doc/src/borderlayout.qdoc b/examples/widgets/doc/src/borderlayout.qdoc index c8f2ae4196..6572bfe578 100644 --- a/examples/widgets/doc/src/borderlayout.qdoc +++ b/examples/widgets/doc/src/borderlayout.qdoc @@ -36,6 +36,34 @@ \image borderlayout-example.png + The constructor of the Window class creates a QTextBrowser object, + to which a BorderLayout named \c layout is added. The declaration + of the BorderLayout class is quoted at the end of this document. + + \quotefromfile layouts/borderlayout/window.cpp + \skipto Window::Window() + \printuntil BorderLayout + + Several labeled widgets are added to \c layout with the orientation + \c {Center}, \c {North}, \c {West}, \c {East 1}, \c {East 2}, and + \c {South}. + + \skipto layout->addWidget + \printuntil setWindowTitle + + createLabel() in class \c Window sets the text of the labeled widgets + and the style. + + \skipto QLabel *Window::createLabel + \printuntil /^\}/ + + Class BorderLayout contains all the utilitarian functions for formatting + the widgets it contains. + + \quotefromfile layouts/borderlayout/borderlayout.h + \skipto class + \printuntil /^\}/ + For more information, visit the \l{Layout Management} page. \include examples-run.qdocinc From 8e098f87bbab8ac0c5189f432bbfe0aa7dfe3a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Sun, 18 Feb 2018 12:31:22 +0100 Subject: [PATCH 09/20] macOS: Remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7e016db57cbf347529b6aa003d84585eeab0767d Reviewed-by: Jake Petroules Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index ca580e7d17..4aee3527c8 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1136,8 +1136,6 @@ void QCocoaWindow::handleGeometryChange() void QCocoaWindow::handleExposeEvent(const QRegion ®ion) { - const QRect previouslyExposedRect = m_exposedRect; - // Ideally we'd implement isExposed() in terms of these properties, // plus the occlusionState of the NSWindow, and let the expose event // pull the exposed state out when needed. However, when the window From 29ae5cbaf840dc7693a3755097489998aecdf061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Sat, 17 Feb 2018 21:04:36 +0100 Subject: [PATCH 10/20] macOS: Don't assume m_view is QNSView when calling requestUpdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I98833c5ecc5816a0926045e10ef0442a39be6b2e Reviewed-by: Jake Petroules Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 4aee3527c8..511c471519 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1329,7 +1329,7 @@ void QCocoaWindow::recreateWindowIfNeeded() void QCocoaWindow::requestUpdate() { qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::requestUpdate" << window(); - [m_view requestUpdate]; + [qnsview_cast(m_view) requestUpdate]; } void QCocoaWindow::requestActivateWindow() From 95eeaec36f769d53b5cdfd72a4fb05e924a030da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 13 Feb 2018 17:09:48 +0100 Subject: [PATCH 11/20] macOS: Remove qDebug silencer in qthread_unix.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was added by Sam back in 2007, and we've removed other instances of the same pattern since then. It doesn't make any sense today. Change-Id: I0f3cb299e312648fd9dc96c639dab4c77fcb48c7 Reviewed-by: Thiago Macieira Reviewed-by: Timur Pocheptsov Reviewed-by: Tor Arne Vestbø --- src/corelib/thread/qthread_unix.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 6248842d78..9ad32b162d 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -83,19 +83,6 @@ #include #endif -#if defined(Q_OS_MAC) -# ifdef qDebug -# define old_qDebug qDebug -# undef qDebug -# endif - -# ifdef old_qDebug -# undef qDebug -# define qDebug QT_NO_QDEBUG_MACRO -# undef old_qDebug -# endif -#endif - #if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) #include #endif From 0d4ce766ae7dd2eb36dc2d64b97808763457e915 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 13 Sep 2017 16:07:36 +0200 Subject: [PATCH 12/20] Doc: review language and spelling in Editable Tree Model Example Task-number: QTBUG-60635 Change-Id: If82e3e36e5f6d1044028dc4454f2db13f84754d8 Reviewed-by: Edward Welbourne --- .../widgets/doc/src/editabletreemodel.qdoc | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/widgets/doc/src/editabletreemodel.qdoc b/examples/widgets/doc/src/editabletreemodel.qdoc index 87249a578e..68e10e3e78 100644 --- a/examples/widgets/doc/src/editabletreemodel.qdoc +++ b/examples/widgets/doc/src/editabletreemodel.qdoc @@ -153,7 +153,7 @@ We can retrieve pointers stored in this way by calling the \l{QModelIndex::}{internalPointer()} function on the relevant model index - we create our own \l{TreeModel::getItem}{getItem()} function to - do this work for us, and call it from our \l{TreeModel::data}{data()} + do the work for us, and call it from our \l{TreeModel::data}{data()} and \l{TreeModel::parent}{parent()} implementations. Storing pointers to items is convenient when we control how they are @@ -169,7 +169,7 @@ \row \li \b{Storing information in the underlying data structure} Several pieces of data are stored as QVariant objects in the \c itemData - member of each \c TreeItem instance + member of each \c TreeItem instance. The diagram shows how pieces of information, represented by the labels \b{a}, \b{b} and \b{c} in the @@ -227,8 +227,8 @@ \section1 TreeItem Class Definition The \c TreeItem class provides simple items that contain several - pieces of data, and which can provide information about their parent - and child items: + pieces of data, including information about their parent and + child items: \snippet itemviews/editabletreemodel/treeitem.h 0 @@ -302,7 +302,7 @@ \snippet itemviews/editabletreemodel/treeitem.cpp 11 To make implementation of the model easier, we return true to indicate - whether the data was set successfully, or false if an invalid column + that the data was set successfully. Editable models often need to be resizable, enabling rows and columns to be inserted and removed. The insertion of rows beneath a given model index @@ -356,29 +356,29 @@ We call the internal \l{TreeModel::setupModelData}{setupModelData()} function to convert the textual data supplied to a data structure we can use with the model. Other models may be initialized with a ready-made - data structure, or use an API to a library that maintains its own data. + data structure, or use an API from a library that maintains its own data. - The destructor only has to delete the root item; all child items will - be recursively deleted by the \c TreeItem destructor. + The destructor only has to delete the root item, which will cause all child + items to be recursively deleted. \snippet itemviews/editabletreemodel/treemodel.cpp 1 \target TreeModel::getItem Since the model's interface to the other model/view components is based - on model indexes, and the internal data structure is item-based, many of - the functions implemented by the model need to be able to convert any - given model index to its corresponding item. For convenience and + on model indexes, and since the internal data structure is item-based, + many of the functions implemented by the model need to be able to convert + any given model index to its corresponding item. For convenience and consistency, we have defined a \c getItem() function to perform this repetitive task: \snippet itemviews/editabletreemodel/treemodel.cpp 4 - This function assumes that each model index it is passed corresponds to - a valid item in memory. If the index is invalid, or its internal pointer - does not refer to a valid item, the root item is returned instead. + Each model index passed to this function should correspond to a valid + item in memory. If the index is invalid, or its internal pointer does + not refer to a valid item, the root item is returned instead. The model's \c rowCount() implementation is simple: it first uses the - \c getItem() function to obtain the relevant item, then returns the + \c getItem() function to obtain the relevant item; then it returns the number of children it contains: \snippet itemviews/editabletreemodel/treemodel.cpp 8 From 13e51ea48758337397164a548d4c82d079067ae3 Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Mon, 19 Feb 2018 14:53:04 +0200 Subject: [PATCH 13/20] QLineEdit: Clear input context commit string after test functions Since the PlatformInputContext is shared between test cases, the set commit string from inputMethod() was otherwise saved and could pollute other tests. For example on Windows PlatformInputContext::commit() was called when the QLineEdit was first clicked onto in tst_QLineEdit::testQuickSelectionWithMouse() and inserted "text" in the middle of the text, rather than starting selection as intended. This led to tst_QLineEdit::testQuickSelectionWithMouse() failing on Windows at first in CI, but then always passing the repeats when it was tested alone. Task-number: QTBUG-66499 Task-number: QTBUG-66216 Change-Id: Id6bdd263d57fd6d08fb48f013542b55b132907ea Reviewed-by: Friedemann Kleint Reviewed-by: Frederik Gladhorn Reviewed-by: Sami Nurmenniemi --- tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 1513025f16..0be8d319c2 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -411,6 +411,7 @@ void tst_QLineEdit::cleanup() { delete m_testWidget; m_testWidget = 0; + m_platformInputContext.m_commitString.clear(); } void tst_QLineEdit::experimental() From 093d85393fbacf68028e3b5fd39329878757d603 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 14 Feb 2018 15:51:38 +0100 Subject: [PATCH 14/20] Support multiple entries in the Qt platform plugin string [ChangeLog][QtGui] QT_QPA_PLATFORM and the -platform argument now support a list of platform plugins in prioritized order. Platforms are separated by semicolons. The plugins are tried in the order they are specified as long as all preceding platforms fail gracefully by returning nullptr in the implementation of QPlatformIntegrationPlugin::create() This is useful on Linux distributions where the Wayland plugin may be installed, but is not supported by the current session. i.e. if X11 is running or if the compositor does not provide a compatible shell extension. Example usage: QT_QPA_PLATFORM="wayland;xcb" ./application or ./application -platform "wayland;xcb" Task-number: QTBUG-59762 Change-Id: Ia3f034ec522ed6729d71acf971d172da9e68a5a0 Reviewed-by: Gatis Paeglis --- config_help.txt | 3 +- src/gui/kernel/qguiapplication.cpp | 65 ++++++++++++++++++------------ 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/config_help.txt b/config_help.txt index 4be797cc6b..f61601ec7a 100644 --- a/config_help.txt +++ b/config_help.txt @@ -274,7 +274,8 @@ Gui, printing, widget options: (Windows only) -combined-angle-lib .. Merge LibEGL and LibGLESv2 into LibANGLE (Windows only) - -qpa .......... Select default QPA backend (e.g., xcb, cocoa, windows) + -qpa .......... Select default QPA backend(s) (e.g., xcb, cocoa, windows) + A prioritized list separated by semi-colons. -xcb-xlib............. Enable Xcb-Xlib support [auto] Platform backends: diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 183ecc3117..fdc27b760c 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1140,33 +1140,47 @@ QString QGuiApplication::platformName() *QGuiApplicationPrivate::platform_name : QString(); } -static void init_platform(const QString &pluginArgument, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv) +Q_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin"); + +static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv) { - // Split into platform name and arguments - QStringList arguments = pluginArgument.split(QLatin1Char(':')); - const QString name = arguments.takeFirst().toLower(); - QString argumentsKey = name; - argumentsKey[0] = argumentsKey.at(0).toUpper(); - arguments.append(QLibraryInfo::platformPluginArguments(argumentsKey)); + QStringList plugins = pluginNamesWithArguments.split(QLatin1Char(';')); + QStringList platformArguments; + QStringList availablePlugins = QPlatformIntegrationFactory::keys(platformPluginPath); + for (auto pluginArgument : plugins) { + // Split into platform name and arguments + QStringList arguments = pluginArgument.split(QLatin1Char(':')); + const QString name = arguments.takeFirst().toLower(); + QString argumentsKey = name; + argumentsKey[0] = argumentsKey.at(0).toUpper(); + arguments.append(QLibraryInfo::platformPluginArguments(argumentsKey)); - // Create the platform integration. - QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath); - if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) { - QStringList keys = QPlatformIntegrationFactory::keys(platformPluginPath); - - QString fatalMessage; - if (keys.contains(name)) { - fatalMessage = QStringLiteral("This application failed to start because it could not load the Qt platform plugin \"%2\"\nin \"%3\", even though it was found. ").arg(name, QDir::toNativeSeparators(platformPluginPath)); - fatalMessage += QStringLiteral("This is usually due to missing dependencies, which you can verify by setting the env variable QT_DEBUG_PLUGINS to 1.\n\n"); + // Create the platform integration. + QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath); + if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) { + if (availablePlugins.contains(name)) { + qCInfo(lcQpaPluginLoading).nospace().noquote() + << "Could not load the Qt platform plugin \"" << name << "\" in \"" + << QDir::toNativeSeparators(platformPluginPath) << "\" even though it was found."; + } else { + qCWarning(lcQpaPluginLoading).nospace().noquote() + << "Could not find the Qt platform plugin \"" << name << "\" in \"" + << QDir::toNativeSeparators(platformPluginPath) << "\""; + } } else { - fatalMessage = QStringLiteral("This application failed to start because it could not find the Qt platform plugin \"%2\"\nin \"%3\".\n\n").arg(name, QDir::toNativeSeparators(platformPluginPath)); + QGuiApplicationPrivate::platform_name = new QString(name); + platformArguments = arguments; + break; } + } + + if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) { + QString fatalMessage = QStringLiteral("This application failed to start because no Qt platform plugin could be initialized. " + "Reinstalling the application may fix this problem.\n"); + + if (!availablePlugins.isEmpty()) + fatalMessage += QStringLiteral("\nAvailable platform plugins are: %1.\n").arg(availablePlugins.join(QLatin1String(", "))); - if (!keys.isEmpty()) { - fatalMessage += QStringLiteral("Available platform plugins are: %1.\n\n").arg( - keys.join(QLatin1String(", "))); - } - fatalMessage += QStringLiteral("Reinstalling the application may fix this problem."); #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) // Windows: Display message box unless it is a console application // or debug build showing an assert box. @@ -1174,11 +1188,10 @@ static void init_platform(const QString &pluginArgument, const QString &platform MessageBox(0, (LPCTSTR)fatalMessage.utf16(), (LPCTSTR)(QCoreApplication::applicationName().utf16()), MB_OK | MB_ICONERROR); #endif // Q_OS_WIN && !Q_OS_WINRT qFatal("%s", qPrintable(fatalMessage)); + return; } - QGuiApplicationPrivate::platform_name = new QString(name); - // Many platforms have created QScreens at this point. Finish initializing // QHighDpiScaling to be prepared for early calls to qt_defaultDpi(). if (QGuiApplication::primaryScreen()) { @@ -1225,9 +1238,9 @@ static void init_platform(const QString &pluginArgument, const QString &platform #ifndef QT_NO_PROPERTIES // Set arguments as dynamic properties on the native interface as // boolean 'foo' or strings: 'foo=bar' - if (!arguments.isEmpty()) { + if (!platformArguments.isEmpty()) { if (QObject *nativeInterface = QGuiApplicationPrivate::platform_integration->nativeInterface()) { - for (const QString &argument : qAsConst(arguments)) { + for (const QString &argument : qAsConst(platformArguments)) { const int equalsPos = argument.indexOf(QLatin1Char('=')); const QByteArray name = equalsPos != -1 ? argument.left(equalsPos).toUtf8() : argument.toUtf8(); From ddf6f57f212da5555d799d9f3ac9faff093891d0 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Mon, 19 Feb 2018 12:34:04 +0100 Subject: [PATCH 15/20] xcb: Fix -geometry argument for platformName with arguments or fallbacks -geometry, -title and -icon for xcb did not work if the platform string had arguments or there were fallback platforms. Only accept the arguments if xcb is the default platform. I.e. ignore the arguments if xcb is a fallback. This now works: ./application -platform "xcb:someArg=value" -title specialXcbTitle ./application -platform "xcb;wayland" -title specialXcbTitle ./application -platform "xcb:someArg=value;wayland" -title specialXcbTitle But this does not: ./application -platform "wayland;xcb:someArg=value" -title specialXcbTitle Change-Id: I4ee20b1ed722bc98417a5e75db7d8c98ffcdfcfe Reviewed-by: Gatis Paeglis --- src/gui/kernel/qguiapplication.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index fdc27b760c..12390928f0 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1304,7 +1304,7 @@ void QGuiApplicationPrivate::createPlatformIntegration() argv[j++] = argv[i]; continue; } - const bool isXcb = platformName == "xcb"; + const bool xcbIsDefault = platformName.startsWith("xcb"); const char *arg = argv[i]; if (arg[1] == '-') // startsWith("--") ++arg; @@ -1317,13 +1317,13 @@ void QGuiApplicationPrivate::createPlatformIntegration() } else if (strcmp(arg, "-platformtheme") == 0) { if (++i < argc) platformThemeName = QString::fromLocal8Bit(argv[i]); - } else if (strcmp(arg, "-qwindowgeometry") == 0 || (isXcb && strcmp(arg, "-geometry") == 0)) { + } else if (strcmp(arg, "-qwindowgeometry") == 0 || (xcbIsDefault && strcmp(arg, "-geometry") == 0)) { if (++i < argc) windowGeometrySpecification = QWindowGeometrySpecification::fromArgument(argv[i]); - } else if (strcmp(arg, "-qwindowtitle") == 0 || (isXcb && strcmp(arg, "-title") == 0)) { + } else if (strcmp(arg, "-qwindowtitle") == 0 || (xcbIsDefault && strcmp(arg, "-title") == 0)) { if (++i < argc) firstWindowTitle = QString::fromLocal8Bit(argv[i]); - } else if (strcmp(arg, "-qwindowicon") == 0 || (isXcb && strcmp(arg, "-icon") == 0)) { + } else if (strcmp(arg, "-qwindowicon") == 0 || (xcbIsDefault && strcmp(arg, "-icon") == 0)) { if (++i < argc) { icon = QString::fromLocal8Bit(argv[i]); } From 76617fdb56a5498c01ad75bc461687ded7e8f8d7 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 19 Feb 2018 19:39:42 +0100 Subject: [PATCH 16/20] qmake: fix immediate RESOURCES with absolute RCC_DIR $$RCC_DIR can be absolute, so simple concatenation with $$OUT_PWD is bound to fail. Change-Id: Ibd80c49656c0e03b8a86ebca851af106cced08fb Reviewed-by: Joerg Bornemann --- mkspecs/features/resources.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/resources.prf b/mkspecs/features/resources.prf index de769b4b86..3f5979202c 100644 --- a/mkspecs/features/resources.prf +++ b/mkspecs/features/resources.prf @@ -64,7 +64,7 @@ for(resource, RESOURCES) { "" \ "" - !write_file($$OUT_PWD/$$resource_file, resource_file_content): \ + !write_file($$absolute_path($$resource_file, $$OUT_PWD), resource_file_content): \ error() } From ed3ed0b9db97a8fab0c03add23228b6b0a96f171 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 12 Feb 2018 16:26:38 +0100 Subject: [PATCH 17/20] Fix touch point positions of non-transformable QGraphicsItems TouchEvent::TouchPoint::pos was not updated in QGraphicsScenePrivate::updateTouchPointsForItem(). To prevent the transformation being calculated repeatedly for each touch point member, extract a function genericMapFromSceneTransform() from genericMapFromScene() returning the transformation and use that whereever multiple points are transformed. Add a test, extracting helper functionality from tst_QGraphicsItem::touchEventPropagation(). In addition, fold tst_QGraphicsScene::checkTouchPointsEllipseDiameters() from c48f4bde0044bd5b23af231f3639d0779ecbdb03 into this test, so that it is testing all transformations. Task-number: QTBUG-66192 Change-Id: If71886d2c14c4e216f7781ea2f22f1adc444e6cf Reviewed-by: Andy Shaw Reviewed-by: Richard Moe Gustavsen --- src/widgets/graphicsview/qgraphicsitem.cpp | 25 +- src/widgets/graphicsview/qgraphicsitem_p.h | 1 + src/widgets/graphicsview/qgraphicsscene.cpp | 26 +- .../qgraphicsitem/tst_qgraphicsitem.cpp | 227 +++++++++++++++--- .../qgraphicsscene/tst_qgraphicsscene.cpp | 76 ------ 5 files changed, 226 insertions(+), 129 deletions(-) diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 0bc3af2f77..cef1d1b6da 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -1134,19 +1134,26 @@ void QGraphicsItemPrivate::remapItemPos(QEvent *event, QGraphicsItem *item) is untransformable, this function will correctly map \a pos from the scene using the view's transformation. */ -QPointF QGraphicsItemPrivate::genericMapFromScene(const QPointF &pos, - const QWidget *viewport) const + +QTransform QGraphicsItemPrivate::genericMapFromSceneTransform(const QWidget *viewport) const { Q_Q(const QGraphicsItem); if (!itemIsUntransformable()) - return q->mapFromScene(pos); - QGraphicsView *view = 0; - if (viewport) - view = qobject_cast(viewport->parentWidget()); - if (!view) - return q->mapFromScene(pos); + return sceneTransform.inverted(); + const QGraphicsView *view = viewport + ? qobject_cast(viewport->parentWidget()) + : nullptr; + if (view == nullptr) + return sceneTransform.inverted(); // ### More ping pong than needed. - return q->deviceTransform(view->viewportTransform()).inverted().map(view->mapFromScene(pos)); + const QTransform viewportTransform = view->viewportTransform(); + return viewportTransform * q->deviceTransform(viewportTransform).inverted(); +} + +QPointF QGraphicsItemPrivate::genericMapFromScene(const QPointF &pos, + const QWidget *viewport) const +{ + return genericMapFromSceneTransform(viewport).map(pos); } /*! diff --git a/src/widgets/graphicsview/qgraphicsitem_p.h b/src/widgets/graphicsview/qgraphicsitem_p.h index bae38473f9..9fc6c0794a 100644 --- a/src/widgets/graphicsview/qgraphicsitem_p.h +++ b/src/widgets/graphicsview/qgraphicsitem_p.h @@ -190,6 +190,7 @@ public: void updateAncestorFlags(); void setIsMemberOfGroup(bool enabled); void remapItemPos(QEvent *event, QGraphicsItem *item); + QTransform genericMapFromSceneTransform(const QWidget *viewport = nullptr) const; QPointF genericMapFromScene(const QPointF &pos, const QWidget *viewport) const; inline bool itemIsUntransformable() const { diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index 25b77aa02f..37c631483a 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -1286,10 +1286,11 @@ void QGraphicsScenePrivate::sendHoverEvent(QEvent::Type type, QGraphicsItem *ite { QGraphicsSceneHoverEvent event(type); event.setWidget(hoverEvent->widget()); - event.setPos(item->d_ptr->genericMapFromScene(hoverEvent->scenePos(), hoverEvent->widget())); + const QTransform mapFromScene = item->d_ptr->genericMapFromSceneTransform(hoverEvent->widget()); + event.setPos(mapFromScene.map(hoverEvent->scenePos())); event.setScenePos(hoverEvent->scenePos()); event.setScreenPos(hoverEvent->screenPos()); - event.setLastPos(item->d_ptr->genericMapFromScene(hoverEvent->lastScenePos(), hoverEvent->widget())); + event.setLastPos(mapFromScene.map(hoverEvent->lastScenePos())); event.setLastScenePos(hoverEvent->lastScenePos()); event.setLastScreenPos(hoverEvent->lastScreenPos()); event.setModifiers(hoverEvent->modifiers()); @@ -1312,14 +1313,16 @@ void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent) if (item->isBlockedByModalPanel()) return; + const QTransform mapFromScene = item->d_ptr->genericMapFromSceneTransform(mouseEvent->widget()); + const QPointF itemPos = mapFromScene.map(mouseEvent->scenePos()); for (int i = 0x1; i <= 0x10; i <<= 1) { Qt::MouseButton button = Qt::MouseButton(i); - mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget()))); + mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, itemPos)); mouseEvent->setButtonDownScenePos(button, mouseGrabberButtonDownScenePos.value(button, mouseEvent->scenePos())); mouseEvent->setButtonDownScreenPos(button, mouseGrabberButtonDownScreenPos.value(button, mouseEvent->screenPos())); } - mouseEvent->setPos(item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget())); - mouseEvent->setLastPos(item->d_ptr->genericMapFromScene(mouseEvent->lastScenePos(), mouseEvent->widget())); + mouseEvent->setPos(itemPos); + mouseEvent->setLastPos(mapFromScene.map(mouseEvent->lastScenePos())); sendEvent(item, mouseEvent); } @@ -5858,10 +5861,17 @@ void QGraphicsScenePrivate::removeView(QGraphicsView *view) void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent) { + const QTransform mapFromScene = + item->d_ptr->genericMapFromSceneTransform(static_cast(touchEvent->target())); + for (auto &touchPoint : touchEvent->_touchPoints) { - touchPoint.setRect(item->mapFromScene(touchPoint.sceneRect()).boundingRect()); - touchPoint.setStartPos(item->d_ptr->genericMapFromScene(touchPoint.startScenePos(), static_cast(touchEvent->target()))); - touchPoint.setLastPos(item->d_ptr->genericMapFromScene(touchPoint.lastScenePos(), static_cast(touchEvent->target()))); + // Deprecated TouchPoint::setRect clobbers ellipseDiameters, restore + const QSizeF ellipseDiameters = touchPoint.ellipseDiameters(); + touchPoint.setRect(mapFromScene.map(touchPoint.sceneRect()).boundingRect()); + touchPoint.setEllipseDiameters(ellipseDiameters); + touchPoint.setPos(mapFromScene.map(touchPoint.scenePos())); + touchPoint.setStartPos(mapFromScene.map(touchPoint.startScenePos())); + touchPoint.setLastPos(mapFromScene.map(touchPoint.lastScenePos())); } } diff --git a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp index 26831002ce..4f4a11a79c 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -54,10 +55,13 @@ #include #include #include +#include #include #include Q_DECLARE_METATYPE(QPainterPath) +Q_DECLARE_METATYPE(QSizeF) +Q_DECLARE_METATYPE(QTransform) #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) #include @@ -435,6 +439,8 @@ private slots: void focusHandling(); void touchEventPropagation_data(); void touchEventPropagation(); + void touchEventTransformation_data(); + void touchEventTransformation(); void deviceCoordinateCache_simpleRotations(); void resolvePaletteForItemChildren(); @@ -465,6 +471,7 @@ private slots: private: QList paintedItems; + QTouchDevice *m_touchDevice = nullptr; }; void tst_QGraphicsItem::construction() @@ -10945,6 +10952,95 @@ void tst_QGraphicsItem::focusHandling() QCOMPARE(scene.focusItem(), focusableUnder); } +class TouchEventTestee : public QGraphicsRectItem +{ +public: + TouchEventTestee(const QSizeF &size = QSizeF(100, 100)) : + QGraphicsRectItem(QRectF(QPointF(), size)) + { + setAcceptTouchEvents(true); + setFlag(QGraphicsItem::ItemIsFocusable, false); + } + + QList touchBeginPoints() const { return m_touchBeginPoints; } + int touchBeginEventCount() const { return m_touchBeginPoints.size(); } + + QList touchUpdatePoints() const { return m_touchUpdatePoints; } + int touchUpdateEventCount() const { return m_touchUpdatePoints.size(); } + +protected: + bool sceneEvent(QEvent *ev) override + { + switch (ev->type()) { + case QEvent::TouchBegin: + m_touchBeginPoints.append(static_cast(ev)->touchPoints().constFirst()); + ev->accept(); + return true; + case QEvent::TouchUpdate: + m_touchUpdatePoints.append(static_cast(ev)->touchPoints().constFirst()); + ev->accept(); + return true; + default: + break; + } + + return QGraphicsRectItem::sceneEvent(ev); + } + +private: + QList m_touchBeginPoints; + QList m_touchUpdatePoints; +}; + +static QList + createTouchPoints(const QGraphicsView &view, + const QPointF &scenePos, + const QSizeF &ellipseDiameters, + Qt::TouchPointState state = Qt::TouchPointPressed) +{ + QTouchEvent::TouchPoint tp(0); + tp.setState(state); + tp.setScenePos(scenePos); + tp.setStartScenePos(scenePos); + tp.setLastScenePos(scenePos); + const QPointF screenPos = view.viewport()->mapToGlobal(view.mapFromScene(scenePos)); + tp.setScreenPos(screenPos); + tp.setStartScreenPos(screenPos); + tp.setLastScreenPos(screenPos); + tp.setEllipseDiameters(ellipseDiameters); + const QSizeF screenSize = QApplication::desktop()->screenGeometry(&view).size(); + tp.setNormalizedPos(QPointF(screenPos.x() / screenSize.width(), screenPos.y() / screenSize.height())); + return QList() << tp; +} + +static bool comparePointF(const QPointF &p1, const QPointF &p2) +{ + return qFuzzyCompare(p1.x(), p2.x()) && qFuzzyCompare(p1.y(), p2.y()); +} + +static bool compareSizeF(const QSizeF &s1, const QSizeF &s2) +{ + return qFuzzyCompare(s1.width(), s2.width()) && qFuzzyCompare(s1.height(), s2.height()); +} + +static QByteArray msgPointFComparisonFailed(const QPointF &p1, const QPointF &p2) +{ + return QByteArray::number(p1.x()) + ", " + QByteArray::number(p1.y()) + + " != " + QByteArray::number(p2.x()) + ", " + QByteArray::number(p2.y()); +} + +static QByteArray msgSizeFComparisonFailed(const QSizeF &s1, const QSizeF &s2) +{ + return QByteArray::number(s1.width()) + 'x' + QByteArray::number(s1.height()) + + " != " + QByteArray::number(s2.width()) + 'x' + QByteArray::number(s2.height()); +} + +#define COMPARE_POINTF(ACTUAL, EXPECTED) \ + QVERIFY2(comparePointF(ACTUAL, EXPECTED), msgPointFComparisonFailed(ACTUAL, EXPECTED).constData()) + +#define COMPARE_SIZEF(ACTUAL, EXPECTED) \ + QVERIFY2(compareSizeF(ACTUAL, EXPECTED), msgSizeFComparisonFailed(ACTUAL, EXPECTED).constData()) + void tst_QGraphicsItem::touchEventPropagation_data() { QTest::addColumn("flag"); @@ -10963,29 +11059,7 @@ void tst_QGraphicsItem::touchEventPropagation() QFETCH(QGraphicsItem::GraphicsItemFlag, flag); QFETCH(int, expectedCount); - class Testee : public QGraphicsRectItem - { - public: - int touchBeginEventCount; - - Testee() - : QGraphicsRectItem(0, 0, 100, 100) - , touchBeginEventCount(0) - { - setAcceptTouchEvents(true); - setFlag(QGraphicsItem::ItemIsFocusable, false); - } - - bool sceneEvent(QEvent *ev) - { - if (ev->type() == QEvent::TouchBegin) - ++touchBeginEventCount; - - return QGraphicsRectItem::sceneEvent(ev); - } - }; - - Testee *touchEventReceiver = new Testee; + TouchEventTestee *touchEventReceiver = new TouchEventTestee; QGraphicsItem *topMost = new QGraphicsRectItem(touchEventReceiver->boundingRect()); QGraphicsScene scene; @@ -10998,26 +11072,107 @@ void tst_QGraphicsItem::touchEventPropagation() topMost->setFlag(flag, true); QGraphicsView view(&scene); + view.setWindowTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1String("::") + + QLatin1String(QTest::currentDataTag())); view.setSceneRect(touchEventReceiver->boundingRect()); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - QCOMPARE(touchEventReceiver->touchBeginEventCount, 0); + QCOMPARE(touchEventReceiver->touchBeginEventCount(), 0); - QTouchEvent::TouchPoint tp(0); - tp.setState(Qt::TouchPointPressed); - tp.setScenePos(view.sceneRect().center()); - tp.setLastScenePos(view.sceneRect().center()); - - QList touchPoints; - touchPoints << tp; - - sendMousePress(&scene, tp.scenePos()); - QTouchDevice *device = QTest::createTouchDevice(); - QTouchEvent touchBegin(QEvent::TouchBegin, device, Qt::NoModifier, Qt::TouchPointPressed, touchPoints); + const QPointF scenePos = view.sceneRect().center(); + sendMousePress(&scene, scenePos); + if (m_touchDevice == nullptr) + m_touchDevice = QTest::createTouchDevice(); + QTouchEvent touchBegin(QEvent::TouchBegin, m_touchDevice, Qt::NoModifier, Qt::TouchPointPressed, + createTouchPoints(view, scenePos, QSizeF(10, 10))); + touchBegin.setTarget(view.viewport()); qApp->sendEvent(&scene, &touchBegin); - QCOMPARE(touchEventReceiver->touchBeginEventCount, expectedCount); + QCOMPARE(touchEventReceiver->touchBeginEventCount(), expectedCount); +} + +void tst_QGraphicsItem::touchEventTransformation_data() +{ + QTest::addColumn("flag"); + QTest::addColumn("viewTransform"); + QTest::addColumn("touchScenePos"); + QTest::addColumn("ellipseDiameters"); + QTest::addColumn("expectedItemPos"); + + QTest::newRow("notransform") + << QGraphicsItem::ItemIsSelectable << QTransform() + << QPointF(150, 150) << QSizeF(7, 8) << QPointF(50, 50); + QTest::newRow("scaled") + << QGraphicsItem::ItemIsSelectable << QTransform::fromScale(0.5, 0.5) + << QPointF(150, 150) << QSizeF(7, 8) << QPointF(50, 50); + // QTBUG-66192: When the item ignores the downscaling transformation, + // it will receive the touch point at 25,25 instead of 50,50. + QTest::newRow("scaled/ItemIgnoresTransformations") + << QGraphicsItem::ItemIgnoresTransformations << QTransform::fromScale(0.5, 0.5) + << QPointF(150, 150) << QSizeF(7, 8) << QPointF(25, 25); +} + +void tst_QGraphicsItem::touchEventTransformation() +{ + QFETCH(QGraphicsItem::GraphicsItemFlag, flag); + QFETCH(QTransform, viewTransform); + QFETCH(QPointF, touchScenePos); + QFETCH(QSizeF, ellipseDiameters); + QFETCH(QPointF, expectedItemPos); + + TouchEventTestee *touchEventReceiver = new TouchEventTestee; + + QGraphicsScene scene; + scene.addItem(touchEventReceiver); + const QPointF itemPos(100, 100); + + touchEventReceiver->setPos(itemPos); + + touchEventReceiver->setFlag(flag, true); + + QGraphicsView view(&scene); + view.setWindowTitle(QLatin1String(QTest::currentTestFunction()) + QLatin1String("::") + + QLatin1String(QTest::currentDataTag())); + view.setSceneRect(QRectF(QPointF(0, 0), QSizeF(300, 300))); + view.setTransform(viewTransform); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QCOMPARE(touchEventReceiver->touchBeginEventCount(), 0); + + if (m_touchDevice == nullptr) + m_touchDevice = QTest::createTouchDevice(); + QTouchEvent touchBegin(QEvent::TouchBegin, m_touchDevice, Qt::NoModifier, Qt::TouchPointPressed, + createTouchPoints(view, touchScenePos, ellipseDiameters)); + touchBegin.setTarget(view.viewport()); + + QCoreApplication::sendEvent(&scene, &touchBegin); + QCOMPARE(touchEventReceiver->touchBeginEventCount(), 1); + + const QTouchEvent::TouchPoint touchBeginPoint = touchEventReceiver->touchBeginPoints().constFirst(); + + COMPARE_POINTF(touchBeginPoint.scenePos(), touchScenePos); + COMPARE_POINTF(touchBeginPoint.startScenePos(), touchScenePos); + COMPARE_POINTF(touchBeginPoint.lastScenePos(), touchScenePos); + COMPARE_POINTF(touchBeginPoint.pos(), expectedItemPos); + COMPARE_SIZEF(touchBeginPoint.ellipseDiameters(), ellipseDiameters); // Must remain untransformed + + QTouchEvent touchUpdate(QEvent::TouchUpdate, m_touchDevice, Qt::NoModifier, Qt::TouchPointMoved, + createTouchPoints(view, touchScenePos, ellipseDiameters, Qt::TouchPointMoved)); + touchUpdate.setTarget(view.viewport()); + + QCoreApplication::sendEvent(&scene, &touchUpdate); + QCOMPARE(touchEventReceiver->touchUpdateEventCount(), 1); + + const QTouchEvent::TouchPoint touchUpdatePoint = touchEventReceiver->touchUpdatePoints().constFirst(); + + COMPARE_POINTF(touchUpdatePoint.scenePos(), touchScenePos); + COMPARE_POINTF(touchBeginPoint.startScenePos(), touchScenePos); + COMPARE_POINTF(touchUpdatePoint.lastScenePos(), touchScenePos); + COMPARE_POINTF(touchUpdatePoint.pos(), expectedItemPos); + COMPARE_SIZEF(touchUpdatePoint.ellipseDiameters(), ellipseDiameters); // Must remain untransformed + } void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations() diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp index fe8571abf1..3b340d06ab 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp @@ -254,7 +254,6 @@ private slots: void zeroScale(); void focusItemChangedSignal(); void minimumRenderSize(); - void checkTouchPointsEllipseDiameters(); // task specific tests below me void task139710_bspTreeCrash(); @@ -4765,81 +4764,6 @@ void tst_QGraphicsScene::minimumRenderSize() QVERIFY(smallChild->repaints > smallerGrandChild->repaints); } -class TouchItem : public QGraphicsRectItem -{ -public: - TouchItem() : QGraphicsRectItem(QRectF(-10, -10, 20, 20)), - seenTouch(false) - { - setAcceptTouchEvents(true); - setFlag(QGraphicsItem::ItemIgnoresTransformations); - } - bool seenTouch; - QList touchPoints; -protected: - bool sceneEvent(QEvent *event) override - { - switch (event->type()) { - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - seenTouch = true; - touchPoints = static_cast(event)->touchPoints(); - event->accept(); - return true; - default: - break; - } - return QGraphicsRectItem::sceneEvent(event); - } -}; - -void tst_QGraphicsScene::checkTouchPointsEllipseDiameters() -{ - QGraphicsScene scene; - QGraphicsView view(&scene); - scene.setSceneRect(1, 1, 198, 198); - view.scale(1.5, 1.5); - view.setFocus(); - TouchItem *rect = new TouchItem; - scene.addItem(rect); - view.show(); - QApplication::setActiveWindow(&view); - QVERIFY(QTest::qWaitForWindowActive(&view)); - - const QSizeF ellipseDiameters(10.0, 10.0); - QTouchEvent::TouchPoint touchPoint(0); - touchPoint.setState(Qt::TouchPointPressed); - touchPoint.setPos(view.mapFromScene(rect->mapToScene(rect->boundingRect().center()))); - touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); - touchPoint.setEllipseDiameters(ellipseDiameters); - - QList touchPoints = { touchPoint }; - - QTouchDevice *testDevice = QTest::createTouchDevice(QTouchDevice::TouchPad); - QTouchEvent touchEvent(QEvent::TouchBegin, - testDevice, - Qt::NoModifier, - Qt::TouchPointPressed, - touchPoints); - QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(rect->seenTouch); - QVERIFY(rect->touchPoints.size() == 1); - QCOMPARE(ellipseDiameters, rect->touchPoints.first().ellipseDiameters()); - - rect->seenTouch = false; - rect->touchPoints.clear(); - QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, - testDevice, - Qt::NoModifier, - Qt::TouchPointMoved, - touchPoints); - QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(rect->seenTouch); - QVERIFY(rect->touchPoints.size() == 1); - QCOMPARE(ellipseDiameters, rect->touchPoints.first().ellipseDiameters()); -} - void tst_QGraphicsScene::taskQTBUG_15977_renderWithDeviceCoordinateCache() { QGraphicsScene scene; From a4ff8634037e71ceab4dc3b6e85516aa48c6ead3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 20 Feb 2018 13:31:56 +0100 Subject: [PATCH 18/20] Add missing "We mean it." warnings Private headers not only need the _p suffix, but we also need to mean it :) Change-Id: I6028200a872661af34cbf90c77974cc1a22c09c3 Reviewed-by: Friedemann Kleint --- .../windowsuiautomation/uiaattributeids_p.h | 11 +++++++++++ .../windowsuiautomation/uiaclientinterfaces_p.h | 11 +++++++++++ .../windowsuiautomation/uiacontroltypeids_p.h | 11 +++++++++++ .../windowsuiautomation/uiaerrorids_p.h | 11 +++++++++++ .../windowsuiautomation/uiaeventids_p.h | 11 +++++++++++ .../windowsuiautomation/uiageneralids_p.h | 11 +++++++++++ .../windowsuiautomation/uiapatternids_p.h | 11 +++++++++++ .../windowsuiautomation/uiapropertyids_p.h | 11 +++++++++++ .../windowsuiautomation/uiaserverinterfaces_p.h | 11 +++++++++++ src/platformsupport/windowsuiautomation/uiatypes_p.h | 11 +++++++++++ 10 files changed, 110 insertions(+) diff --git a/src/platformsupport/windowsuiautomation/uiaattributeids_p.h b/src/platformsupport/windowsuiautomation/uiaattributeids_p.h index 52e7306a67..795cb9e551 100644 --- a/src/platformsupport/windowsuiautomation/uiaattributeids_p.h +++ b/src/platformsupport/windowsuiautomation/uiaattributeids_p.h @@ -40,6 +40,17 @@ #ifndef UIAATTRIBUTEIDS_H #define UIAATTRIBUTEIDS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #define UIA_AnimationStyleAttributeId 40000 #define UIA_BackgroundColorAttributeId 40001 #define UIA_BulletStyleAttributeId 40002 diff --git a/src/platformsupport/windowsuiautomation/uiaclientinterfaces_p.h b/src/platformsupport/windowsuiautomation/uiaclientinterfaces_p.h index b95c05f6a4..5ed79cdb47 100644 --- a/src/platformsupport/windowsuiautomation/uiaclientinterfaces_p.h +++ b/src/platformsupport/windowsuiautomation/uiaclientinterfaces_p.h @@ -40,6 +40,17 @@ #ifndef UIACLIENTINTERFACES_H #define UIACLIENTINTERFACES_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include #ifndef __IUIAutomationElement_INTERFACE_DEFINED__ diff --git a/src/platformsupport/windowsuiautomation/uiacontroltypeids_p.h b/src/platformsupport/windowsuiautomation/uiacontroltypeids_p.h index d77fc68da9..b5c5a0a4ff 100644 --- a/src/platformsupport/windowsuiautomation/uiacontroltypeids_p.h +++ b/src/platformsupport/windowsuiautomation/uiacontroltypeids_p.h @@ -40,6 +40,17 @@ #ifndef UIACONTROLTYPEIDS_H #define UIACONTROLTYPEIDS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #define UIA_ButtonControlTypeId 50000 #define UIA_CalendarControlTypeId 50001 #define UIA_CheckBoxControlTypeId 50002 diff --git a/src/platformsupport/windowsuiautomation/uiaerrorids_p.h b/src/platformsupport/windowsuiautomation/uiaerrorids_p.h index c25453007d..8c2a24dbc7 100644 --- a/src/platformsupport/windowsuiautomation/uiaerrorids_p.h +++ b/src/platformsupport/windowsuiautomation/uiaerrorids_p.h @@ -40,6 +40,17 @@ #ifndef UIAERRORIDS_H #define UIAERRORIDS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #define UIA_E_ELEMENTNOTENABLED 0x80040200 #define UIA_E_ELEMENTNOTAVAILABLE 0x80040201 #define UIA_E_NOCLICKABLEPOINT 0x80040202 diff --git a/src/platformsupport/windowsuiautomation/uiaeventids_p.h b/src/platformsupport/windowsuiautomation/uiaeventids_p.h index 2b414968ed..ed6c36834e 100644 --- a/src/platformsupport/windowsuiautomation/uiaeventids_p.h +++ b/src/platformsupport/windowsuiautomation/uiaeventids_p.h @@ -40,6 +40,17 @@ #ifndef UIAEVENTIDS_H #define UIAEVENTIDS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #define UIA_ToolTipOpenedEventId 20000 #define UIA_ToolTipClosedEventId 20001 #define UIA_StructureChangedEventId 20002 diff --git a/src/platformsupport/windowsuiautomation/uiageneralids_p.h b/src/platformsupport/windowsuiautomation/uiageneralids_p.h index 62c795b94a..220554f885 100644 --- a/src/platformsupport/windowsuiautomation/uiageneralids_p.h +++ b/src/platformsupport/windowsuiautomation/uiageneralids_p.h @@ -40,6 +40,17 @@ #ifndef UIAGENERALIDS_H #define UIAGENERALIDS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #define UiaAppendRuntimeId 3 #define UiaRootObjectId -25 diff --git a/src/platformsupport/windowsuiautomation/uiapatternids_p.h b/src/platformsupport/windowsuiautomation/uiapatternids_p.h index 114aabcaa5..d3f4c9bd7a 100644 --- a/src/platformsupport/windowsuiautomation/uiapatternids_p.h +++ b/src/platformsupport/windowsuiautomation/uiapatternids_p.h @@ -40,6 +40,17 @@ #ifndef UIAPATTERNIDS_H #define UIAPATTERNIDS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #define UIA_InvokePatternId 10000 #define UIA_SelectionPatternId 10001 #define UIA_ValuePatternId 10002 diff --git a/src/platformsupport/windowsuiautomation/uiapropertyids_p.h b/src/platformsupport/windowsuiautomation/uiapropertyids_p.h index 5c35c956f8..74e84147f6 100644 --- a/src/platformsupport/windowsuiautomation/uiapropertyids_p.h +++ b/src/platformsupport/windowsuiautomation/uiapropertyids_p.h @@ -40,6 +40,17 @@ #ifndef UIAPROPERTYIDS_H #define UIAPROPERTYIDS_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #define UIA_RuntimeIdPropertyId 30000 #define UIA_BoundingRectanglePropertyId 30001 #define UIA_ProcessIdPropertyId 30002 diff --git a/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h b/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h index caae84755b..a6a2e4c20d 100644 --- a/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h +++ b/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h @@ -40,6 +40,17 @@ #ifndef UIASERVERINTERFACES_H #define UIASERVERINTERFACES_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include #ifndef __IRawElementProviderSimple_INTERFACE_DEFINED__ diff --git a/src/platformsupport/windowsuiautomation/uiatypes_p.h b/src/platformsupport/windowsuiautomation/uiatypes_p.h index 25d8b8cb2b..ea58417943 100644 --- a/src/platformsupport/windowsuiautomation/uiatypes_p.h +++ b/src/platformsupport/windowsuiautomation/uiatypes_p.h @@ -40,6 +40,17 @@ #ifndef UIATYPES_H #define UIATYPES_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + typedef int PROPERTYID; typedef int PATTERNID; typedef int EVENTID; From a245c312b87a87ed6707e255de627aa8d1e0be7b Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 10 Jan 2018 15:52:11 +0100 Subject: [PATCH 19/20] psql: Fix SQL tests This also accounts for some quirks on the PostgreSQL side: - Null values for a related table are placed in a different order when sorted. - Functions (sum, count) return a different type than other databases - Using quotes to account for case sensitivity with tables Task-number: QTBUG-63861 Change-Id: Ib1894fa8d0c77d7045941f7c57be0d0acd8d117e Reviewed-by: Edward Welbourne --- .../sql/kernel/qsqlquery/tst_qsqlquery.cpp | 75 +++++++++++++------ .../tst_qsqlrelationaltablemodel.cpp | 33 +++++--- .../qsqltablemodel/tst_qsqltablemodel.cpp | 2 +- 3 files changed, 73 insertions(+), 37 deletions(-) diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index ada57996f4..aba99a9e20 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -2711,8 +2711,22 @@ void tst_QSqlQuery::lastInsertId() QSqlQuery q( db ); - QVERIFY_SQL( q, exec( "insert into " + qtest + " values (41, 'VarChar41', 'Char41')" ) ); - + const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); + // PostgreSQL >= 8.1 relies on lastval() which does not work if a value is + // manually inserted to the serial field, so we create a table specifically + if (dbType == QSqlDriver::PostgreSQL) { + const auto tst_lastInsertId = qTableName("tst_lastInsertId", __FILE__, db); + tst_Databases::safeDropTable(db, tst_lastInsertId); + QVERIFY_SQL(q, exec(QStringLiteral("create table ") + tst_lastInsertId + + QStringLiteral(" (id serial not null, t_varchar " + "varchar(20), t_char char(20), primary key(id))"))); + QVERIFY_SQL(q, exec(QStringLiteral("insert into ") + tst_lastInsertId + + QStringLiteral(" (t_varchar, t_char) values " + "('VarChar41', 'Char41')"))); + } else { + QVERIFY_SQL(q, exec(QStringLiteral("insert into ") + qtest + + QStringLiteral(" values (41, 'VarChar41', 'Char41')"))); + } QVariant v = q.lastInsertId(); QVERIFY( v.isValid() ); @@ -3269,10 +3283,19 @@ void tst_QSqlQuery::timeStampParsing() const QString tableName(qTableName("timeStampParsing", __FILE__, db)); tst_Databases::safeDropTable(db, tableName); QSqlQuery q(db); - QVERIFY_SQL(q, exec(QStringLiteral("CREATE TABLE ") + tableName - + QStringLiteral(" (id integer, datefield timestamp)"))); - QVERIFY_SQL(q, exec(QStringLiteral("INSERT INTO ") + tableName - + QStringLiteral(" (datefield) VALUES (current_timestamp)"))); + QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); + if (dbType == QSqlDriver::PostgreSQL) { + QVERIFY_SQL(q, exec(QStringLiteral("CREATE TABLE ") + tableName + QStringLiteral("(" + "id serial NOT NULL, " + "datefield timestamp, primary key(id));"))); + } else { + QVERIFY_SQL(q, exec(QStringLiteral("CREATE TABLE ") + tableName + QStringLiteral("(" + "\"id\" integer NOT NULL PRIMARY KEY AUTOINCREMENT," + "\"datefield\" timestamp);"))); + } + QVERIFY_SQL(q, exec( + QStringLiteral("INSERT INTO ") + tableName + QStringLiteral(" (datefield) VALUES (current_timestamp);" + ))); QVERIFY_SQL(q, exec(QStringLiteral("SELECT * FROM ") + tableName)); while (q.next()) QVERIFY(q.value(1).toDateTime().isValid()); @@ -3643,15 +3666,17 @@ void tst_QSqlQuery::QTBUG_18435() void tst_QSqlQuery::QTBUG_5251() { + // Since QSqlTableModel will escape the identifiers, we need to escape + // them for databases that are case sensitive QFETCH( QString, dbName ); QSqlDatabase db = QSqlDatabase::database( dbName ); CHECK_DATABASE( db ); const QString timetest(qTableName("timetest", __FILE__, db)); - + tst_Databases::safeDropTable(db, timetest); QSqlQuery q(db); - q.exec("DROP TABLE " + timetest); - QVERIFY_SQL(q, exec("CREATE TABLE " + timetest + " (t TIME)")); - QVERIFY_SQL(q, exec("INSERT INTO " + timetest + " VALUES ('1:2:3.666')")); + QVERIFY_SQL(q, exec(QStringLiteral("CREATE TABLE \"") + timetest + QStringLiteral("\" (t TIME)"))); + QVERIFY_SQL(q, exec(QStringLiteral("INSERT INTO \"") + timetest + + QStringLiteral("\" VALUES ('1:2:3.666')"))); QSqlTableModel timetestModel(0,db); timetestModel.setEditStrategy(QSqlTableModel::OnManualSubmit); @@ -3664,7 +3689,8 @@ void tst_QSqlQuery::QTBUG_5251() QVERIFY_SQL(timetestModel, submitAll()); QCOMPARE(timetestModel.record(0).field(0).value().toTime().toString("HH:mm:ss.zzz"), QString("00:12:34.500")); - QVERIFY_SQL(q, exec("UPDATE " + timetest + " SET t = '0:11:22.33'")); + QVERIFY_SQL(q, exec(QStringLiteral("UPDATE \"") + timetest + + QStringLiteral("\" SET t = '0:11:22.33'"))); QVERIFY_SQL(timetestModel, select()); QCOMPARE(timetestModel.record(0).field(0).value().toTime().toString("HH:mm:ss.zzz"), QString("00:11:22.330")); @@ -4241,12 +4267,18 @@ void tst_QSqlQuery::aggregateFunctionTypes() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); QVariant::Type intType = QVariant::Int; + QVariant::Type sumType = intType; + QVariant::Type countType = intType; // QPSQL uses LongLong for manipulation of integers const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); - if (dbType == QSqlDriver::PostgreSQL) - intType = QVariant::LongLong; - else if (dbType == QSqlDriver::Oracle) - intType = QVariant::Double; + if (dbType == QSqlDriver::PostgreSQL) { + sumType = countType = QVariant::LongLong; + } else if (dbType == QSqlDriver::Oracle) { + intType = sumType = countType = QVariant::Double; + } else if (dbType == QSqlDriver::MySqlServer) { + sumType = QVariant::Double; + countType = QVariant::LongLong; + } { const QString tableName(qTableName("numericFunctionsWithIntValues", __FILE__, db)); tst_Databases::safeDropTable( db, tableName ); @@ -4259,10 +4291,8 @@ void tst_QSqlQuery::aggregateFunctionTypes() QVERIFY(q.next()); if (dbType == QSqlDriver::SQLite) QCOMPARE(q.record().field(0).type(), QVariant::Invalid); - else if (dbType == QSqlDriver::MySqlServer) - QCOMPARE(q.record().field(0).type(), QVariant::Double); else - QCOMPARE(q.record().field(0).type(), intType); + QCOMPARE(q.record().field(0).type(), sumType); QVERIFY_SQL(q, exec("INSERT INTO " + tableName + " (id) VALUES (1)")); QVERIFY_SQL(q, exec("INSERT INTO " + tableName + " (id) VALUES (2)")); @@ -4270,10 +4300,7 @@ void tst_QSqlQuery::aggregateFunctionTypes() QVERIFY_SQL(q, exec("SELECT SUM(id) FROM " + tableName)); QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), 3); - if (dbType == QSqlDriver::MySqlServer) - QCOMPARE(q.record().field(0).type(), QVariant::Double); - else - QCOMPARE(q.record().field(0).type(), intType); + QCOMPARE(q.record().field(0).type(), sumType); QVERIFY_SQL(q, exec("SELECT AVG(id) FROM " + tableName)); QVERIFY(q.next()); @@ -4289,7 +4316,7 @@ void tst_QSqlQuery::aggregateFunctionTypes() QVERIFY_SQL(q, exec("SELECT COUNT(id) FROM " + tableName)); QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), 2); - QCOMPARE(q.record().field(0).type(), dbType != QSqlDriver::MySqlServer ? intType : QVariant::LongLong); + QCOMPARE(q.record().field(0).type(), countType); QVERIFY_SQL(q, exec("SELECT MIN(id) FROM " + tableName)); QVERIFY(q.next()); @@ -4332,7 +4359,7 @@ void tst_QSqlQuery::aggregateFunctionTypes() QVERIFY_SQL(q, exec("SELECT COUNT(id) FROM " + tableName)); QVERIFY(q.next()); QCOMPARE(q.value(0).toInt(), 2); - QCOMPARE(q.record().field(0).type(), dbType != QSqlDriver::MySqlServer ? intType : QVariant::LongLong); + QCOMPARE(q.record().field(0).type(), countType); QVERIFY_SQL(q, exec("SELECT MIN(id) FROM " + tableName)); QVERIFY(q.next()); diff --git a/tests/auto/sql/models/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp b/tests/auto/sql/models/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp index 84cca482fb..f1c55df1ef 100644 --- a/tests/auto/sql/models/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp +++ b/tests/auto/sql/models/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp @@ -385,6 +385,7 @@ void tst_QSqlRelationalTableModel::setData() model.setRelation(1, QSqlRelation(reltest5, "title", "abbrev")); model.setEditStrategy(QSqlTableModel::OnManualSubmit); model.setJoinMode(QSqlRelationalTableModel::LeftJoin); + model.setSort(0, Qt::AscendingOrder); QVERIFY_SQL(model, select()); QCOMPARE(model.data(model.index(0,1)).toString(), QString("Mr")); @@ -783,24 +784,32 @@ void tst_QSqlRelationalTableModel::sort() QVERIFY_SQL(model, select()); QCOMPARE(model.rowCount(), 6); - QCOMPARE(model.data(model.index(0, 2)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(1, 2)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(2, 2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(3, 2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(4, 2)).toString(), QString("")); - QCOMPARE(model.data(model.index(5, 2)).toString(), QString("")); + + QStringList stringsInDatabaseOrder; + // PostgreSQL puts the null ones (from the table with the original value) first in descending order + // which translate to empty strings in the related table + if (dbType == QSqlDriver::PostgreSQL) + stringsInDatabaseOrder << "" << "" << "mister" << "mister" << "herr" << "herr"; + else + stringsInDatabaseOrder << "mister" << "mister" << "herr" << "herr" << "" << ""; + for (int i = 0; i < 6; ++i) + QCOMPARE(model.data(model.index(i, 2)).toString(), stringsInDatabaseOrder.at(i)); model.setSort(3, Qt::AscendingOrder); QVERIFY_SQL(model, select()); + // PostgreSQL puts the null ones (from the table with the original value) first in descending order + // which translate to empty strings in the related table + stringsInDatabaseOrder.clear(); + if (dbType == QSqlDriver::PostgreSQL) + stringsInDatabaseOrder << "herr" << "mister" << "mister" << "mister" << "mister" << ""; + else if (dbType != QSqlDriver::Sybase) + stringsInDatabaseOrder << "" << "herr" << "mister" << "mister" << "mister" << "mister"; + if (dbType != QSqlDriver::Sybase) { QCOMPARE(model.rowCount(), 6); - QCOMPARE(model.data(model.index(0, 3)).toString(), QString("")); - QCOMPARE(model.data(model.index(1, 3)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(2, 3)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(3, 3)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(4, 3)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(5, 3)).toString(), QString("mister")); + for (int i = 0; i < 6; ++i) + QCOMPARE(model.data(model.index(i, 3)).toString(), stringsInDatabaseOrder.at(i)); } else { QCOMPARE(model.data(model.index(0, 3)).toInt(), 1); QCOMPARE(model.data(model.index(1, 3)).toInt(), 2); diff --git a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp index bf76ed2bb6..ded360ef8d 100644 --- a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp @@ -275,7 +275,7 @@ void tst_QSqlTableModel::init() void tst_QSqlTableModel::cleanup() { - repopulateTestTables(); + recreateTestTables(); } void tst_QSqlTableModel::select() From 8dbd245979dac890c9317a27067a43205314a4f0 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 11 Feb 2018 12:31:04 +0100 Subject: [PATCH 20/20] QtConcurrent::MedianDouble: do not access uninitialzed values Properly initialize MedianDouble::values in ctor. This fixes the following valgrind warnings in the unit test: Conditional jump or move depends on uninitialised value(s) at 0x40771E4: addValue (qtconcurrentmedian.h:161) by 0x40771E4: QtConcurrent::BlockSizeManagerV2::timeAfterUser() (qtconcurrentiteratekernel.cpp:195) Change-Id: I8c8e297a52caca38cd6191ae2653f2765d387077 Reviewed-by: Frederik Gladhorn --- src/concurrent/qtconcurrentmedian.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/concurrent/qtconcurrentmedian.h b/src/concurrent/qtconcurrentmedian.h index 87e6b2935d..864b2d33d5 100644 --- a/src/concurrent/qtconcurrentmedian.h +++ b/src/concurrent/qtconcurrentmedian.h @@ -135,6 +135,7 @@ public: MedianDouble() : currentMedian(), currentIndex(0), valid(false), dirty(true) { + std::fill_n(values, static_cast(BufferSize), 0.0); } void reset()