Merge "Merge remote-tracking branch 'origin/5.12' into 5.13" into refs/staging/5.13

This commit is contained in:
Qt Forward Merge Bot 2019-02-28 00:00:37 +00:00 committed by The Qt Project
commit 55b4641962
24 changed files with 375 additions and 41 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -448,7 +448,7 @@
],
"sources": [
{ "type": "pkgConfig", "args": "gl", "condition": "!config.darwin" },
{ "type": "makeSpec", "spec": "OPENGL" }
{ "type": "openglMakeSpec" }
]
},
"opengl_es2": {

View File

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

View File

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

View File

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

View File

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

View File

@ -62,9 +62,6 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
QEglFSScreen::~QEglFSScreen()
{
delete m_cursor;
#ifndef QT_NO_OPENGL
QOpenGLCompositor::destroy();
#endif
}
QRect QEglFSScreen::geometry() const

View File

@ -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();
#ifndef QT_NO_OPENGL
QOpenGLCompositor::destroy();
delete m_rasterCompositingContext;
#endif
}
m_flags = 0;
#ifndef QT_NO_OPENGL
QOpenGLCompositor::instance()->removeWindow(this);
#endif
}
void QEglFSWindow::invalidateSurface()

View File

@ -116,6 +116,7 @@ public:
protected:
#ifndef QT_NO_OPENGL
QOpenGLCompositorBackingStore *m_backingStore;
QOpenGLContext *m_rasterCompositingContext;
#endif
bool m_raster;
WId m_winId;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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