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
This commit is contained in:
Liang Qi 2016-04-27 09:18:05 +02:00
commit 23a36fd2bf
29 changed files with 337 additions and 93 deletions

View File

@ -53,6 +53,15 @@
int main(int argc, char **argv)
{
for (int i = 1; i < argc; ++i) {
if (!qstrcmp(argv[i], "-g"))
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
else if (!qstrcmp(argv[i], "-s"))
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
else if (!qstrcmp(argv[i], "-d"))
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
}
QApplication app(argc, argv);
Widget w;

View File

@ -60,10 +60,12 @@
#include <QPushButton>
#include <QTextEdit>
#include <QSplitter>
#include <QGuiApplication>
#include <QSurfaceFormat>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QDebug>
#include <QTextStream>
struct Version {
const char *str;
@ -235,6 +237,24 @@ Widget::Widget(QWidget *parent)
m_renderWindowContainer = new QWidget;
addRenderWindow();
QString description;
QTextStream str(&description);
str << "Qt " << QT_VERSION_STR << ' ' << QGuiApplication::platformName();
const char *openGlVariables[] =
{"QT_ANGLE_PLATFORM", "QT_OPENGL", "QT_OPENGL_BUGLIST", "QT_OPENGL_DLL"};
const size_t variableCount = sizeof(openGlVariables) / sizeof(openGlVariables[0]);
for (size_t v = 0; v < variableCount; ++v) {
if (qEnvironmentVariableIsSet(openGlVariables[v]))
str << ' ' << openGlVariables[v] << '=' << qgetenv(openGlVariables[v]);
}
if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES))
str << " Qt::AA_UseOpenGLES";
if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL))
str << " Qt::AA_UseSoftwareOpenGL";
if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL))
str << " Qt::AA_UseSoftwareOpenGL";
layout->addWidget(new QLabel(description));
setLayout(layout);
}

View File

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

View File

