Merge remote-tracking branch 'origin/5.6' into 5.7

Conflicts:
	src/network/access/qhttpnetworkconnection.cpp
	src/network/access/qhttpnetworkconnection_p.h

Change-Id: I11f8641ef482efa8cee1b79977d19cc3182814b4
This commit is contained in:
Liang Qi 2016-10-08 17:15:55 +02:00
commit 3e71810cf3
32 changed files with 271 additions and 116 deletions

View File

@ -110,12 +110,13 @@ void Client::readFortune()
in.setVersion(QDataStream::Qt_4_0); in.setVersion(QDataStream::Qt_4_0);
if (blockSize == 0) { if (blockSize == 0) {
if (socket->bytesAvailable() < (int)sizeof(quint16)) // Relies on the fact that QDataStream format streams a quint32 into sizeof(quint32) bytes
if (socket->bytesAvailable() < (int)sizeof(quint32))
return; return;
in >> blockSize; in >> blockSize;
} }
if (in.atEnd()) if (socket->bytesAvailable() < blockSize || in.atEnd())
return; return;
QString nextFortune; QString nextFortune;

View File

@ -86,7 +86,7 @@ private:
QLocalSocket *socket; QLocalSocket *socket;
QString currentFortune; QString currentFortune;
quint16 blockSize; quint32 blockSize;
}; };
#endif #endif

View File

@ -106,10 +106,10 @@ void Server::sendFortune()
QByteArray block; QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly); QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0); out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0; out << (quint32)0;
out << fortunes.at(qrand() % fortunes.size()); out << fortunes.at(qrand() % fortunes.size());
out.device()->seek(0); out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16)); out << (quint32)(block.size() - sizeof(quint32));
QLocalSocket *clientConnection = server->nextPendingConnection(); QLocalSocket *clientConnection = server->nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()), connect(clientConnection, SIGNAL(disconnected()),

View File

@ -3,7 +3,7 @@ MAKEFILE_GENERATOR = UNIX
QMAKE_PLATFORM = android QMAKE_PLATFORM = android
QMAKE_COMPILER = gcc clang llvm QMAKE_COMPILER = gcc clang llvm
CONFIG += android_install unversioned_soname unversioned_libname android_deployment_settings CONFIG += android_install unversioned_soname unversioned_libname plugin_with_soname android_deployment_settings
include(../common/linux.conf) include(../common/linux.conf)
include(../common/clang.conf) include(../common/clang.conf)

View File

@ -3,7 +3,7 @@ MAKEFILE_GENERATOR = UNIX
QMAKE_PLATFORM = android QMAKE_PLATFORM = android
QMAKE_COMPILER = gcc QMAKE_COMPILER = gcc
CONFIG += android_install unversioned_soname unversioned_libname android_deployment_settings CONFIG += android_install unversioned_soname unversioned_libname plugin_with_soname android_deployment_settings
include(../common/linux.conf) include(../common/linux.conf)
include(../common/gcc-base-unix.conf) include(../common/gcc-base-unix.conf)

View File

@ -87,8 +87,9 @@ have_target:!static:if(darwin|!isEmpty(QMAKE_OBJCOPY)) {
QMAKE_POST_LINK = $$mkdir_debug_info && $$copy_debug_info && $$strip_debug_info $$QMAKE_POST_LINK QMAKE_POST_LINK = $$mkdir_debug_info && $$copy_debug_info && $$strip_debug_info $$QMAKE_POST_LINK
} else { } else {
link_debug_info = $$QMAKE_OBJCOPY --add-gnu-debuglink=$$shell_target_debug_info $$shell_target link_debug_info = $$QMAKE_OBJCOPY --add-gnu-debuglink=$$shell_target_debug_info $$shell_target
chmod_debug_info = chmod -x $$shell_target_debug_info !contains(QMAKE_HOST.os, Windows): \
QMAKE_POST_LINK = $$copy_debug_info && $$strip_debug_info && $$link_debug_info && $$chmod_debug_info $$QMAKE_POST_LINK QMAKE_POST_LINK = && chmod -x $$shell_target_debug_info $$QMAKE_POST_LINK
QMAKE_POST_LINK = $$copy_debug_info && $$strip_debug_info && $$link_debug_info $$QMAKE_POST_LINK
} }
silent:QMAKE_POST_LINK = @echo creating $@.$$debug_info_suffix && $$QMAKE_POST_LINK silent:QMAKE_POST_LINK = @echo creating $@.$$debug_info_suffix && $$QMAKE_POST_LINK

View File

