diff options
author | Liang Qi <liang.qi@qt.io> | 2016-04-27 09:18:05 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-04-27 09:18:05 +0200 |
commit | 23a36fd2bfcdb57849deaa1e10e6e3f7b1156ed8 (patch) | |
tree | b527c7e3ba4a831b542b0bccfb6a5a748a8a4fd9 /src | |
parent | c003a18ee332abf2387172eb0856a176a32a6c8f (diff) | |
parent | 072f5b513e486e884ea7fa4a1cac9aedf3846374 (diff) |
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts:
src/corelib/io/qprocess_win.cpp
src/widgets/itemviews/qheaderview.cpp
Change-Id: I0a59ade9cd6e91f770fdf298a7d72a41e79fd761
Diffstat (limited to 'src')
22 files changed, 235 insertions, 88 deletions
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index de37731b1a..4851d1ce6f 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -988,15 +988,18 @@ struct QMessagePattern { #endif #ifdef QLOGGING_HAVE_BACKTRACE struct BacktraceParams { - QString backtraceSeparator; - int backtraceDepth; + QString backtraceSeparator; + int backtraceDepth; }; - QList<BacktraceParams> backtraceArgs; // backtrace argumens in sequence of %{backtrace + QVector<BacktraceParams> backtraceArgs; // backtrace argumens in sequence of %{backtrace #endif bool fromEnvironment; static QBasicMutex mutex; }; +#ifdef QLOGGING_HAVE_BACKTRACE +Q_DECLARE_TYPEINFO(QMessagePattern::BacktraceParams, Q_MOVABLE_TYPE); +#endif QBasicMutex QMessagePattern::mutex; diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index 7255414bdc..03dc5fc660 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -151,12 +151,14 @@ static bool fcntlWorksAfterFlock(const QString &fn) if (fcntlOK.isDestroyed()) return QLockFilePrivate::checkFcntlWorksAfterFlock(fn); bool *worksPtr = fcntlOK->object(fn); - if (!worksPtr) { - worksPtr = new bool(QLockFilePrivate::checkFcntlWorksAfterFlock(fn)); - fcntlOK->insert(fn, worksPtr); - } + if (worksPtr) + return *worksPtr; + + const bool val = QLockFilePrivate::checkFcntlWorksAfterFlock(fn); + worksPtr = new bool(val); + fcntlOK->insert(fn, worksPtr); - return *worksPtr; + return val; } static bool setNativeLocks(const QString &fileName, int fd) diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index 818772a399..eaebbc1ffc 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -365,9 +365,6 @@ void QLoggingRegistry::setApiRules(const QString &content) */ void QLoggingRegistry::updateRules() { - if (categoryFilter != defaultCategoryFilter) - return; - rules = qtConfigRules + configRules + apiRules + envRules; for (auto it = categories.keyBegin(), end = categories.keyEnd(); it != end; ++it) diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 5d8b567c8c..ed540f9e5b 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -49,6 +49,7 @@ #include <qfileinfo.h> #include <qregexp.h> #include <qwineventnotifier.h> +#include <private/qsystemlibrary_p.h> #include <private/qthread_p.h> #include <qdebug.h> @@ -817,8 +818,45 @@ qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) return stdinChannel.writer->write(data, maxlen); } +// Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails +// with ERROR_ELEVATION_REQUIRED. +static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments, + const QString &workingDir, qint64 *pid) +{ + typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *); + + static const ShellExecuteExType shellExecuteEx = // XP ServicePack 1 onwards. + reinterpret_cast<ShellExecuteExType>(QSystemLibrary::resolve(QLatin1String("shell32"), + "ShellExecuteExW")); + if (!shellExecuteEx) + return false; + + const QString args = qt_create_commandline(QString(), arguments); // needs arguments only + SHELLEXECUTEINFOW shellExecuteExInfo; + memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW)); + shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW); + shellExecuteExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI; + shellExecuteExInfo.lpVerb = L"runas"; + const QString program = QDir::toNativeSeparators(programIn); + shellExecuteExInfo.lpFile = reinterpret_cast<LPCWSTR>(program.utf16()); + if (!args.isEmpty()) + shellExecuteExInfo.lpParameters = reinterpret_cast<LPCWSTR>(args.utf16()); + if (!workingDir.isEmpty()) + shellExecuteExInfo.lpDirectory = reinterpret_cast<LPCWSTR>(workingDir.utf16()); + shellExecuteExInfo.nShow = SW_SHOWNORMAL; + + if (!shellExecuteEx(&shellExecuteExInfo)) + return false; + if (pid) + *pid = qint64(GetProcessId(shellExecuteExInfo.hProcess)); + CloseHandle(shellExecuteExInfo.hProcess); + return true; +} + bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) { + static const DWORD errorElevationRequired = 740; + QString args = qt_create_commandline(program, arguments); bool success = false; PROCESS_INFORMATION pinfo; @@ -838,6 +876,8 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a CloseHandle(pinfo.hProcess); if (pid) *pid = pinfo.dwProcessId; + } else if (GetLastError() == errorElevationRequired) { + success = startDetachedUacPrompt(program, arguments, workingDir, pid); } return success; diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index bff6a9ac15..d866d3bcf7 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -520,7 +520,7 @@ QMimeType QMimeDatabase::mimeTypeForUrl(const QUrl &url) const return mimeTypeForFile(url.toLocalFile()); const QString scheme = url.scheme(); - if (scheme.startsWith(QLatin1String("http"))) + if (scheme.startsWith(QLatin1String("http")) || scheme == QLatin1String("mailto")) return mimeTypeForName(d->defaultMimeType()); return mimeTypeForFile(url.path()); diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 9bfc46f32e..c3aae2fd22 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -10092,6 +10092,9 @@ static inline int qt_find_latin1_string(const QChar *haystack, int size, QLatin1String needle, int from, Qt::CaseSensitivity cs) { + if (size < needle.size()) + return -1; + const char *latin1 = needle.latin1(); int len = needle.size(); QVarLengthArray<ushort> s(len); diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h index 296918961f..ca0a2cde13 100644 --- a/src/dbus/qdbusargument_p.h +++ b/src/dbus/qdbusargument_p.h @@ -72,7 +72,7 @@ public: inline QDBusArgumentPrivate(int flags = 0) : message(0), ref(1), capabilities(flags) { } - ~QDBusArgumentPrivate(); + virtual ~QDBusArgumentPrivate(); static bool checkRead(QDBusArgumentPrivate *d); static bool checkReadAndDetach(QDBusArgumentPrivate *&d); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 935c17dfc1..c6173791a6 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1956,7 +1956,7 @@ void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected() void QNetworkReplyHttpImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState) { if (sessionState == QNetworkSession::Disconnected - && (state != Idle || state != Reconnecting)) { + && state != Idle && state != Reconnecting) { error(QNetworkReplyImpl::NetworkSessionFailedError, QCoreApplication::translate("QNetworkReply", "Network session error.")); finished(); diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 59a0cd8ddc..d69d5983cb 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -325,7 +325,7 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected() void QNetworkReplyImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState) { if (sessionState == QNetworkSession::Disconnected - && (state != Idle || state != Reconnecting)) { + && state != Idle && state != Reconnecting) { error(QNetworkReplyImpl::NetworkSessionFailedError, QCoreApplication::translate("QNetworkReply", "Network session error.")); finished(); diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index a874c1b43f..7bf9a6de7a 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -2181,7 +2181,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs) } do { - if (state() != ConnectedState) + if (state() != ConnectedState && state() != BoundState) return false; bool readyToRead = false; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 4d2af84e8e..4d5f5d74f2 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -72,6 +72,7 @@ typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow; QCocoaWindow *_platformWindow; BOOL _grabbingMouse; BOOL _releaseOnMouseUp; + QPointer<QObject> _watcher; } @property (nonatomic, readonly) QCocoaNSWindow *window; @@ -321,6 +322,11 @@ public: // for QNSView }; QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false) + + // This object is tracked by a 'watcher' + // object in a window helper, preventing use of dangling + // pointers. + QObject sentinel; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 29cc4130ed..01e72303be 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -99,6 +99,7 @@ static bool isMouseEvent(NSEvent *ev) // make sure that m_nsWindow stays valid until the // QCocoaWindow is deleted by Qt. [_window setReleasedWhenClosed:NO]; + _watcher = &_platformWindow->sentinel; } return self; @@ -107,7 +108,7 @@ static bool isMouseEvent(NSEvent *ev) - (void)handleWindowEvent:(NSEvent *)theEvent { QCocoaWindow *pw = self.platformWindow; - if (pw && pw->m_forwardWindow) { + if (_watcher && pw && pw->m_forwardWindow) { if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) { QNSView *forwardView = pw->m_qtView; if (theEvent.type == NSLeftMouseUp) { @@ -146,7 +147,7 @@ static bool isMouseEvent(NSEvent *ev) if (!self.window.delegate) return; // Already detached, pending NSAppKitDefined event - if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { + if (_watcher && pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { NSPoint loc = [theEvent locationInWindow]; NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]]; NSRect contentFrame = [[self.window contentView] frame]; @@ -162,6 +163,7 @@ static bool isMouseEvent(NSEvent *ev) - (void)detachFromPlatformWindow { _platformWindow = 0; + _watcher.clear(); [self.window.delegate release]; self.window.delegate = nil; } diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 9486dd84f0..b524adb2cb 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -374,13 +374,11 @@ QWindowsWindow *QWindowsIntegration::createPlatformWindowHelper(QWindow *window, QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate() { #if defined(QT_OPENGL_DYNAMIC) - const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers(); - QWindowsOpenGLTester::Renderer requestedRenderer = QWindowsOpenGLTester::requestedRenderer(); switch (requestedRenderer) { case QWindowsOpenGLTester::DesktopGl: if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) { - if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag) + if ((QWindowsOpenGLTester::supportedRenderers() & QWindowsOpenGLTester::DisableRotationFlag) && !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) { qCWarning(lcQpaGl, "Unable to disable rotation."); } @@ -406,6 +404,7 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate() break; } + const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers(); if (supportedRenderers & QWindowsOpenGLTester::DesktopGl) { if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) { if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag) diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index aec09a260b..f3667aaa0d 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1135,6 +1135,8 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args return S_OK; } + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); + // Activate topWindow if (!d->visibleWindows.isEmpty()) { Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 2e51576e3b..5ad349fdc2 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -567,6 +567,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra , m_buttons(0) , m_focusWindow(0) , m_mouseGrabber(0) + , m_mousePressWindow(0) , m_clientLeader(0) , m_systemTrayTracker(0) , m_glIntegration(Q_NULLPTR) @@ -1379,6 +1380,11 @@ void QXcbConnection::setFocusWindow(QXcbWindow *w) void QXcbConnection::setMouseGrabber(QXcbWindow *w) { m_mouseGrabber = w; + m_mousePressWindow = Q_NULLPTR; +} +void QXcbConnection::setMousePressWindow(QXcbWindow *w) +{ + m_mousePressWindow = w; } void QXcbConnection::grabServer() diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index e8af82ec8c..68d7b5622f 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -481,6 +481,8 @@ public: void setFocusWindow(QXcbWindow *); QXcbWindow *mouseGrabber() const { return m_mouseGrabber; } void setMouseGrabber(QXcbWindow *); + QXcbWindow *mousePressWindow() const { return m_mousePressWindow; } + void setMousePressWindow(QXcbWindow *); QByteArray startupId() const { return m_startupId; } void setStartupId(const QByteArray &nextId) { m_startupId = nextId; } @@ -668,6 +670,7 @@ private: QXcbWindow *m_focusWindow; QXcbWindow *m_mouseGrabber; + QXcbWindow *m_mousePressWindow; xcb_window_t m_clientLeader; QByteArray m_startupId; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5e4aaa37d9..c507ac09b6 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -592,8 +592,12 @@ QXcbWindow::~QXcbWindow() { if (window()->type() != Qt::ForeignWindow) destroy(); - else if (connection()->mouseGrabber() == this) - connection()->setMouseGrabber(Q_NULLPTR); + else { + if (connection()->mouseGrabber() == this) + connection()->setMouseGrabber(Q_NULLPTR); + if (connection()->mousePressWindow() == this) + connection()->setMousePressWindow(Q_NULLPTR); + } } void QXcbWindow::destroy() @@ -851,6 +855,16 @@ void QXcbWindow::hide() if (connection()->mouseGrabber() == this) connection()->setMouseGrabber(Q_NULLPTR); + if (QPlatformWindow *w = connection()->mousePressWindow()) { + // Unset mousePressWindow when it (or one of its parents) is unmapped + while (w) { + if (w == this) { + connection()->setMousePressWindow(Q_NULLPTR); + break; + } + w = w->parent(); + } + } m_mapped = false; @@ -2199,6 +2213,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in return; } + connection()->setMousePressWindow(this); + handleMouseEvent(timestamp, local, global, modifiers, source); } @@ -2213,19 +2229,44 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, return; } + if (connection()->buttons() == Qt::NoButton) + connection()->setMousePressWindow(Q_NULLPTR); + handleMouseEvent(timestamp, local, global, modifiers, source); } -static bool ignoreLeaveEvent(quint8 mode, quint8 detail) +static inline bool doCheckUnGrabAncestor(QXcbConnection *conn) +{ + /* Checking for XCB_NOTIFY_MODE_GRAB and XCB_NOTIFY_DETAIL_ANCESTOR prevents unwanted + * enter/leave events on AwesomeWM on mouse button press. It also ignores duplicated + * enter/leave events on Alt+Tab switching on some WMs with XInput2 events. + * Without XInput2 events the (Un)grabAncestor cannot be checked when mouse button is + * not pressed, otherwise (e.g. on Alt+Tab) it can igonre important enter/leave events. + */ + if (conn) { + const bool mouseButtonsPressed = (conn->buttons() != Qt::NoButton); +#ifdef XCB_USE_XINPUT22 + return mouseButtonsPressed || (conn->isAtLeastXI22() && conn->xi2MouseEvents()); +#else + return mouseButtonsPressed; +#endif + } + return true; +} + +static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR) { - return (mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM + return ((doCheckUnGrabAncestor(conn) + && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) + || (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR) || detail == XCB_NOTIFY_DETAIL_VIRTUAL - || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL; + || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); } -static bool ignoreEnterEvent(quint8 mode, quint8 detail) +static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR) { - return ((mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM + return ((doCheckUnGrabAncestor(conn) + && mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) || (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB) || detail == XCB_NOTIFY_DETAIL_VIRTUAL || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); @@ -2259,9 +2300,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in const QPoint global = QPoint(root_x, root_y); - if (ignoreEnterEvent(mode, detail) - || (connection()->buttons() != Qt::NoButton - && QGuiApplicationPrivate::lastCursorPosition != global)) + if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; const QPoint local(event_x, event_y); @@ -2273,11 +2312,7 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, { connection()->setTime(timestamp); - const QPoint global(root_x, root_y); - - if (ignoreLeaveEvent(mode, detail) - || (connection()->buttons() != Qt::NoButton - && QGuiApplicationPrivate::lastCursorPosition != global)) + if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; EnterEventChecker checker; @@ -2300,6 +2335,11 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i { QPoint local(event_x, event_y); QPoint global(root_x, root_y); + + // "mousePressWindow" can be NULL i.e. if a window will be grabbed or umnapped, so set it again here + if (connection()->buttons() != Qt::NoButton && connection()->mousePressWindow() == Q_NULLPTR) + connection()->setMousePressWindow(this); + handleMouseEvent(timestamp, local, global, modifiers, source); } diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index c72761f2ae..f639be809c 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -867,9 +867,11 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in if (newName == idx.data().toString()) return true; + const QString parentPath = filePath(parent(idx)); + if (newName.isEmpty() || QDir::toNativeSeparators(newName).contains(QDir::separator()) - || !QDir(filePath(parent(idx))).rename(oldName, newName)) { + || !QDir(parentPath).rename(oldName, newName)) { #ifndef QT_NO_MESSAGEBOX QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"), QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.") @@ -896,7 +898,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in parentNode->visibleChildren.removeAt(visibleLocation); QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName); parentNode->children[newName] = oldValue; - QFileInfo info(d->rootDir, newName); + QFileInfo info(parentPath, newName); oldValue->fileName = newName; oldValue->parent = parentNode; #ifndef QT_NO_FILESYSTEMWATCHER @@ -908,7 +910,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in parentNode->visibleChildren.insert(visibleLocation, newName); d->delayedSort(); - emit fileRenamed(filePath(idx.parent()), oldName, newName); + emit fileRenamed(parentPath, oldName, newName); } return true; } diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 9306b20043..7b393463a6 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -3013,30 +3013,41 @@ QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) c { Q_D(const QHeaderView); const int max = d->modelSectionCount(); - if (d->orientation == Qt::Horizontal) { - int left = max; - int right = 0; - int rangeLeft, rangeRight; - for (const auto &r : selection) { - if (r.parent().isValid() || !r.isValid()) - continue; // we only know about toplevel items and we don't want invalid ranges - // FIXME an item inside the range may be the leftmost or rightmost - rangeLeft = visualIndex(r.left()); - if (rangeLeft == -1) // in some cases users may change the selections - continue; // before we have a chance to do the layout - rangeRight = visualIndex(r.right()); - if (rangeRight == -1) // in some cases users may change the selections - continue; // before we have a chance to do the layout - if (rangeLeft < left) - left = rangeLeft; - if (rangeRight > right) - right = rangeRight; + if (d->orientation == Qt::Horizontal) { + int logicalLeft = max; + int logicalRight = 0; + + if (d->visualIndices.empty()) { + // If no reordered sections, skip redundant visual-to-logical transformations + for (const auto &r : selection) { + if (r.parent().isValid() || !r.isValid()) + continue; // we only know about toplevel items and we don't want invalid ranges + if (r.left() < logicalLeft) + logicalLeft = r.left(); + if (r.right() > logicalRight) + logicalRight = r.right(); + } + } else { + int left = max; + int right = 0; + for (const auto &r : selection) { + if (r.parent().isValid() || !r.isValid()) + continue; // we only know about toplevel items and we don't want invalid ranges + for (int k = r.left(); k <= r.right(); ++k) { + int visual = visualIndex(k); + if (visual == -1) // in some cases users may change the selections + continue; // before we have a chance to do the layout + if (visual < left) + left = visual; + if (visual > right) + right = visual; + } + } + logicalLeft = logicalIndex(left); + logicalRight = logicalIndex(right); } - int logicalLeft = logicalIndex(left); - int logicalRight = logicalIndex(right); - if (logicalLeft < 0 || logicalLeft >= count() || logicalRight < 0 || logicalRight >= count()) return QRegion(); @@ -3047,31 +3058,44 @@ QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) c return QRect(leftPos, 0, rightPos - leftPos, height()); } // orientation() == Qt::Vertical - int top = max; - int bottom = 0; - int rangeTop, rangeBottom; - - for (const auto &r : selection) { - if (r.parent().isValid() || !r.isValid()) - continue; // we only know about toplevel items - // FIXME an item inside the range may be the leftmost or rightmost - rangeTop = visualIndex(r.top()); - if (rangeTop == -1) // in some cases users may change the selections - continue; // before we have a chance to do the layout - rangeBottom = visualIndex(r.bottom()); - if (rangeBottom == -1) // in some cases users may change the selections - continue; // before we have a chance to do the layout - if (rangeTop < top) - top = rangeTop; - if (rangeBottom > bottom) - bottom = rangeBottom; - } - - int logicalTop = logicalIndex(top); - int logicalBottom = logicalIndex(bottom); - - if (logicalTop == -1 || logicalBottom == -1) - return QRect(); + int logicalTop = max; + int logicalBottom = 0; + + if (d->visualIndices.empty()) { + // If no reordered sections, skip redundant visual-to-logical transformations + for (const auto &r : selection) { + if (r.parent().isValid() || !r.isValid()) + continue; // we only know about toplevel items and we don't want invalid ranges + if (r.top() < logicalTop) + logicalTop = r.top(); + if (r.bottom() > logicalBottom) + logicalBottom = r.bottom(); + } + } else { + int top = max; + int bottom = 0; + + for (const auto &r : selection) { + if (r.parent().isValid() || !r.isValid()) + continue; // we only know about toplevel items and we don't want invalid ranges + for (int k = r.top(); k <= r.bottom(); ++k) { + int visual = visualIndex(k); + if (visual == -1) // in some cases users may change the selections + continue; // before we have a chance to do the layout + if (visual < top) + top = visual; + if (visual > bottom) + bottom = visual; + } + } + + logicalTop = logicalIndex(top); + logicalBottom = logicalIndex(bottom); + } + + if (logicalTop < 0 || logicalTop >= count() || + logicalBottom < 0 || logicalBottom >= count()) + return QRegion(); int topPos = sectionViewportPosition(logicalTop); int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 281567cede..5826116a96 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -5263,7 +5263,9 @@ QPixmap QWidget::grab(const QRect &rectangle) if (!r.intersects(rect())) return QPixmap(); - QPixmap res(r.size()); + const qreal dpr = devicePixelRatioF(); + QPixmap res((QSizeF(r.size()) * dpr).toSize()); + res.setDevicePixelRatio(dpr); if (!d->isOpaque) res.fill(Qt::transparent); d->render(&res, QPoint(), QRegion(r), renderFlags); diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 5b6e47e2c6..0dd3610164 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -3422,12 +3422,28 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom QSize textSize = option->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2); int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); + + const int width = textSize.width() + + (option->subControls & QStyle::SC_GroupBoxCheckBox ? indicatorWidth + 5 : 0); + rect = QRect(); + + if (option->rect.width() > width) { + switch (groupBox->textAlignment & Qt::AlignHorizontal_Mask) { + case Qt::AlignHCenter: + rect.moveLeft((option->rect.width() - width) / 2); + break; + case Qt::AlignRight: + rect.moveLeft(option->rect.width() - width); + break; + } + } + if (subControl == SC_GroupBoxCheckBox) { rect.setWidth(indicatorWidth); rect.setHeight(indicatorHeight); rect.moveTop(textSize.height() > indicatorHeight ? (textSize.height() - indicatorHeight) / 2 : 0); - rect.moveLeft(1); + rect.translate(1, 0); } else if (subControl == SC_GroupBoxLabel) { rect.setSize(textSize); rect.moveTop(1); diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index a0bc924dd9..dce0a93e10 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -1149,7 +1149,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget)) alignment |= Qt::TextHideMnemonic; - if (widget) { // Not needed for QtQuick Controls + if (widget && mbi->palette.color(QPalette::Window) != Qt::transparent) { // Not needed for QtQuick Controls //The rect adjustment is a workaround for the menu not really filling its background. XPThemeData theme(widget, painter, QWindowsXPStylePrivate::MenuTheme, |