@ -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;
return *worksPtr;
const bool val = QLockFilePrivate::checkFcntlWorksAfterFlock(fn);
worksPtr = new bool(val);
fcntlOK->insert(fn, worksPtr);
return val;
}
static bool setNativeLocks(const QString &fileName, int fd)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2181,7 +2181,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
}
do {
if (state() != ConnectedState)
if (state() != ConnectedState && state() != BoundState)
return false;
bool readyToRead = false;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{
return (mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL;
/* 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 ignoreEnterEvent(quint8 mode, quint8 detail)
static bool ignoreLeaveEvent(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_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);
}
static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
{
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);
}

View File

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

View File

@ -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;
int logicalLeft = max;
int logicalRight = 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
// 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->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;
int logicalTop = max;
int logicalBottom = 0;
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;
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);
}
int logicalTop = logicalIndex(top);
int logicalBottom = logicalIndex(bottom);
if (logicalTop == -1 || logicalBottom == -1)
return QRect();
if (logicalTop < 0 || logicalTop >= count() ||
logicalBottom < 0 || logicalBottom >= count())
return QRegion();
int topPos = sectionViewportPosition(logicalTop);
int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);

View File

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

View File

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

View File

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

View File

@ -513,6 +513,8 @@ void tst_QMimeDatabase::mimeTypeForUrl()
QVERIFY(db.mimeTypeForUrl(QUrl::fromEncoded("http://foo/bar.png")).isDefault()); // HTTP can't know before downloading
QCOMPARE(db.mimeTypeForUrl(QUrl::fromEncoded("ftp://foo/bar.png")).name(), QString::fromLatin1("image/png"));
QCOMPARE(db.mimeTypeForUrl(QUrl::fromEncoded("ftp://foo/bar")).name(), QString::fromLatin1("application/octet-stream")); // unknown extension
QCOMPARE(db.mimeTypeForUrl(QUrl("mailto:something@example.com")).name(), QString::fromLatin1("application/octet-stream")); // unknown
QCOMPARE(db.mimeTypeForUrl(QUrl("mailto:something@polish.pl")).name(), QString::fromLatin1("application/octet-stream")); // unknown, NOT perl ;)
}
void tst_QMimeDatabase::mimeTypeForData_data()

View File

@ -29,9 +29,16 @@
#include <QtCore>
#include <QtNetwork>
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC)
# include <crtdbg.h>
#endif
int main(int argc, char *argv[])
{
// Windows: Suppress crash notification dialog.
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC)
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
#endif
QCoreApplication app(argc, argv);
QTcpServer server;

View File

@ -693,6 +693,7 @@ void tst_QFileSystemModel::nameFilters()
}
void tst_QFileSystemModel::setData_data()
{
QTest::addColumn<QString>("subdirName");
QTest::addColumn<QStringList>("files");
QTest::addColumn<QString>("oldFileName");
QTest::addColumn<QString>("newFileName");
@ -702,7 +703,15 @@ void tst_QFileSystemModel::setData_data()
<< QDir::temp().absolutePath() + '/' + "a"
<< false;
*/
QTest::newRow("in current dir") << (QStringList() << "a" << "b" << "c")
QTest::newRow("in current dir")
<< QString()
<< (QStringList() << "a" << "b" << "c")
<< "a"
<< "d"
<< true;
QTest::newRow("in subdir")
<< "s"
<< (QStringList() << "a" << "b" << "c")
<< "a"
<< "d"
<< true;
@ -711,15 +720,25 @@ void tst_QFileSystemModel::setData_data()
void tst_QFileSystemModel::setData()
{
QSignalSpy spy(model, SIGNAL(fileRenamed(QString,QString,QString)));
QString tmp = flatDirTestPath;
QFETCH(QString, subdirName);
QFETCH(QStringList, files);
QFETCH(QString, oldFileName);
QFETCH(QString, newFileName);
QFETCH(bool, success);
QString tmp = flatDirTestPath;
if (!subdirName.isEmpty()) {
QDir dir(tmp);
QVERIFY(dir.mkdir(subdirName));
tmp.append('/' + subdirName);
}
QVERIFY(createFiles(tmp, files));
QModelIndex root = model->setRootPath(tmp);
QTRY_COMPARE(model->rowCount(root), files.count());
QModelIndex tmpIdx = model->setRootPath(flatDirTestPath);
if (!subdirName.isEmpty()) {
tmpIdx = model->index(tmp);
model->fetchMore(tmpIdx);
}
QTRY_COMPARE(model->rowCount(tmpIdx), files.count());
QModelIndex idx = model->index(tmp + '/' + oldFileName);
QCOMPARE(idx.isValid(), true);
@ -727,16 +746,21 @@ void tst_QFileSystemModel::setData()
model->setReadOnly(false);
QCOMPARE(model->setData(idx, newFileName), success);
model->setReadOnly(true);
if (success) {
QCOMPARE(spy.count(), 1);
QList<QVariant> arguments = spy.takeFirst();
QCOMPARE(model->data(idx, QFileSystemModel::FileNameRole).toString(), newFileName);
QCOMPARE(model->fileInfo(idx).filePath(), tmp + '/' + newFileName);
QCOMPARE(model->index(arguments.at(0).toString()), model->index(tmp));
QCOMPARE(arguments.at(1).toString(), oldFileName);
QCOMPARE(arguments.at(2).toString(), newFileName);
QCOMPARE(QFile::rename(tmp + '/' + newFileName, tmp + '/' + oldFileName), true);
}
QTRY_COMPARE(model->rowCount(root), files.count());
QTRY_COMPARE(model->rowCount(tmpIdx), files.count());
// cleanup
if (!subdirName.isEmpty())
QVERIFY(QDir(tmp).removeRecursively());
}
void tst_QFileSystemModel::sortPersistentIndex()

View File

@ -73,6 +73,7 @@ public:
void testEvent();
void testhorizontalOffset();
void testverticalOffset();
void testVisualRegionForSelection();
friend class tst_QHeaderView;
};
@ -204,6 +205,7 @@ private slots:
void QTBUG8650_crashOnInsertSections();
void QTBUG12268_hiddenMovedSectionSorting();
void QTBUG14242_hideSectionAutoSize();
void QTBUG50171_visualRegionForSwappedItems();
void ensureNoIndexAtLength();
void offsetConsistent();
@ -2281,6 +2283,24 @@ void tst_QHeaderView::QTBUG14242_hideSectionAutoSize()
QCOMPARE(calced_length, afterlength);
}
void tst_QHeaderView::QTBUG50171_visualRegionForSwappedItems()
{
protected_QHeaderView headerView(Qt::Horizontal);
QtTestModel model;
model.rows = 2;
model.cols = 3;
headerView.setModel(&model);
headerView.swapSections(1, 2);
headerView.hideSection(0);
headerView.testVisualRegionForSelection();
}
void protected_QHeaderView::testVisualRegionForSelection()
{
QRegion r = visualRegionForSelection(QItemSelection(model()->index(1, 0), model()->index(1, 2)));
QCOMPARE(r.boundingRect().contains(QRect(1, 1, length() - 2, 1)), true);
}
void tst_QHeaderView::ensureNoIndexAtLength()
{
QTableView qtv;

View File

@ -3030,8 +3030,23 @@ protected:
QSize sizeHint() const { return QSize(500, 500); }
};
// Scale to remove devicePixelRatio should scaling be active.
static QPixmap grabFromWidget(QWidget *w, const QRect &rect)
{
QPixmap pixmap = w->grab(rect);
const qreal devicePixelRatio = pixmap.devicePixelRatioF();
if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
pixmap = pixmap.scaled((QSizeF(pixmap.size()) / devicePixelRatio).toSize(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
pixmap.setDevicePixelRatio(1);
}
return pixmap;
}
void tst_QWidget::testContentsPropagation()
{
if (!qFuzzyCompare(qApp->devicePixelRatio(), qreal(1)))
QSKIP("This test does not work with scaling.");
ContentsPropagationWidget widget;
widget.setFixedSize(500, 500);
widget.setContentsPropagation(false);
@ -9203,7 +9218,7 @@ void tst_QWidget::rectOutsideCoordinatesLimit_task144779()
QPixmap correct(main.size());
correct.fill(Qt::green);
const QPixmap mainPixmap = main.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
const QPixmap mainPixmap = grabFromWidget(&main, QRect(QPoint(0, 0), QSize(-1, -1)));
QTRY_COMPARE(mainPixmap.toImage().convertToFormat(QImage::Format_RGB32),
correct.toImage().convertToFormat(QImage::Format_RGB32));
@ -9667,10 +9682,10 @@ void tst_QWidget::grab()
p.drawTiledPixmap(0, 0, 128, 128, pal.brush(QPalette::Window).texture(), 0, 0);
p.end();
QPixmap actual = widget.grab(QRect(64, 64, 64, 64));
QPixmap actual = grabFromWidget(&widget, QRect(64, 64, 64, 64));
QVERIFY(lenientCompare(actual, expected));
actual = widget.grab(QRect(64, 64, -1, -1));
actual = grabFromWidget(&widget, QRect(64, 64, -1, -1));
QVERIFY(lenientCompare(actual, expected));
// Make sure a widget that is not yet shown is grabbed correctly.