@ -87,7 +87,7 @@ bool QFseventsFileSystemWatcherEngine::checkDir(DirsByName::iterator &it)
if (res == -1) { if (res == -1) {
needsRestart |= derefPath(info.watchedPath); needsRestart |= derefPath(info.watchedPath);
emit emitDirectoryChanged(info.origPath, true); emit emitDirectoryChanged(info.origPath, true);
it = watchedDirectories.erase(it); it = watchingState.watchedDirectories.erase(it);
} else if (st.st_ctimespec != info.ctime || st.st_mode != info.mode) { } else if (st.st_ctimespec != info.ctime || st.st_mode != info.mode) {
info.ctime = st.st_ctimespec; info.ctime = st.st_ctimespec;
info.mode = st.st_mode; info.mode = st.st_mode;
@ -138,7 +138,8 @@ bool QFseventsFileSystemWatcherEngine::rescanDirs(const QString &path)
{ {
bool needsRestart = false; bool needsRestart = false;
for (DirsByName::iterator it = watchedDirectories.begin(); it != watchedDirectories.end(); ) { for (DirsByName::iterator it = watchingState.watchedDirectories.begin();
it != watchingState.watchedDirectories.end(); ) {
if (it.key().startsWith(path)) if (it.key().startsWith(path))
needsRestart |= checkDir(it); needsRestart |= checkDir(it);
else else
@ -177,11 +178,12 @@ bool QFseventsFileSystemWatcherEngine::rescanFiles(const QString &path)
{ {
bool needsRestart = false; bool needsRestart = false;
for (FilesByPath::iterator i = watchedFiles.begin(); i != watchedFiles.end(); ) { for (FilesByPath::iterator i = watchingState.watchedFiles.begin();
i != watchingState.watchedFiles.end(); ) {
if (i.key().startsWith(path)) { if (i.key().startsWith(path)) {
needsRestart |= rescanFiles(i.value()); needsRestart |= rescanFiles(i.value());
if (i.value().isEmpty()) { if (i.value().isEmpty()) {
i = watchedFiles.erase(i); i = watchingState.watchedFiles.erase(i);
continue; continue;
} }
} }
@ -232,8 +234,8 @@ void QFseventsFileSystemWatcherEngine::processEvent(ConstFSEventStreamRef stream
if (eFlags & kFSEventStreamEventFlagRootChanged) { if (eFlags & kFSEventStreamEventFlagRootChanged) {
// re-check everything: // re-check everything:
DirsByName::iterator dirIt = watchedDirectories.find(path); DirsByName::iterator dirIt = watchingState.watchedDirectories.find(path);
if (dirIt != watchedDirectories.end()) if (dirIt != watchingState.watchedDirectories.end())
needsRestart |= checkDir(dirIt); needsRestart |= checkDir(dirIt);
needsRestart |= rescanFiles(path); needsRestart |= rescanFiles(path);
continue; continue;
@ -243,13 +245,13 @@ void QFseventsFileSystemWatcherEngine::processEvent(ConstFSEventStreamRef stream
needsRestart |= rescanDirs(path); needsRestart |= rescanDirs(path);
// check watched directories: // check watched directories:
DirsByName::iterator dirIt = watchedDirectories.find(path); DirsByName::iterator dirIt = watchingState.watchedDirectories.find(path);
if (dirIt != watchedDirectories.end()) if (dirIt != watchingState.watchedDirectories.end())
needsRestart |= checkDir(dirIt); needsRestart |= checkDir(dirIt);
// check watched files: // check watched files:
FilesByPath::iterator pIt = watchedFiles.find(path); FilesByPath::iterator pIt = watchingState.watchedFiles.find(path);
if (pIt != watchedFiles.end()) if (pIt != watchingState.watchedFiles.end())
needsRestart |= rescanFiles(pIt.value()); needsRestart |= rescanFiles(pIt.value());
} }
@ -282,12 +284,11 @@ void QFseventsFileSystemWatcherEngine::doEmitDirectoryChanged(const QString &pat
emit directoryChanged(path, removed); emit directoryChanged(path, removed);
} }
void QFseventsFileSystemWatcherEngine::restartStream() bool QFseventsFileSystemWatcherEngine::restartStream()
{ {
QMacAutoReleasePool pool;
QMutexLocker locker(&lock); QMutexLocker locker(&lock);
stopStream(); stopStream();
startStream(); return startStream();
} }
QFseventsFileSystemWatcherEngine *QFseventsFileSystemWatcherEngine::create(QObject *parent) QFseventsFileSystemWatcherEngine *QFseventsFileSystemWatcherEngine::create(QObject *parent)
@ -317,6 +318,7 @@ QFseventsFileSystemWatcherEngine::~QFseventsFileSystemWatcherEngine()
{ {
QMacAutoReleasePool pool; QMacAutoReleasePool pool;
// Stop the stream in case we have to wait for the lock below to be acquired.
if (stream) if (stream)
FSEventStreamStop(stream); FSEventStreamStop(stream);
@ -340,8 +342,10 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
QMutexLocker locker(&lock); QMutexLocker locker(&lock);
bool wasRunning = stream != Q_NULLPTR;
bool needsRestart = false; bool needsRestart = false;
WatchingState oldState = watchingState;
QStringList p = paths; QStringList p = paths;
QMutableListIterator<QString> it(p); QMutableListIterator<QString> it(p);
while (it.hasNext()) { while (it.hasNext()) {
@ -362,7 +366,7 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
const bool isDir = S_ISDIR(st.st_mode); const bool isDir = S_ISDIR(st.st_mode);
if (isDir) { if (isDir) {
if (watchedDirectories.contains(realPath)) if (watchingState.watchedDirectories.contains(realPath))
continue; continue;
directories->append(origPath); directories->append(origPath);
watchedPath = realPath; watchedPath = realPath;
@ -377,17 +381,18 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
parentPath = watchedPath; parentPath = watchedPath;
} }
for (PathRefCounts::const_iterator i = watchedPaths.begin(), ei = watchedPaths.end(); i != ei; ++i) { for (PathRefCounts::const_iterator i = watchingState.watchedPaths.begin(),
ei = watchingState.watchedPaths.end(); i != ei; ++i) {
if (watchedPath.startsWith(i.key())) { if (watchedPath.startsWith(i.key())) {
watchedPath = i.key(); watchedPath = i.key();
break; break;
} }
} }
PathRefCounts::iterator it = watchedPaths.find(watchedPath); PathRefCounts::iterator it = watchingState.watchedPaths.find(watchedPath);
if (it == watchedPaths.end()) { if (it == watchingState.watchedPaths.end()) {
needsRestart = true; needsRestart = true;
watchedPaths.insert(watchedPath, 1); watchingState.watchedPaths.insert(watchedPath, 1);
DEBUG("Adding '%s' to watchedPaths", qPrintable(watchedPath)); DEBUG("Adding '%s' to watchedPaths", qPrintable(watchedPath));
} else { } else {
++it.value(); ++it.value();
@ -398,18 +403,25 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
DirInfo dirInfo; DirInfo dirInfo;
dirInfo.dirInfo = info; dirInfo.dirInfo = info;
dirInfo.entries = scanForDirEntries(realPath); dirInfo.entries = scanForDirEntries(realPath);
watchedDirectories.insert(realPath, dirInfo); watchingState.watchedDirectories.insert(realPath, dirInfo);
DEBUG("-- Also adding '%s' to watchedDirectories", qPrintable(realPath)); DEBUG("-- Also adding '%s' to watchedDirectories", qPrintable(realPath));
} else { } else {
watchedFiles[parentPath].insert(realPath, info); watchingState.watchedFiles[parentPath].insert(realPath, info);
DEBUG("-- Also adding '%s' to watchedFiles", qPrintable(realPath)); DEBUG("-- Also adding '%s' to watchedFiles", qPrintable(realPath));
} }
} }
if (needsRestart) { if (needsRestart) {
stopStream(); stopStream();
if (!startStream()) if (!startStream()) {
// ok, something went wrong, let's try to restore the previous state
watchingState = qMove(oldState);
// and because we don't know which path caused the issue (if any), fail on all of them
p = paths; p = paths;
if (wasRunning)
startStream();
}
} }
return p; return p;
@ -425,6 +437,7 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat
bool needsRestart = false; bool needsRestart = false;
WatchingState oldState = watchingState;
QStringList p = paths; QStringList p = paths;
QMutableListIterator<QString> it(p); QMutableListIterator<QString> it(p);
while (it.hasNext()) { while (it.hasNext()) {
@ -437,10 +450,10 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat
realPath = fi.canonicalFilePath(); realPath = fi.canonicalFilePath();
if (fi.isDir()) { if (fi.isDir()) {
DirsByName::iterator dirIt = watchedDirectories.find(realPath); DirsByName::iterator dirIt = watchingState.watchedDirectories.find(realPath);
if (dirIt != watchedDirectories.end()) { if (dirIt != watchingState.watchedDirectories.end()) {
needsRestart |= derefPath(dirIt->dirInfo.watchedPath); needsRestart |= derefPath(dirIt->dirInfo.watchedPath);
watchedDirectories.erase(dirIt); watchingState.watchedDirectories.erase(dirIt);
directories->removeAll(origPath); directories->removeAll(origPath);
it.remove(); it.remove();
DEBUG("Removed directory '%s'", qPrintable(realPath)); DEBUG("Removed directory '%s'", qPrintable(realPath));
@ -448,15 +461,15 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat
} else { } else {
QFileInfo fi(realPath); QFileInfo fi(realPath);
QString parentPath = fi.path(); QString parentPath = fi.path();
FilesByPath::iterator pIt = watchedFiles.find(parentPath); FilesByPath::iterator pIt = watchingState.watchedFiles.find(parentPath);
if (pIt != watchedFiles.end()) { if (pIt != watchingState.watchedFiles.end()) {
InfoByName &filesInDir = pIt.value(); InfoByName &filesInDir = pIt.value();
InfoByName::iterator fIt = filesInDir.find(realPath); InfoByName::iterator fIt = filesInDir.find(realPath);
if (fIt != filesInDir.end()) { if (fIt != filesInDir.end()) {
needsRestart |= derefPath(fIt->watchedPath); needsRestart |= derefPath(fIt->watchedPath);
filesInDir.erase(fIt); filesInDir.erase(fIt);
if (filesInDir.isEmpty()) if (filesInDir.isEmpty())
watchedFiles.erase(pIt); watchingState.watchedFiles.erase(pIt);
files->removeAll(origPath); files->removeAll(origPath);
it.remove(); it.remove();
DEBUG("Removed file '%s'", qPrintable(realPath)); DEBUG("Removed file '%s'", qPrintable(realPath));
@ -467,26 +480,33 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat
locker.unlock(); locker.unlock();
if (needsRestart) if (needsRestart) {
restartStream(); if (!restartStream()) {
watchingState = qMove(oldState);
startStream();
}
}
return p; return p;
} }
// Returns false if FSEventStream* calls failed for some mysterious reason, true if things got a
// thumbs-up.
bool QFseventsFileSystemWatcherEngine::startStream() bool QFseventsFileSystemWatcherEngine::startStream()
{ {
Q_ASSERT(stream == 0); Q_ASSERT(stream == 0);
QMacAutoReleasePool pool; if (stream) // Ok, this really shouldn't happen, esp. not after the assert. But let's be nice in release mode and still handle it.
if (stream) // This shouldn't happen, but let's be nice and handle it.
stopStream(); stopStream();
if (watchedPaths.isEmpty()) QMacAutoReleasePool pool;
return false;
DEBUG() << "Starting stream with paths" << watchedPaths.keys(); if (watchingState.watchedPaths.isEmpty())
return true; // we succeeded in doing nothing
NSMutableArray *pathsToWatch = [NSMutableArray arrayWithCapacity:watchedPaths.size()]; DEBUG() << "Starting stream with paths" << watchingState.watchedPaths.keys();
for (PathRefCounts::const_iterator i = watchedPaths.begin(), ei = watchedPaths.end(); i != ei; ++i)
NSMutableArray *pathsToWatch = [NSMutableArray arrayWithCapacity:watchingState.watchedPaths.size()];
for (PathRefCounts::const_iterator i = watchingState.watchedPaths.begin(), ei = watchingState.watchedPaths.end(); i != ei; ++i)
[pathsToWatch addObject:i.key().toNSString()]; [pathsToWatch addObject:i.key().toNSString()];
struct FSEventStreamContext callBackInfo = { struct FSEventStreamContext callBackInfo = {
@ -510,7 +530,7 @@ bool QFseventsFileSystemWatcherEngine::startStream()
latency, latency,
FSEventStreamCreateFlags(0)); FSEventStreamCreateFlags(0));
if (!stream) { if (!stream) { // nope, no way to know what went wrong, so just fail
DEBUG() << "Failed to create stream!"; DEBUG() << "Failed to create stream!";
return false; return false;
} }
@ -520,7 +540,7 @@ bool QFseventsFileSystemWatcherEngine::startStream()
if (FSEventStreamStart(stream)) { if (FSEventStreamStart(stream)) {
DEBUG() << "Stream started successfully with sinceWhen =" << lastReceivedEvent; DEBUG() << "Stream started successfully with sinceWhen =" << lastReceivedEvent;
return true; return true;
} else { } else { // again, no way to know what went wrong, so just clean up and fail
DEBUG() << "Stream failed to start!"; DEBUG() << "Stream failed to start!";
FSEventStreamInvalidate(stream); FSEventStreamInvalidate(stream);
FSEventStreamRelease(stream); FSEventStreamRelease(stream);
@ -531,6 +551,7 @@ bool QFseventsFileSystemWatcherEngine::startStream()
void QFseventsFileSystemWatcherEngine::stopStream(bool isStopped) void QFseventsFileSystemWatcherEngine::stopStream(bool isStopped)
{ {
QMacAutoReleasePool pool;
if (stream) { if (stream) {
if (!isStopped) if (!isStopped)
FSEventStreamStop(stream); FSEventStreamStop(stream);
@ -560,9 +581,9 @@ QFseventsFileSystemWatcherEngine::InfoByName QFseventsFileSystemWatcherEngine::s
bool QFseventsFileSystemWatcherEngine::derefPath(const QString &watchedPath) bool QFseventsFileSystemWatcherEngine::derefPath(const QString &watchedPath)
{ {
PathRefCounts::iterator it = watchedPaths.find(watchedPath); PathRefCounts::iterator it = watchingState.watchedPaths.find(watchedPath);
if (it != watchedPaths.end() && --it.value() < 1) { if (it != watchingState.watchedPaths.end() && --it.value() < 1) {
watchedPaths.erase(it); watchingState.watchedPaths.erase(it);
DEBUG("Removing '%s' from watchedPaths.", qPrintable(watchedPath)); DEBUG("Removing '%s' from watchedPaths.", qPrintable(watchedPath));
return true; return true;
} }

View File

@ -87,7 +87,7 @@ Q_SIGNALS:
private slots: private slots:
void doEmitFileChanged(const QString &path, bool removed); void doEmitFileChanged(const QString &path, bool removed);
void doEmitDirectoryChanged(const QString &path, bool removed); void doEmitDirectoryChanged(const QString &path, bool removed);
void restartStream(); bool restartStream();
private: private:
struct Info { struct Info {
@ -118,6 +118,19 @@ private:
typedef QHash<QString, DirInfo> DirsByName; typedef QHash<QString, DirInfo> DirsByName;
typedef QHash<QString, qint64> PathRefCounts; typedef QHash<QString, qint64> PathRefCounts;
struct WatchingState {
// These fields go hand-in-hand. FSEvents watches paths, and there is no use in watching
// the same path multiple times. So, the "refcount" on a path is the number of watched
// files that have the same path, plus the number of directories that have the same path.
//
// If the stream fails to start after adding files/directories, the watcher will try to
// keep watching files/directories that it was already watching. It does that by restoring
// the previous WatchingState and restarting the stream.
FilesByPath watchedFiles;
DirsByName watchedDirectories;
PathRefCounts watchedPaths;
};
QFseventsFileSystemWatcherEngine(QObject *parent); QFseventsFileSystemWatcherEngine(QObject *parent);
bool startStream(); bool startStream();
void stopStream(bool isStopped = false); void stopStream(bool isStopped = false);
@ -131,10 +144,8 @@ private:
QMutex lock; QMutex lock;
dispatch_queue_t queue; dispatch_queue_t queue;
FSEventStreamRef stream; FSEventStreamRef stream;
FilesByPath watchedFiles;
DirsByName watchedDirectories;
PathRefCounts watchedPaths;
FSEventStreamEventId lastReceivedEvent; FSEventStreamEventId lastReceivedEvent;
WatchingState watchingState;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -672,7 +672,7 @@ QString QTemporaryFile::fileTemplate() const
/*! /*!
Sets the static portion of the file name to \a name. If the file Sets the static portion of the file name to \a name. If the file
template ends in XXXXXX that will automatically be replaced with template contains XXXXXX that will automatically be replaced with
the unique part of the filename, otherwise a filename will be the unique part of the filename, otherwise a filename will be
determined automatically based on the static portion specified. determined automatically based on the static portion specified.

View File

@ -539,6 +539,8 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv
A single-shot timer fires only once, non-single-shot timers fire A single-shot timer fires only once, non-single-shot timers fire
every \l interval milliseconds. every \l interval milliseconds.
The default value for this property is \c false.
\sa interval, singleShot() \sa interval, singleShot()
*/ */

View File

@ -39,6 +39,9 @@
#include "qdbusargument_p.h" #include "qdbusargument_p.h"
#include "qdbusconnection.h" #include "qdbusconnection.h"
#include <qscopedpointer.h>
#include <stdlib.h> #include <stdlib.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -423,12 +426,12 @@ QDBusDemarshaller *QDBusDemarshaller::endCommon()
QDBusArgument QDBusDemarshaller::duplicate() QDBusArgument QDBusDemarshaller::duplicate()
{ {
QDBusDemarshaller *d = new QDBusDemarshaller(capabilities); QScopedPointer<QDBusDemarshaller> d(new QDBusDemarshaller(capabilities));
d->iterator = iterator; d->iterator = iterator;
d->message = q_dbus_message_ref(message); d->message = q_dbus_message_ref(message);
q_dbus_message_iter_next(&iterator); q_dbus_message_iter_next(&iterator);
return QDBusArgumentPrivate::create(d); return QDBusArgumentPrivate::create(d.take());
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -768,39 +768,37 @@ QBitmap QPixmap::createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode)
bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConversionFlags flags) bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConversionFlags flags)
{ {
if (fileName.isEmpty()) { if (!fileName.isEmpty()) {
data.reset();
return false; QFileInfo info(fileName);
// Note: If no extension is provided, we try to match the
// file against known plugin extensions
if (info.completeSuffix().isEmpty() || info.exists()) {
QString key = QLatin1String("qt_pixmap")
% info.absoluteFilePath()
% HexString<uint>(info.lastModified().toTime_t())
% HexString<quint64>(info.size())
% HexString<uint>(data ? data->pixelType() : QPlatformPixmap::PixmapType);
if (QPixmapCache::find(key, this))
return true;
data = QPlatformPixmap::create(0, 0, data ? data->pixelType() : QPlatformPixmap::PixmapType);
if (data->fromFile(fileName, format, flags)) {
QPixmapCache::insert(key, *this);
return true;
}
}
} }
detach(); if (!isNull()) {
if (isQBitmap())
QFileInfo info(fileName); *this = QBitmap();
QString key = QLatin1String("qt_pixmap") else
% info.absoluteFilePath() data.reset();
% HexString<uint>(info.lastModified().toTime_t())
% HexString<quint64>(info.size())
% HexString<uint>(data ? data->pixelType() : QPlatformPixmap::PixmapType);
// Note: If no extension is provided, we try to match the
// file against known plugin extensions
if (!info.completeSuffix().isEmpty() && !info.exists()) {
data.reset();
return false;
} }
if (QPixmapCache::find(key, this))
return true;
if (!data)
data = QPlatformPixmap::create(0, 0, QPlatformPixmap::PixmapType);
if (data->fromFile(fileName, format, flags)) {
QPixmapCache::insert(key, *this);
return true;
}
data.reset();
return false; return false;
} }

View File

@ -1658,7 +1658,7 @@ QResizeEvent::~QResizeEvent()
The event handler QWidget::closeEvent() receives close events. The The event handler QWidget::closeEvent() receives close events. The
default implementation of this event handler accepts the close default implementation of this event handler accepts the close
event. If you do not want your widget to be hidden, or want some event. If you do not want your widget to be hidden, or want some
special handing, you should reimplement the event handler and special handling, you should reimplement the event handler and
ignore() the event. ignore() the event.
The \l{mainwindows/application#close event handler}{closeEvent() in the The \l{mainwindows/application#close event handler}{closeEvent() in the

View File

@ -674,8 +674,7 @@ bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
HttpMessagePair messagePair = highPriorityQueue.takeLast(); HttpMessagePair messagePair = highPriorityQueue.takeLast();
if (!messagePair.second->d_func()->requestIsPrepared) if (!messagePair.second->d_func()->requestIsPrepared)
prepareRequest(messagePair); prepareRequest(messagePair);
channels[i].request = messagePair.first; updateChannel(i, messagePair);
channels[i].reply = messagePair.second;
return true; return true;
} }
@ -684,13 +683,21 @@ bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
HttpMessagePair messagePair = lowPriorityQueue.takeLast(); HttpMessagePair messagePair = lowPriorityQueue.takeLast();
if (!messagePair.second->d_func()->requestIsPrepared) if (!messagePair.second->d_func()->requestIsPrepared)
prepareRequest(messagePair); prepareRequest(messagePair);
channels[i].request = messagePair.first; updateChannel(i, messagePair);
channels[i].reply = messagePair.second;
return true; return true;
} }
return false; return false;
} }
void QHttpNetworkConnectionPrivate::updateChannel(int i, const HttpMessagePair &messagePair)
{
channels[i].request = messagePair.first;
channels[i].reply = messagePair.second;
// Now that reply is assigned a channel, correct reply to channel association
// previously set in queueRequest.
channels[i].reply->d_func()->connectionChannel = &channels[i];
}
QHttpNetworkRequest QHttpNetworkConnectionPrivate::predictNextRequest() const QHttpNetworkRequest QHttpNetworkConnectionPrivate::predictNextRequest() const
{ {
if (!highPriorityQueue.isEmpty()) if (!highPriorityQueue.isEmpty())

View File

@ -213,6 +213,7 @@ public:
void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke
bool dequeueRequest(QAbstractSocket *socket); bool dequeueRequest(QAbstractSocket *socket);
void prepareRequest(HttpMessagePair &request); void prepareRequest(HttpMessagePair &request);
void updateChannel(int i, const HttpMessagePair &messagePair);
QHttpNetworkRequest predictNextRequest() const; QHttpNetworkRequest predictNextRequest() const;
void fillPipeline(QAbstractSocket *socket); void fillPipeline(QAbstractSocket *socket);

View File

@ -1076,6 +1076,7 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
connection->d_func()->dequeueRequest(socket); connection->d_func()->dequeueRequest(socket);
if (reply) { if (reply) {
reply->setSpdyWasUsed(false); reply->setSpdyWasUsed(false);
Q_ASSERT(reply->d_func()->connectionChannel == this);
emit reply->encrypted(); emit reply->encrypted();
} }
if (reply) if (reply)
@ -1115,8 +1116,6 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
connection->d_func()->pauseConnection(); connection->d_func()->pauseConnection();
if (pendingEncrypt && !reply) if (pendingEncrypt && !reply)
connection->d_func()->dequeueRequest(socket); connection->d_func()->dequeueRequest(socket);
if (reply) // a reply was actually dequeued.
reply->d_func()->connectionChannel = this; // set correct channel like in sendRequest() and queueRequest();
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) { if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) {
if (reply) if (reply)
emit reply->sslErrors(errors); emit reply->sslErrors(errors);

View File

@ -95,6 +95,12 @@ bool QDBusMenuConnection::registerTrayIconMenu(QDBusTrayIcon *item)
return success; return success;
} }
void QDBusMenuConnection::unregisterTrayIconMenu(QDBusTrayIcon *item)
{
if (item->menu())
connection().unregisterObject(MenuBarPath);
}
bool QDBusMenuConnection::registerTrayIcon(QDBusTrayIcon *item) bool QDBusMenuConnection::registerTrayIcon(QDBusTrayIcon *item)
{ {
bool success = connection().registerService(item->instanceId()); bool success = connection().registerService(item->instanceId());
@ -124,7 +130,7 @@ bool QDBusMenuConnection::registerTrayIcon(QDBusTrayIcon *item)
bool QDBusMenuConnection::unregisterTrayIcon(QDBusTrayIcon *item) bool QDBusMenuConnection::unregisterTrayIcon(QDBusTrayIcon *item)
{ {
connection().unregisterObject(MenuBarPath); unregisterTrayIconMenu(item);
connection().unregisterObject(StatusNotifierItemPath); connection().unregisterObject(StatusNotifierItemPath);
bool success = connection().unregisterService(item->instanceId()); bool success = connection().unregisterService(item->instanceId());
if (!success) if (!success)

View File

@ -72,6 +72,7 @@ public:
bool isStatusNotifierHostRegistered() const { return m_statusNotifierHostRegistered; } bool isStatusNotifierHostRegistered() const { return m_statusNotifierHostRegistered; }
#ifndef QT_NO_SYSTEMTRAYICON #ifndef QT_NO_SYSTEMTRAYICON
bool registerTrayIconMenu(QDBusTrayIcon *item); bool registerTrayIconMenu(QDBusTrayIcon *item);
void unregisterTrayIconMenu(QDBusTrayIcon *item);
bool registerTrayIcon(QDBusTrayIcon *item); bool registerTrayIcon(QDBusTrayIcon *item);
bool unregisterTrayIcon(QDBusTrayIcon *item); bool unregisterTrayIcon(QDBusTrayIcon *item);
#endif // QT_NO_SYSTEMTRAYICON #endif // QT_NO_SYSTEMTRAYICON

View File

@ -213,20 +213,21 @@ QPlatformMenu *QDBusTrayIcon::createMenu() const
void QDBusTrayIcon::updateMenu(QPlatformMenu * menu) void QDBusTrayIcon::updateMenu(QPlatformMenu * menu)
{ {
qCDebug(qLcTray) << menu; qCDebug(qLcTray) << menu;
bool needsRegistering = !m_menu; QDBusPlatformMenu *newMenu = qobject_cast<QDBusPlatformMenu *>(menu);
if (!m_menu) if (m_menu != newMenu) {
m_menu = qobject_cast<QDBusPlatformMenu *>(menu); if (m_menu) {
if (!m_menuAdaptor) { dBusConnection()->unregisterTrayIconMenu(this);
delete m_menuAdaptor;
}
m_menu = newMenu;
m_menuAdaptor = new QDBusMenuAdaptor(m_menu); m_menuAdaptor = new QDBusMenuAdaptor(m_menu);
// TODO connect(m_menu, , m_menuAdaptor, SIGNAL(ItemActivationRequested(int,uint))); // TODO connect(m_menu, , m_menuAdaptor, SIGNAL(ItemActivationRequested(int,uint)));
connect(m_menu, SIGNAL(propertiesUpdated(QDBusMenuItemList,QDBusMenuItemKeysList)), connect(m_menu, SIGNAL(propertiesUpdated(QDBusMenuItemList,QDBusMenuItemKeysList)),
m_menuAdaptor, SIGNAL(ItemsPropertiesUpdated(QDBusMenuItemList,QDBusMenuItemKeysList))); m_menuAdaptor, SIGNAL(ItemsPropertiesUpdated(QDBusMenuItemList,QDBusMenuItemKeysList)));
connect(m_menu, SIGNAL(updated(uint,int)), connect(m_menu, SIGNAL(updated(uint,int)),
m_menuAdaptor, SIGNAL(LayoutUpdated(uint,int))); m_menuAdaptor, SIGNAL(LayoutUpdated(uint,int)));
}
m_menu->emitUpdated();
if (needsRegistering)
dBusConnection()->registerTrayIconMenu(this); dBusConnection()->registerTrayIconMenu(this);
}
} }
void QDBusTrayIcon::showMessage(const QString &title, const QString &msg, const QIcon &icon, void QDBusTrayIcon::showMessage(const QString &title, const QString &msg, const QIcon &icon,

View File

@ -507,7 +507,7 @@ static const uint CmdTbl[] = { // Multimedia keys mapping table
Qt::Key_Open, // 30 0x1e APPCOMMAND_OPEN Qt::Key_Open, // 30 0x1e APPCOMMAND_OPEN
Qt::Key_Close, // 31 0x1f APPCOMMAND_CLOSE Qt::Key_Close, // 31 0x1f APPCOMMAND_CLOSE
Qt::Key_Save, // 32 0x20 APPCOMMAND_SAVE Qt::Key_Save, // 32 0x20 APPCOMMAND_SAVE
Qt::Key_Print, // 33 0x21 APPCOMMAND_PRINT Qt::Key_Printer, // 33 0x21 APPCOMMAND_PRINT
Qt::Key_Undo, // 34 0x22 APPCOMMAND_UNDO Qt::Key_Undo, // 34 0x22 APPCOMMAND_UNDO
Qt::Key_Redo, // 35 0x23 APPCOMMAND_REDO Qt::Key_Redo, // 35 0x23 APPCOMMAND_REDO
Qt::Key_Copy, // 36 0x24 APPCOMMAND_COPY Qt::Key_Copy, // 36 0x24 APPCOMMAND_COPY

View File

@ -737,7 +737,7 @@
\image spinboxdelegate-example.png \image spinboxdelegate-example.png
We subclass the delegate from \l QItemDelegate because we do not want We subclass the delegate from \l QStyledItemDelegate because we do not want
to write custom display functions. However, we must still provide to write custom display functions. However, we must still provide
functions to manage the editor widget: functions to manage the editor widget:

View File

@ -274,6 +274,11 @@ QGraphicsWidget::~QGraphicsWidget()
// Remove this graphics widget from widgetStyles // Remove this graphics widget from widgetStyles
widgetStyles()->setStyleForWidget(this, 0); widgetStyles()->setStyleForWidget(this, 0);
// Unset the parent here, when we're still a QGraphicsWidget.
// It is otherwise done in ~QGraphicsItem() where we'd be
// calling QGraphicsWidget members on an ex-QGraphicsWidget object
setParentItem(Q_NULLPTR);
} }
/*! /*!

View File

@ -1786,13 +1786,18 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event)
d->autoScroll = false; d->autoScroll = false;
d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
d->autoScroll = autoScroll; d->autoScroll = autoScroll;
QRect rect(visualRect(d->currentSelectionStartIndex).center(), pos);
if (command.testFlag(QItemSelectionModel::Toggle)) { if (command.testFlag(QItemSelectionModel::Toggle)) {
command &= ~QItemSelectionModel::Toggle; command &= ~QItemSelectionModel::Toggle;
d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select; d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
command |= d->ctrlDragSelectionFlag; command |= d->ctrlDragSelectionFlag;
} }
setSelection(rect, command);
if ((command & QItemSelectionModel::Current) == 0) {
setSelection(QRect(pos, QSize(1, 1)), command);
} else {
QRect rect(visualRect(d->currentSelectionStartIndex).center(), pos);
setSelection(rect, command);
}
// signal handlers may change the model // signal handlers may change the model
emit pressed(index); emit pressed(index);

View File

@ -157,7 +157,7 @@ public:
int insertRow(int row); int insertRow(int row);
void insertRows(int row, int count); void insertRows(int row, int count);
void setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item); bool setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item);
void setLayout(int row, QFormLayout::ItemRole role, QLayout *layout); void setLayout(int row, QFormLayout::ItemRole role, QLayout *layout);
void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget); void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget);
@ -919,21 +919,21 @@ void QFormLayoutPrivate::insertRows(int row, int count)
} }
} }
void QFormLayoutPrivate::setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item) bool QFormLayoutPrivate::setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item)
{ {
const bool fullRow = role == QFormLayout::SpanningRole; const bool fullRow = role == QFormLayout::SpanningRole;
const int column = role == QFormLayout::SpanningRole ? 1 : static_cast<int>(role); const int column = role == QFormLayout::SpanningRole ? 1 : static_cast<int>(role);
if (Q_UNLIKELY(uint(row) >= uint(m_matrix.rowCount()) || uint(column) > 1U)) { if (Q_UNLIKELY(uint(row) >= uint(m_matrix.rowCount()) || uint(column) > 1U)) {
qWarning("QFormLayoutPrivate::setItem: Invalid cell (%d, %d)", row, column); qWarning("QFormLayoutPrivate::setItem: Invalid cell (%d, %d)", row, column);
return; return false;
} }
if (!item) if (!item)
return; return false;
if (Q_UNLIKELY(m_matrix(row, column))) { if (Q_UNLIKELY(m_matrix(row, column))) {
qWarning("QFormLayoutPrivate::setItem: Cell (%d, %d) already occupied", row, column); qWarning("QFormLayoutPrivate::setItem: Cell (%d, %d) already occupied", row, column);
return; return false;
} }
QFormLayoutItem *i = new QFormLayoutItem(item); QFormLayoutItem *i = new QFormLayoutItem(item);
@ -941,6 +941,7 @@ void QFormLayoutPrivate::setItem(int row, QFormLayout::ItemRole role, QLayoutIte
m_matrix(row, column) = i; m_matrix(row, column) = i;
m_things.append(i); m_things.append(i);
return true;
} }
void QFormLayoutPrivate::setLayout(int row, QFormLayout::ItemRole role, QLayout *layout) void QFormLayoutPrivate::setLayout(int row, QFormLayout::ItemRole role, QLayout *layout)
@ -957,7 +958,9 @@ void QFormLayoutPrivate::setWidget(int row, QFormLayout::ItemRole role, QWidget
if (widget) { if (widget) {
Q_Q(QFormLayout); Q_Q(QFormLayout);
q->addChildWidget(widget); q->addChildWidget(widget);
setItem(row, role, QLayoutPrivate::createWidgetItem(q, widget)); QWidgetItem *item = QLayoutPrivate::createWidgetItem(q, widget);
if (!setItem(row, role, item))
delete item;
} }
} }

View File

@ -1317,7 +1317,9 @@ QDockWidget::DockWidgetFeatures QDockWidget::features() const
By default, this property is \c true. By default, this property is \c true.
\sa isWindow() When this property changes, the \c {topLevelChanged()} signal is emitted.
\sa isWindow(), topLevelChanged()
*/ */
void QDockWidget::setFloating(bool floating) void QDockWidget::setFloating(bool floating)
{ {

View File

@ -1514,7 +1514,7 @@ void QTextEditPrivate::paint(QPainter *p, QPaintEvent *e)
if (layout) if (layout)
layout->setViewport(QRect()); layout->setViewport(QRect());
if (!placeholderText.isEmpty() && doc->isEmpty()) { if (!placeholderText.isEmpty() && doc->isEmpty() && !control->isPreediting()) {
QColor col = control->palette().text().color(); QColor col = control->palette().text().color();
col.setAlpha(128); col.setAlpha(128);
p->setPen(col); p->setPen(col);

View File

@ -2584,6 +2584,11 @@ bool QWidgetTextControl::isWordSelectionEnabled() const
return d->wordSelectionEnabled; return d->wordSelectionEnabled;
} }
bool QWidgetTextControl::isPreediting()
{
return d_func()->isPreediting();
}
#ifndef QT_NO_PRINTER #ifndef QT_NO_PRINTER
void QWidgetTextControl::print(QPagedPaintDevice *printer) const void QWidgetTextControl::print(QPagedPaintDevice *printer) const
{ {

View File

@ -172,6 +172,8 @@ public:
bool isWordSelectionEnabled() const; bool isWordSelectionEnabled() const;
void setWordSelectionEnabled(bool enabled); void setWordSelectionEnabled(bool enabled);
bool isPreediting();
void print(QPagedPaintDevice *printer) const; void print(QPagedPaintDevice *printer) const;
virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const; virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const;

View File

@ -1492,6 +1492,33 @@ void tst_QPixmap::loadAsBitmapOrPixmap()
QVERIFY(!bitmap.isNull()); QVERIFY(!bitmap.isNull());
QCOMPARE(bitmap.depth(), 1); QCOMPARE(bitmap.depth(), 1);
QVERIFY(bitmap.isQBitmap()); QVERIFY(bitmap.isQBitmap());
// check that a QBitmap stays a QBitmap even when loading fails:
ok = bitmap.load(QString());
QVERIFY(!ok);
QVERIFY(bitmap.isNull());
QVERIFY(bitmap.isQBitmap());
ok = bitmap.load("does not exist");
QVERIFY(!ok);
QVERIFY(bitmap.isNull());
QVERIFY(bitmap.isQBitmap());
ok = bitmap.load("does not exist.png");
QVERIFY(!ok);
QVERIFY(bitmap.isNull());
QVERIFY(bitmap.isQBitmap());
QTemporaryFile garbage;
QVERIFY(garbage.open());
const QString garbagePath = garbage.fileName();
garbage.write(reinterpret_cast<const char *>(&garbage), sizeof garbage);
garbage.close();
ok = bitmap.load(garbagePath);
QVERIFY(!ok);
QVERIFY(bitmap.isNull());
QVERIFY(bitmap.isQBitmap());
} }
void tst_QPixmap::toImageDeepCopy() void tst_QPixmap::toImageDeepCopy()

View File

@ -149,6 +149,7 @@ private slots:
void QTBUG50102_SH_ItemView_ScrollMode(); void QTBUG50102_SH_ItemView_ScrollMode();
void QTBUG50535_update_on_new_selection_model(); void QTBUG50535_update_on_new_selection_model();
void testSelectionModelInSyncWithView(); void testSelectionModelInSyncWithView();
void testClickToSelect();
}; };
class MyAbstractItemDelegate : public QAbstractItemDelegate class MyAbstractItemDelegate : public QAbstractItemDelegate
@ -2113,5 +2114,56 @@ void tst_QAbstractItemView::testSelectionModelInSyncWithView()
QCOMPARE(view.selectionModel()->selection().indexes(), QModelIndexList() << model.index(0, 0)); QCOMPARE(view.selectionModel()->selection().indexes(), QModelIndexList() << model.index(0, 0));
} }
class SetSelectionTestView : public QListView
{
Q_OBJECT
public:
SetSelectionTestView() : QListView() {}
signals:
void setSelectionCalled(const QRect &rect);
protected:
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) Q_DECL_OVERRIDE
{
emit setSelectionCalled(rect);
QListView::setSelection(rect, flags);
}
};
void tst_QAbstractItemView::testClickToSelect()
{
// This test verifies that the QRect that is passed from QAbstractItemView::mousePressEvent
// to the virtual method QAbstractItemView::setSelection(const QRect &, SelectionFlags)
// is the 1x1 rect which conains exactly the clicked pixel if no modifiers are pressed.
QStringList list;
list << "A" << "B" << "C";
QStringListModel model(list);
SetSelectionTestView view;
view.setModel(&model);
view.show();
QTest::qWaitForWindowExposed(&view);
QSignalSpy spy(&view, &SetSelectionTestView::setSelectionCalled);
const QModelIndex indexA(model.index(0, 0));
const QRect visualRectA = view.visualRect(indexA);
const QPoint centerA = visualRectA.center();
// Click the center of the visualRect of item "A"
QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, centerA);
QCOMPARE(spy.count(), 1);
QCOMPARE(spy.back().front().value<QRect>(), QRect(centerA, QSize(1, 1)));
// Click a point slightly away from the center
const QPoint nearCenterA = centerA + QPoint(1, 1);
QVERIFY(visualRectA.contains(nearCenterA));
QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, nearCenterA);
QCOMPARE(spy.count(), 2);
QCOMPARE(spy.back().front().value<QRect>(), QRect(nearCenterA, QSize(1, 1)));
}
QTEST_MAIN(tst_QAbstractItemView) QTEST_MAIN(tst_QAbstractItemView)
#include "tst_qabstractitemview.moc" #include "tst_qabstractitemview.moc"

View File

@ -1207,7 +1207,8 @@ QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const char *name, int t
void tst_QShortcut::shortcutDestroyed(QObject* obj) void tst_QShortcut::shortcutDestroyed(QObject* obj)
{ {
shortcuts.removeAll(static_cast<QShortcut *>(obj)); shortcuts.erase(std::remove(shortcuts.begin(), shortcuts.end(), obj),
shortcuts.end());
} }
void tst_QShortcut::sendKeyEvents(int k1, QChar c1, int k2, QChar c2, int k3, QChar c3, int k4, QChar c4) void tst_QShortcut::sendKeyEvents(int k1, QChar c1, int k2, QChar c2, int k3, QChar c3, int k4, QChar c4)

View File

@ -163,7 +163,8 @@ private:
void tst_QStackedWidget::dynamicPages() void tst_QStackedWidget::dynamicPages()
{ {
QStackedWidget *sw = new QStackedWidget; QStackedWidget stackedWidget;
QStackedWidget *sw = &stackedWidget;
TestPage *w1 = new TestPage(true); TestPage *w1 = new TestPage(true);
w1->setN(3); w1->setN(3);