diff options
36 files changed, 922 insertions, 250 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 <name> .......... Select default QPA backend (e.g., xcb, cocoa, windows) + -qpa <name> .......... 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/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 <paths.h>) 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. diff --git a/doc/src/images/borderlayout-example.png b/doc/src/images/borderlayout-example.png Binary files differindex e856e06572..27b939bc2e 100644 --- a/doc/src/images/borderlayout-example.png +++ b/doc/src/images/borderlayout-example.png 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 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 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) { "</qresource>" \ "</RCC>" - !write_file($$OUT_PWD/$$resource_file, resource_file_content): \ + !write_file($$absolute_path($$resource_file, $$OUT_PWD), resource_file_content): \ error() } 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<int>(BufferSize), 0.0); } void reset() 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 <sys/pstat.h> #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 <sys/prctl.h> #endif diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index b465bdc0f4..ed56f99771 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -568,10 +568,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) @@ -600,11 +596,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/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index f7da94d111..12390928f0 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 @@ -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 @@ -1138,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) -{ - // 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)); +Q_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin"); + +static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv) +{ + 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)) { + 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 { + QGuiApplicationPrivate::platform_name = new QString(name); + platformArguments = arguments; + break; + } + } - // 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 = QStringLiteral("This application failed to start because no Qt platform plugin could be initialized. " + "Reinstalling the application may fix this problem.\n"); - 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"); - } 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)); - } + 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. @@ -1172,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()) { @@ -1223,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(); @@ -1289,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; @@ -1302,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]); } 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 <Unknwn.h> #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 <Unknwn.h> #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; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 471a19adb0..3bc9055650 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1126,13 +1126,11 @@ 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) { - 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 @@ -1326,7 +1324,7 @@ void QCocoaWindow::recreateWindowIfNeeded() void QCocoaWindow::requestUpdate() { qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::requestUpdate" << window(); - [m_view requestUpdate]; + [qnsview_cast(m_view) requestUpdate]; } void QCocoaWindow::requestActivateWindow() 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) diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 6f105f79ca..368b777ca5 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -204,6 +204,7 @@ public: void setDatestyle(); void setByteaOutput(); void detectBackslashEscape(); + mutable QHash<int, QString> oidToTable; }; void QPSQLDriverPrivate::appendTables(QStringList &tl, QSqlQuery &t, QChar type) @@ -815,18 +816,20 @@ QSqlRecord QPSQLResult::record() const f.setName(QString::fromUtf8(PQfname(d->result, i))); else f.setName(QString::fromLocal8Bit(PQfname(d->result, i))); - + const int tableOid = PQftable(d->result, i); + auto &tableName = d->drv_d_func()->oidToTable[tableOid]; // WARNING: We cannot execute any other SQL queries on // the same db connection while forward-only mode is active // (this would discard all results of forward-only query). // So we just skip this... - if (!isForwardOnly()) { + if (tableName.isEmpty() && !isForwardOnly()) { 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()); + .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/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<QGraphicsView *>(viewport->parentWidget()); - if (!view) - return q->mapFromScene(pos); + return sceneTransform.inverted(); + const QGraphicsView *view = viewport + ? qobject_cast<QGraphicsView *>(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<const QWidget *>(touchEvent->target())); + for (auto &touchPoint : touchEvent->_touchPoints) { - touchPoint.setRect(item->mapFromScene(touchPoint.sceneRect()).boundingRect()); - touchPoint.setStartPos(item->d_ptr->genericMapFromScene(touchPoint.startScenePos(), static_cast<QWidget *>(touchEvent->target()))); - touchPoint.setLastPos(item->d_ptr->genericMapFromScene(touchPoint.lastScenePos(), static_cast<QWidget *>(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/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index c22998f804..6aa3c498aa 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -6091,8 +6091,14 @@ void tst_QString::compare_data() QTest::addColumn<int>("csr"); // case sensitive result QTest::addColumn<int>("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; diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index baf2551dfb..aba99a9e20 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -370,7 +370,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); @@ -1009,6 +1010,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 ); @@ -1030,6 +1054,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() @@ -2667,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() ); @@ -3225,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()); @@ -3599,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); @@ -3620,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")); @@ -4197,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 ); @@ -4215,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)")); @@ -4226,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()); @@ -4245,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()); @@ -4288,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() 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 <QAbstractTextDocumentLayout> #include <QBitmap> #include <QCursor> +#include <QDesktopWidget> #include <QScreen> #include <QLabel> #include <QDial> @@ -54,10 +55,13 @@ #include <QPushButton> #include <QLineEdit> #include <QGraphicsLinearLayout> +#include <QTransform> #include <float.h> #include <QStyleHints> Q_DECLARE_METATYPE(QPainterPath) +Q_DECLARE_METATYPE(QSizeF) +Q_DECLARE_METATYPE(QTransform) #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) #include <windows.h> @@ -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<QGraphicsItem *> 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<QTouchEvent::TouchPoint> touchBeginPoints() const { return m_touchBeginPoints; } + int touchBeginEventCount() const { return m_touchBeginPoints.size(); } + + QList<QTouchEvent::TouchPoint> 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<const QTouchEvent *>(ev)->touchPoints().constFirst()); + ev->accept(); + return true; + case QEvent::TouchUpdate: + m_touchUpdatePoints.append(static_cast<const QTouchEvent *>(ev)->touchPoints().constFirst()); + ev->accept(); + return true; + default: + break; + } + + return QGraphicsRectItem::sceneEvent(ev); + } + +private: + QList<QTouchEvent::TouchPoint> m_touchBeginPoints; + QList<QTouchEvent::TouchPoint> m_touchUpdatePoints; +}; + +static QList<QTouchEvent::TouchPoint> + 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<QTouchEvent::TouchPoint>() << 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<QGraphicsItem::GraphicsItemFlag>("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()); + 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()); - QList<QTouchEvent::TouchPoint> touchPoints; - touchPoints << tp; + qApp->sendEvent(&scene, &touchBegin); + QCOMPARE(touchEventReceiver->touchBeginEventCount(), expectedCount); +} - sendMousePress(&scene, tp.scenePos()); - QTouchDevice *device = QTest::createTouchDevice(); - QTouchEvent touchBegin(QEvent::TouchBegin, device, Qt::NoModifier, Qt::TouchPointPressed, touchPoints); +void tst_QGraphicsItem::touchEventTransformation_data() +{ + QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("flag"); + QTest::addColumn<QTransform>("viewTransform"); + QTest::addColumn<QPointF>("touchScenePos"); + QTest::addColumn<QSizeF>("ellipseDiameters"); + QTest::addColumn<QPointF>("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 - qApp->sendEvent(&scene, &touchBegin); - QCOMPARE(touchEventReceiver->touchBeginEventCount, expectedCount); } 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<QTouchEvent::TouchPoint> touchPoints; -protected: - bool sceneEvent(QEvent *event) override - { - switch (event->type()) { - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - seenTouch = true; - touchPoints = static_cast<QTouchEvent *>(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<QTouchEvent::TouchPoint> 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; diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 045c242fb4..9015c03f3f 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() 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 <QtTest/QtTest> +#include <QtSql/QtSql> + +#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" |