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

Change-Id: I9c90d71fde002544fd97df7e8a2690953cf9f817
This commit is contained in:
Qt Forward Merge Bot 2018-02-21 09:41:46 +01:00
commit b949c44783
36 changed files with 922 additions and 250 deletions

View File

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

154
dist/changes-5.10.1 vendored Normal file
View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,8 +1140,14 @@ 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)
{
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();
@ -1150,21 +1158,29 @@ static void init_platform(const QString &pluginArgument, const QString &platform
// 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");
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 {
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));
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;
}
}
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 (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 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]);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &region)
{
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()

View File

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

View File

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

View File

@ -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);
}
/*!

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -275,7 +275,7 @@ void tst_QSqlTableModel::init()
void tst_QSqlTableModel::cleanup()
{
repopulateTestTables();
recreateTestTables();
}
void tst_QSqlTableModel::select()

View File

@ -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());
QList<QTouchEvent::TouchPoint> 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<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
}
void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations()

View File

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

View File

@ -411,6 +411,7 @@ void tst_QLineEdit::cleanup()
{
delete m_testWidget;
m_testWidget = 0;
m_platformInputContext.m_commitString.clear();
}
void tst_QLineEdit::experimental()

View File

@ -1,3 +1,4 @@
TEMPLATE = subdirs
SUBDIRS = \
qsqlquery \
qsqlrecord

View File

@ -0,0 +1,5 @@
TARGET = tst_bench_qsqlrecord
SOURCES += tst_qsqlrecord.cpp
QT = core sql testlib core-private sql-private

View File

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