summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-02-28 01:00:14 +0100
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-02-28 01:00:15 +0100
commit043f99954faa8355c9f0d78d441099a6f7e1ad8b (patch)
tree3543e16fef20cb6f71b1374594477a4b145f9bab
parentf6ce77f3e4dbc67531db7eeaf271c5416b4a4934 (diff)
parentf657c7426329d3763bbf3373b986378c22020269 (diff)
Merge remote-tracking branch 'origin/5.12' into 5.13
-rw-r--r--mkspecs/common/mac.conf2
-rw-r--r--mkspecs/features/mac/sdk.prf4
-rw-r--r--qmake/generators/win32/msvc_vcproj.cpp27
-rw-r--r--qmake/generators/win32/msvc_vcproj.h1
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp4
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp10
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h7
-rw-r--r--src/corelib/kernel/qobject.cpp6
-rw-r--r--src/gui/configure.json2
-rw-r--r--src/gui/configure.pri11
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp20
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h1
-rw-r--r--src/gui/text/qsyntaxhighlighter.cpp2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen.cpp3
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp27
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow_p.h1
-rw-r--r--src/plugins/platforms/haiku/haiku.pro2
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp6
-rw-r--r--src/widgets/itemviews/qabstractitemview.cpp2
-rw-r--r--src/widgets/itemviews/qlistview.cpp4
-rw-r--r--src/widgets/itemviews/qlistview_p.h19
-rw-r--r--tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp155
-rw-r--r--tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp46
-rw-r--r--tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp54
24 files changed, 375 insertions, 41 deletions
diff --git a/mkspecs/common/mac.conf b/mkspecs/common/mac.conf
index b77494ec9b..f21ba5ec51 100644
--- a/mkspecs/common/mac.conf
+++ b/mkspecs/common/mac.conf
@@ -17,7 +17,7 @@ QMAKE_EXTENSION_SHLIB = dylib
QMAKE_EXTENSIONS_AUX_SHLIB = tbd
QMAKE_LIBDIR =
-# sdk.prf will prefix the proper SDK sysroot
+# qtConfLibrary_openglMakeSpec will prefix the proper SDK sysroot
QMAKE_INCDIR_OPENGL = \
/System/Library/Frameworks/OpenGL.framework/Headers \
/System/Library/Frameworks/AGL.framework/Headers/
diff --git a/mkspecs/features/mac/sdk.prf b/mkspecs/features/mac/sdk.prf
index 8360dd8b38..50a41657d8 100644
--- a/mkspecs/features/mac/sdk.prf
+++ b/mkspecs/features/mac/sdk.prf
@@ -33,10 +33,6 @@ QMAKE_MAC_SDK_PATH = $$xcodeSDKInfo(Path)
QMAKE_MAC_SDK_PLATFORM_PATH = $$xcodeSDKInfo(PlatformPath)
QMAKE_MAC_SDK_VERSION = $$xcodeSDKInfo(SDKVersion)
-sysrootified =
-for(val, QMAKE_INCDIR_OPENGL): sysrootified += $${QMAKE_MAC_SDK_PATH}$$val
-QMAKE_INCDIR_OPENGL = $$sysrootified
-
QMAKESPEC_NAME = $$basename(QMAKESPEC)
# Resolve SDK version of various tools
diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp
index e5af54b5b7..06a96f7538 100644
--- a/qmake/generators/win32/msvc_vcproj.cpp
+++ b/qmake/generators/win32/msvc_vcproj.cpp
@@ -1454,6 +1454,7 @@ void VcprojGenerator::initTranslationFiles()
vcProject.TranslationFiles.Guid = _GUIDTranslationFiles;
vcProject.TranslationFiles.addFiles(project->values("TRANSLATIONS"));
+ vcProject.TranslationFiles.addFiles(project->values("EXTRA_TRANSLATIONS"));
vcProject.TranslationFiles.Project = this;
vcProject.TranslationFiles.Config = &(vcProject.Configuration);
@@ -1576,7 +1577,7 @@ void VcprojGenerator::initExtraCompilerOutputs()
const ProStringList &tmp_in = project->values(project->first(ProKey(*it + ".input")).toKey());
for (int i = 0; i < tmp_in.count(); ++i) {
const QString &filename = tmp_in.at(i).toQString();
- if (extraCompilerSources.contains(filename))
+ if (extraCompilerSources.contains(filename) && !otherFiltersContain(filename))
extraCompile.addFile(Option::fixPathToTargetOS(
replaceExtraCompilerVariables(filename, tmp_out, QString(), NoShell), false));
}
@@ -1592,7 +1593,7 @@ void VcprojGenerator::initExtraCompilerOutputs()
const ProStringList &tmp_in = project->values(inputVar.toKey());
for (int i = 0; i < tmp_in.count(); ++i) {
const QString &filename = tmp_in.at(i).toQString();
- if (extraCompilerSources.contains(filename))
+ if (extraCompilerSources.contains(filename) && !otherFiltersContain(filename))
extraCompile.addFile(Option::fixPathToTargetOS(
replaceExtraCompilerVariables(filename, QString(), QString(), NoShell), false));
}
@@ -1606,6 +1607,28 @@ void VcprojGenerator::initExtraCompilerOutputs()
}
}
+bool VcprojGenerator::otherFiltersContain(const QString &fileName) const
+{
+ auto filterFileMatches = [&fileName] (const VCFilterFile &ff)
+ {
+ return ff.file == fileName;
+ };
+ for (const VCFilter *filter : { &vcProject.RootFiles,
+ &vcProject.SourceFiles,
+ &vcProject.HeaderFiles,
+ &vcProject.GeneratedFiles,
+ &vcProject.LexYaccFiles,
+ &vcProject.TranslationFiles,
+ &vcProject.FormFiles,
+ &vcProject.ResourceFiles,
+ &vcProject.DeploymentFiles,
+ &vcProject.DistributionFiles}) {
+ if (std::any_of(filter->Files.cbegin(), filter->Files.cend(), filterFileMatches))
+ return true;
+ }
+ return false;
+}
+
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h
index 6f9743cb09..55d36c3762 100644
--- a/qmake/generators/win32/msvc_vcproj.h
+++ b/qmake/generators/win32/msvc_vcproj.h
@@ -132,6 +132,7 @@ private:
ProString firstInputFileName(const ProString &extraCompilerName) const;
QString firstExpandedOutputFileName(const ProString &extraCompilerName);
void createCustomBuildToolFakeFile(const QString &cbtFilePath, const QString &realOutFilePath);
+ bool otherFiltersContain(const QString &fileName) const;
friend class VCFilter;
};
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index db66157a0e..c06af79cc7 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -2676,9 +2676,9 @@ QStringList QCoreApplication::libraryPaths()
QStringList *app_libpaths = new QStringList;
coreappdata()->app_libpaths.reset(app_libpaths);
- const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH");
+ QString libPathEnv = qEnvironmentVariable("QT_PLUGIN_PATH");
if (!libPathEnv.isEmpty()) {
- QStringList paths = QFile::decodeName(libPathEnv).split(QDir::listSeparator(), QString::SkipEmptyParts);
+ QStringList paths = libPathEnv.split(QDir::listSeparator(), QString::SkipEmptyParts);
for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) {
QString canonicalPath = QDir(*it).canonicalPath();
if (!canonicalPath.isEmpty()
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 343ed70196..685d765adb 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -95,7 +95,7 @@ class QEventDispatcherWin32Private;
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
- : threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0),
+ : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0),
getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0),
wakeUps(0), activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL)
{
@@ -552,7 +552,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
wakeUp(); // trigger a call to sendPostedEvents()
}
- d->interrupt = false;
+ d->interrupt.store(false);
emit awake();
bool canWait;
@@ -568,7 +568,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
pHandles = &d->winEventNotifierActivatedEvent;
}
QVarLengthArray<MSG> processedTimers;
- while (!d->interrupt) {
+ while (!d->interrupt.load()) {
MSG msg;
bool haveMessage;
@@ -649,7 +649,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
// still nothing - wait for message or signalled objects
canWait = (!retVal
- && !d->interrupt
+ && !d->interrupt.load()
&& (flags & QEventLoop::WaitForMoreEvents));
if (canWait) {
emit aboutToBlock();
@@ -1022,7 +1022,7 @@ void QEventDispatcherWin32::wakeUp()
void QEventDispatcherWin32::interrupt()
{
Q_D(QEventDispatcherWin32);
- d->interrupt = true;
+ d->interrupt.store(true);
wakeUp();
}
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index 707bc79407..dbad2a5450 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -165,8 +165,7 @@ public:
DWORD threadId;
- bool interrupt;
- bool closingDown;
+ QAtomicInt interrupt;
// internal window handle used for socketnotifiers/timers/etc
HWND internalHwnd;
@@ -193,9 +192,11 @@ public:
void postActivateSocketNotifiers();
void doWsaAsyncSelect(int socket, long event);
+ bool closingDown = false;
+
+ bool winEventNotifierListModified = false;
HANDLE winEventNotifierActivatedEvent;
QList<QWinEventNotifier *> winEventNotifierList;
- bool winEventNotifierListModified = false;
void activateEventNotifier(QWinEventNotifier * wen);
QList<MSG> queuedUserInputEvents;
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index e67b2306c2..3a3eb726fa 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -2175,8 +2175,10 @@ void QObject::removeEventFilter(QObject *obj)
Note that entering and leaving a new event loop (e.g., by opening a modal
dialog) will \e not perform the deferred deletion; for the object to be
- deleted, the control must return to the event loop from which
- deleteLater() was called.
+ deleted, the control must return to the event loop from which deleteLater()
+ was called. This does not apply to objects deleted while a previous, nested
+ event loop was still running: the Qt event loop will delete those objects
+ as soon as the new nested event loop starts.
\b{Note:} It is safe to call this function more than once; when the
first deferred deletion event is delivered, any pending events for the
diff --git a/src/gui/configure.json b/src/gui/configure.json
index b5bfdc4a33..59c06af97f 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -448,7 +448,7 @@
],
"sources": [
{ "type": "pkgConfig", "args": "gl", "condition": "!config.darwin" },
- { "type": "makeSpec", "spec": "OPENGL" }
+ { "type": "openglMakeSpec" }
]
},
"opengl_es2": {
diff --git a/src/gui/configure.pri b/src/gui/configure.pri
index 1b95449a10..0db106597e 100644
--- a/src/gui/configure.pri
+++ b/src/gui/configure.pri
@@ -15,6 +15,17 @@ defineTest(qtConfLibrary_freetype) {
return(true)
}
+defineTest(qtConfLibrary_openglMakeSpec) {
+ darwin:sdk {
+ sysrootified =
+ for(val, QMAKE_INCDIR_OPENGL): sysrootified += $${QMAKE_MAC_SDK_PATH}$$val
+ QMAKE_INCDIR_OPENGL = $$sysrootified
+ }
+ $${1}.spec = OPENGL
+ !qtConfLibrary_makeSpec($$1, $$2): return(false)
+ return(true)
+}
+
# Check for Direct X shader compiler 'fxc'.
# Up to Direct X SDK June 2010 and for MinGW, this is pointed to by the
# DXSDK_DIR variable. Starting with Windows Kit 8, it is included in
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 5b32405f5e..7067ece1d8 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -695,13 +695,29 @@ QList<QTouchEvent::TouchPoint>
}
if (states == Qt::TouchPointReleased) {
- g_nextPointId = 1;
- g_pointIdMap->clear();
+ // All points on deviceId have been released.
+ // Remove all points associated with that device from g_pointIdMap.
+ // (On other devices, some touchpoints might still be pressed.
+ // But this function is only called with points from one device at a time.)
+ for (auto it = g_pointIdMap->begin(); it != g_pointIdMap->end();) {
+ if (it.key() >> 32 == quint64(deviceId))
+ it = g_pointIdMap->erase(it);
+ else
+ ++it;
+ }
+ if (g_pointIdMap->isEmpty())
+ g_nextPointId = 1;
}
return touchPoints;
}
+void QWindowSystemInterfacePrivate::clearPointIdMap()
+{
+ g_pointIdMap->clear();
+ g_nextPointId = 1;
+}
+
QList<QWindowSystemInterface::TouchPoint>
QWindowSystemInterfacePrivate::toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList,
const QWindow *window)
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index 563ca8f922..6c818a9030 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -537,6 +537,7 @@ public:
static QList<QWindowSystemInterface::TouchPoint>
toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList,
const QWindow *window);
+ static void clearPointIdMap();
static void installWindowSystemEventHandler(QWindowSystemEventHandler *handler);
static void removeWindowSystemEventhandler(QWindowSystemEventHandler *handler);
diff --git a/src/gui/text/qsyntaxhighlighter.cpp b/src/gui/text/qsyntaxhighlighter.cpp
index 0e07b69868..102a776ed3 100644
--- a/src/gui/text/qsyntaxhighlighter.cpp
+++ b/src/gui/text/qsyntaxhighlighter.cpp
@@ -297,7 +297,7 @@ void QSyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block)
QSyntaxHighlighter::QSyntaxHighlighter(QObject *parent)
: QObject(*new QSyntaxHighlighterPrivate, parent)
{
- if (parent->inherits("QTextEdit")) {
+ if (parent && parent->inherits("QTextEdit")) {
QTextDocument *doc = parent->property("document").value<QTextDocument *>();
if (doc)
setDocument(doc);
diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
index 285dbd93d3..11b68c0589 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
@@ -62,9 +62,6 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
QEglFSScreen::~QEglFSScreen()
{
delete m_cursor;
-#ifndef QT_NO_OPENGL
- QOpenGLCompositor::destroy();
-#endif
}
QRect QEglFSScreen::geometry() const
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
index 29cfd4ea79..98e9ee4728 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
@@ -62,6 +62,7 @@ QEglFSWindow::QEglFSWindow(QWindow *w)
: QPlatformWindow(w),
#ifndef QT_NO_OPENGL
m_backingStore(0),
+ m_rasterCompositingContext(0),
#endif
m_raster(false),
m_winId(0),
@@ -144,18 +145,18 @@ void QEglFSWindow::create()
#ifndef QT_NO_OPENGL
if (isRaster()) {
- QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance());
- context->setShareContext(qt_gl_global_share_context());
- context->setFormat(m_format);
- context->setScreen(window()->screen());
- if (Q_UNLIKELY(!context->create()))
+ m_rasterCompositingContext = new QOpenGLContext;
+ m_rasterCompositingContext->setShareContext(qt_gl_global_share_context());
+ m_rasterCompositingContext->setFormat(m_format);
+ m_rasterCompositingContext->setScreen(window()->screen());
+ if (Q_UNLIKELY(!m_rasterCompositingContext->create()))
qFatal("EGLFS: Failed to create compositing context");
- compositor->setTarget(context, window(), screen->rawGeometry());
+ compositor->setTarget(m_rasterCompositingContext, window(), screen->rawGeometry());
compositor->setRotation(qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION"));
// If there is a "root" window into which raster and QOpenGLWidget content is
// composited, all other contexts must share with its context.
if (!qt_gl_global_share_context()) {
- qt_gl_set_global_share_context(context);
+ qt_gl_set_global_share_context(m_rasterCompositingContext);
// What we set up here is in effect equivalent to the application setting
// AA_ShareOpenGLContexts. Set the attribute to be fully consistent.
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
@@ -166,6 +167,10 @@ void QEglFSWindow::create()
void QEglFSWindow::destroy()
{
+#ifndef QT_NO_OPENGL
+ QOpenGLCompositor::instance()->removeWindow(this);
+#endif
+
QEglFSScreen *screen = this->screen();
if (m_flags.testFlag(HasNativeWindow)) {
#ifndef QT_NO_OPENGL
@@ -177,12 +182,14 @@ void QEglFSWindow::destroy()
screen->setPrimarySurface(EGL_NO_SURFACE);
invalidateSurface();
- }
- m_flags = 0;
#ifndef QT_NO_OPENGL
- QOpenGLCompositor::instance()->removeWindow(this);
+ QOpenGLCompositor::destroy();
+ delete m_rasterCompositingContext;
#endif
+ }
+
+ m_flags = 0;
}
void QEglFSWindow::invalidateSurface()
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
index c61f04f569..b0091e2a62 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
@@ -116,6 +116,7 @@ public:
protected:
#ifndef QT_NO_OPENGL
QOpenGLCompositorBackingStore *m_backingStore;
+ QOpenGLContext *m_rasterCompositingContext;
#endif
bool m_raster;
WId m_winId;
diff --git a/src/plugins/platforms/haiku/haiku.pro b/src/plugins/platforms/haiku/haiku.pro
index fd1f47b963..e7702361ee 100644
--- a/src/plugins/platforms/haiku/haiku.pro
+++ b/src/plugins/platforms/haiku/haiku.pro
@@ -1,6 +1,6 @@
TARGET = qhaiku
-QT += core-private gui-private eventdistpatcher_support-private
+QT += core-private gui-private eventdispatcher_support-private
SOURCES = \
main.cpp \
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 41655dbd57..80517ffe69 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -1099,6 +1099,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return false;
case QtWindows::ClipboardEvent:
return false;
+ case QtWindows::CursorEvent: // Sent to windows that do not have capture (see QTBUG-58590).
+ if (QWindowsCursor::hasOverrideCursor()) {
+ QWindowsCursor::enforceOverrideCursor();
+ return true;
+ }
+ break;
case QtWindows::UnknownEvent:
return false;
case QtWindows::AccessibleObjectFromWindowRequest:
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp
index 63803767c8..59d3ed1d15 100644
--- a/src/widgets/itemviews/qabstractitemview.cpp
+++ b/src/widgets/itemviews/qabstractitemview.cpp
@@ -1912,7 +1912,7 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
bool click = (index == d->pressedIndex && index.isValid());
bool selectedClicked = click && (event->button() == Qt::LeftButton) && d->pressedAlreadySelected;
EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
- bool edited = edit(index, trigger, event);
+ const bool edited = click ? edit(index, trigger, event) : false;
d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp
index e7b2aaec29..641b15f85b 100644
--- a/src/widgets/itemviews/qlistview.cpp
+++ b/src/widgets/itemviews/qlistview.cpp
@@ -1315,8 +1315,8 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl
if (tl.isValid() && br.isValid()
&& d->isIndexEnabled(tl)
&& d->isIndexEnabled(br)) {
- QRect first = rectForIndex(tl);
- QRect last = rectForIndex(br);
+ QRect first = d->cellRectForIndex(tl);
+ QRect last = d->cellRectForIndex(br);
QRect middle;
if (d->flow == LeftToRight) {
QRect &top = first;
diff --git a/src/widgets/itemviews/qlistview_p.h b/src/widgets/itemviews/qlistview_p.h
index 3f997ef7e3..c6810f8fdc 100644
--- a/src/widgets/itemviews/qlistview_p.h
+++ b/src/widgets/itemviews/qlistview_p.h
@@ -333,14 +333,31 @@ public:
inline QModelIndex listViewItemToIndex(const QListViewItem &item) const
{ return model->index(commonListView->itemIndex(item), column, root); }
+ inline bool hasRectForIndex(const QModelIndex &index) const
+ {
+ return isIndexValid(index) && index.parent() == root && index.column() == column && !isHidden(index.row());
+ }
+
QRect rectForIndex(const QModelIndex &index) const
{
- if (!isIndexValid(index) || index.parent() != root || index.column() != column || isHidden(index.row()))
+ if (!hasRectForIndex(index))
return QRect();
executePostedLayout();
return viewItemRect(indexToListViewItem(index));
}
+ QRect cellRectForIndex(const QModelIndex &index)
+ {
+ if (!hasRectForIndex(index))
+ return QRect();
+ executePostedLayout();
+ auto oldItemAlignment = itemAlignment;
+ itemAlignment = Qt::Alignment();
+ const QRect rect = rectForIndex(index);
+ itemAlignment = oldItemAlignment;
+ return rect;
+ }
+
void viewUpdateGeometries() { q_func()->updateGeometries(); }
diff --git a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp
index db5e83e2c7..13dc924f93 100644
--- a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp
+++ b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp
@@ -204,6 +204,7 @@ private slots:
void basicRawEventTranslationOfIds();
void multiPointRawEventTranslationOnTouchScreen();
void multiPointRawEventTranslationOnTouchPad();
+ void touchOnMultipleTouchscreens();
void deleteInEventHandler();
void deleteInRawEventTranslation();
void crashInQGraphicsSceneAfterNotHandlingTouchBegin();
@@ -213,11 +214,13 @@ private slots:
private:
QTouchDevice *touchScreenDevice;
+ QTouchDevice *secondaryTouchScreenDevice;
QTouchDevice *touchPadDevice;
};
tst_QTouchEvent::tst_QTouchEvent()
: touchScreenDevice(QTest::createTouchDevice())
+ , secondaryTouchScreenDevice(QTest::createTouchDevice())
, touchPadDevice(QTest::createTouchDevice(QTouchDevice::TouchPad))
{
}
@@ -225,6 +228,7 @@ tst_QTouchEvent::tst_QTouchEvent()
void tst_QTouchEvent::cleanup()
{
QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
+ QWindowSystemInterfacePrivate::clearPointIdMap();
}
void tst_QTouchEvent::qPointerUniqueId()
@@ -951,6 +955,157 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen()
}
}
+void tst_QTouchEvent::touchOnMultipleTouchscreens()
+{
+ tst_QTouchEventWidget touchWidget;
+ touchWidget.setWindowTitle(QTest::currentTestFunction());
+ touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
+ touchWidget.setGeometry(100, 100, 400, 300);
+ touchWidget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
+ QWindow *window = touchWidget.windowHandle();
+
+ QPointF pos = touchWidget.rect().center();
+ QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint());
+ QPointF delta(10, 10);
+ QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget);
+
+ QVector<QTouchEvent::TouchPoint> rawTouchPoints(3);
+ rawTouchPoints[0].setId(0);
+ rawTouchPoints[1].setId(10);
+ rawTouchPoints[2].setId(11);
+
+ // this should be translated to a TouchBegin
+ rawTouchPoints[0].setState(Qt::TouchPointPressed);
+ rawTouchPoints[0].setScreenPos(screenPos);
+ rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry));
+ rawTouchPoints[0].setRawScreenPositions({{12, 34}, {56, 78}});
+ ulong timestamp = 1234;
+ QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
+ QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
+ QWindowSystemInterface::handleTouchEvent(window, timestamp, touchScreenDevice, nativeTouchPoints);
+ QCoreApplication::processEvents();
+ QVERIFY(touchWidget.seenTouchBegin);
+ QVERIFY(!touchWidget.seenTouchUpdate);
+ QVERIFY(!touchWidget.seenTouchEnd);
+ QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
+ QCOMPARE(touchWidget.timestamp, timestamp);
+ QTouchEvent::TouchPoint touchBeginPoint = touchWidget.touchBeginPoints.first();
+ const int touchPointId = (QTouchDevicePrivate::get(touchScreenDevice)->id << 24) + 1;
+ const int secTouchPointId = (QTouchDevicePrivate::get(secondaryTouchScreenDevice)->id << 24) + 2;
+ QCOMPARE(touchBeginPoint.id(), touchPointId);
+ QCOMPARE(touchBeginPoint.state(), rawTouchPoints[0].state());
+ QCOMPARE(touchBeginPoint.pos(), pos);
+
+ // press a point on secondaryTouchScreenDevice
+ touchWidget.seenTouchBegin = false;
+ rawTouchPoints[1].setState(Qt::TouchPointPressed);
+ rawTouchPoints[1].setScreenPos(screenPos);
+ rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry));
+ rawTouchPoints[1].setRawScreenPositions({{90, 100}, {110, 120}});
+ nativeTouchPoints =
+ QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[1], window);
+ QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
+ QCoreApplication::processEvents();
+ QVERIFY(!touchWidget.seenTouchEnd);
+ QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
+ QCOMPARE(touchWidget.timestamp, timestamp);
+ touchBeginPoint = touchWidget.touchBeginPoints[0];
+ QCOMPARE(touchBeginPoint.id(), (QTouchDevicePrivate::get(secondaryTouchScreenDevice)->id << 24) + 2);
+ QCOMPARE(touchBeginPoint.state(), rawTouchPoints[1].state());
+ QCOMPARE(touchBeginPoint.pos(), pos);
+
+ // press another point on secondaryTouchScreenDevice
+ touchWidget.seenTouchBegin = false;
+ rawTouchPoints[2].setState(Qt::TouchPointPressed);
+ rawTouchPoints[2].setScreenPos(screenPos);
+ rawTouchPoints[2].setNormalizedPos(normalized(rawTouchPoints[2].pos(), screenGeometry));
+ rawTouchPoints[2].setRawScreenPositions({{130, 140}, {150, 160}});
+ nativeTouchPoints =
+ QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[2], window);
+ QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
+ QCoreApplication::processEvents();
+ QVERIFY(!touchWidget.seenTouchEnd);
+ QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
+ QCOMPARE(touchWidget.timestamp, timestamp);
+ touchBeginPoint = touchWidget.touchBeginPoints[0];
+ QCOMPARE(touchBeginPoint.id(), (QTouchDevicePrivate::get(secondaryTouchScreenDevice)->id << 24) + 3);
+ QCOMPARE(touchBeginPoint.state(), rawTouchPoints[2].state());
+ QCOMPARE(touchBeginPoint.pos(), pos);
+
+ // moving the first point should translate to TouchUpdate
+ rawTouchPoints[0].setState(Qt::TouchPointMoved);
+ rawTouchPoints[0].setScreenPos(screenPos + delta);
+ rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry));
+ nativeTouchPoints =
+ QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
+ QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
+ QCoreApplication::processEvents();
+ QVERIFY(touchWidget.seenTouchBegin);
+ QVERIFY(touchWidget.seenTouchUpdate);
+ QVERIFY(!touchWidget.seenTouchEnd);
+ QCOMPARE(touchWidget.touchUpdatePoints.count(), 1);
+ QTouchEvent::TouchPoint touchUpdatePoint = touchWidget.touchUpdatePoints.first();
+ QCOMPARE(touchUpdatePoint.id(), touchPointId);
+ QCOMPARE(touchUpdatePoint.state(), rawTouchPoints[0].state());
+ QCOMPARE(touchUpdatePoint.pos(), pos + delta);
+
+ // releasing the first point translates to TouchEnd
+ rawTouchPoints[0].setState(Qt::TouchPointReleased);
+ rawTouchPoints[0].setScreenPos(screenPos + delta + delta);
+ rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry));
+ nativeTouchPoints =
+ QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
+ QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
+ QCoreApplication::processEvents();
+ QVERIFY(touchWidget.seenTouchBegin);
+ QVERIFY(touchWidget.seenTouchUpdate);
+ QVERIFY(touchWidget.seenTouchEnd);
+ QCOMPARE(touchWidget.touchEndPoints.count(), 1);
+ QTouchEvent::TouchPoint touchEndPoint = touchWidget.touchEndPoints.first();
+ QCOMPARE(touchEndPoint.id(), touchPointId);
+ QCOMPARE(touchEndPoint.state(), rawTouchPoints[0].state());
+ QCOMPARE(touchEndPoint.pos(), pos + delta + delta);
+
+ // Widgets don't normally handle this case: if a TouchEnd was seen before, then
+ // WA_WState_AcceptedTouchBeginEvent will be false, and
+ // QApplicationPrivate::translateRawTouchEvent will ignore touch events that aren't TouchBegin.
+ // So we have to set it true. It _did_ in fact accept the touch begin from the secondary device,
+ // but it also got a TouchEnd from the primary device in the meantime.
+ touchWidget.setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, true);
+
+ // Releasing one point on the secondary touchscreen does not yet generate TouchEnd.
+ touchWidget.seenTouchEnd = false;
+ touchWidget.touchEndPoints.clear();
+ rawTouchPoints[1].setState(Qt::TouchPointReleased);
+ rawTouchPoints[2].setState(Qt::TouchPointStationary);
+ nativeTouchPoints =
+ QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[1] << rawTouchPoints[2], window);
+ QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
+ QCoreApplication::processEvents();
+ QVERIFY(touchWidget.seenTouchBegin);
+ QVERIFY(touchWidget.seenTouchUpdate);
+ QVERIFY(!touchWidget.seenTouchEnd);
+ QCOMPARE(touchWidget.touchUpdatePoints.count(), 2);
+ QCOMPARE(touchWidget.touchUpdatePoints[0].id(), secTouchPointId);
+ QCOMPARE(touchWidget.touchUpdatePoints[1].id(), secTouchPointId + 1);
+
+ // releasing the last point on the secondary touchscreen translates to TouchEnd
+ touchWidget.seenTouchEnd = false;
+ rawTouchPoints[2].setState(Qt::TouchPointReleased);
+ nativeTouchPoints =
+ QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[2], window);
+ QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
+ QCoreApplication::processEvents();
+ QVERIFY(touchWidget.seenTouchBegin);
+ QVERIFY(touchWidget.seenTouchUpdate);
+ QVERIFY(touchWidget.seenTouchEnd);
+ QCOMPARE(touchWidget.touchEndPoints.count(), 1);
+ touchEndPoint = touchWidget.touchEndPoints.first();
+ QCOMPARE(touchEndPoint.id(), secTouchPointId + 1);
+ QCOMPARE(touchEndPoint.state(), rawTouchPoints[2].state());
+}
+
void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
{
tst_QTouchEventWidget touchWidget;
diff --git a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
index e1d527b398..0b828b8484 100644
--- a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
+++ b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp
@@ -121,6 +121,7 @@ private slots:
void task254449_draggingItemToNegativeCoordinates();
void keyboardSearch();
void shiftSelectionWithNonUniformItemSizes();
+ void shiftSelectionWithItemAlignment();
void clickOnViewportClearsSelection();
void task262152_setModelColumnNavigate();
void taskQTBUG_2233_scrollHiddenItems_data();
@@ -1802,6 +1803,51 @@ void tst_QListView::shiftSelectionWithNonUniformItemSizes()
}
}
+void tst_QListView::shiftSelectionWithItemAlignment()
+{
+ QStringList items;
+ for (int c = 0; c < 2; c++) {
+ for (int i = 10; i > 0; i--)
+ items << QString(i, QLatin1Char('*'));
+
+ for (int i = 1; i < 11; i++)
+ items << QString(i, QLatin1Char('*'));
+ }
+
+ QListView view;
+ view.setFlow(QListView::TopToBottom);
+ view.setWrapping(true);
+ view.setItemAlignment(Qt::AlignLeft);
+ view.setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ QStringListModel model(items);
+ view.setModel(&model);
+
+ QFont font = view.font();
+ font.setPixelSize(10);
+ view.setFont(font);
+ view.resize(300, view.sizeHintForRow(0) * items.size() / 2 + view.horizontalScrollBar()->height());
+
+ view.show();
+ QApplication::setActiveWindow(&view);
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QCOMPARE(static_cast<QWidget *>(&view), QApplication::activeWindow());
+
+ QModelIndex index1 = view.model()->index(items.size() / 4, 0);
+ QPoint p = view.visualRect(index1).center();
+ QVERIFY(view.viewport()->rect().contains(p));
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p);
+ QCOMPARE(view.currentIndex(), index1);
+ QCOMPARE(view.selectionModel()->selectedIndexes().size(), 1);
+
+ QModelIndex index2 = view.model()->index(items.size() / 4 * 3, 0);
+ p = view.visualRect(index2).center();
+ QVERIFY(view.viewport()->rect().contains(p));
+ QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, p);
+ QCOMPARE(view.currentIndex(), index2);
+ QCOMPARE(view.selectionModel()->selectedIndexes().size(), index2.row() - index1.row() + 1);
+}
+
void tst_QListView::clickOnViewportClearsSelection()
{
QStringList items;
diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
index ae968d34dd..c31de2ba22 100644
--- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
+++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp
@@ -200,6 +200,7 @@ private slots:
void taskQTBUG_45697_crash();
void taskQTBUG_7232_AllowUserToControlSingleStep();
void taskQTBUG_8376();
+ void taskQTBUG_61476();
void testInitialFocus();
};
@@ -4806,5 +4807,58 @@ void tst_QTreeView::taskQTBUG_8376()
QCOMPARE(rowHeightLvl1Visible, rowHeightLvl1Visible2);
}
+void tst_QTreeView::taskQTBUG_61476()
+{
+ // This checks that if a user clicks on an item to collapse it that it
+ // does not edit (in this case change the check state) the item that is
+ // now over the mouse just because it got a release event
+ QTreeView tv;
+ QStandardItemModel model;
+ QStandardItem *lastTopLevel = nullptr;
+ {
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QLatin1String("Row Item"));
+ item->setCheckable(true);
+ item->setCheckState(Qt::Checked);
+ model.appendRow(item);
+ lastTopLevel = item;
+ for (int j = 0; j < 2; ++j) {
+ QStandardItem *childItem = new QStandardItem(QLatin1String("Child row Item"));
+ childItem->setCheckable(true);
+ childItem->setCheckState(Qt::Checked);
+ item->appendRow(childItem);
+ QStandardItem *grandChild = new QStandardItem(QLatin1String("Grand child row Item"));
+ grandChild->setCheckable(true);
+ grandChild->setCheckState(Qt::Checked);
+ childItem->appendRow(grandChild);
+ }
+ }
+ }
+ tv.setModel(&model);
+ tv.expandAll();
+ // We need it to be this size so that the effect of the collapsing will
+ // cause the parent item to move to be under the cursor
+ tv.resize(200, 200);
+ tv.show();
+ QVERIFY(QTest::qWaitForWindowActive(&tv));
+ tv.verticalScrollBar()->setValue(tv.verticalScrollBar()->maximum());
+
+ // We want to press specifically right around where a checkbox for the
+ // parent item could be when collapsing
+ QTreeViewPrivate *priv = static_cast<QTreeViewPrivate*>(qt_widget_private(&tv));
+ const QModelIndex mi = lastTopLevel->child(0)->index();
+ const QRect rect = priv->itemDecorationRect(mi);
+ const QPoint pos = rect.center();
+
+ QTest::mousePress(tv.viewport(), Qt::LeftButton, 0, pos);
+ if (tv.style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, 0, &tv) ==
+ QEvent::MouseButtonPress)
+ QTRY_VERIFY(!tv.isExpanded(mi));
+
+ QTest::mouseRelease(tv.viewport(), Qt::LeftButton, 0, pos);
+ QTRY_VERIFY(!tv.isExpanded(mi));
+ QCOMPARE(lastTopLevel->checkState(), Qt::Checked);
+}
+
QTEST_MAIN(tst_QTreeView)
#include "tst_qtreeview.moc"