Merge "Merge branch 'stable' into dev" into refs/staging/dev

This commit is contained in:
Sergio Ahumada 2013-09-21 17:34:59 +02:00 committed by The Qt Project
commit 4cebef621b
31 changed files with 429 additions and 169 deletions

View File

@ -32,7 +32,7 @@
# manifestmeta.global.names = * # manifestmeta.global.names = *
# manifestmeta.global.tags = qt5 # manifestmeta.global.tags = qt5
manifestmeta.filters = highlighted webkit1 webkit2 android manifestmeta.filters = highlighted webkit1 webkit2 android thumbnail
manifestmeta.highlighted.names = "QtQuick/Qt Quick Demo - Same Game" \ manifestmeta.highlighted.names = "QtQuick/Qt Quick Demo - Same Game" \
"QtQuick/Qt Quick Demo - Photo Surface" \ "QtQuick/Qt Quick Demo - Photo Surface" \
@ -168,3 +168,28 @@ manifestmeta.android.names = "QtQuick/Qt Quick Demo - Maroon*" \
"QtWidgets/Address Book Example" "QtWidgets/Address Book Example"
manifestmeta.android.tags = android manifestmeta.android.tags = android
# add a generic thumbnail image to examples that do not have any images in their documentation
manifestmeta.thumbnail.attributes = "imageUrl:qthelp\://org.qt-project.qtdoc.$QT_VERSION_TAG/qtdoc/images/qt-codesample.png"
manifestmeta.thumbnail.names = "QtConcurrent/Map Example" \
"QtConcurrent/QtConcurrent Word Count Example" \
"QtConcurrent/Run Function Example" \
"QtGui/Raster Window Example" \
"QtNetwork/Network Download*" \
"QtWidgets/Dynamic Layouts Example" \
"QtWidgets/Event Transitions Example" \
"QtWidgets/Plug & Paint Basic Tools Example" \
"QtWidgets/Plug & Paint Extra Filters Example" \
"QtWidgets/Two-way Button Example" \
"QtWidgets/Validators Example" \
"ActiveQt/*" \
"QtDbus/*" \
"QtHelp/*" \
"QtMultimedia/AudioEngine Example" \
"QtMultimedia/Declarative Radio Example" \
"QtMultimedia/Media Player Example" \
"QtQml/Extending QML*" \
"QtQuick/Qt Quick Examples - Accessibility" \
"QtSensors/Qt Sensors - SensorGesture QML Type example" \
"QtWinExtras/Icon Extractor"

View File

@ -26,6 +26,7 @@ Cpp.ignoretokens += \
Q_CORE_EXPORT_INLINE \ Q_CORE_EXPORT_INLINE \
Q_DBUS_EXPORT \ Q_DBUS_EXPORT \
Q_DECL_CONSTEXPR \ Q_DECL_CONSTEXPR \
Q_DECL_DEPRECATED \
Q_DECL_NOEXCEPT \ Q_DECL_NOEXCEPT \
Q_DECL_NOTHROW \ Q_DECL_NOTHROW \
Q_DECLARATIVE_EXPORT \ Q_DECLARATIVE_EXPORT \

View File

@ -39,7 +39,7 @@
****************************************************************************/ ****************************************************************************/
#ifndef GRAPHICSVIEW_H #ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW #define GRAPHICSVIEW_H
#include <QtWidgets/QGraphicsView> #include <QtWidgets/QGraphicsView>

View File

@ -117,8 +117,8 @@
Random access iterators can be faster in cases where Qt Concurrent is iterating Random access iterators can be faster in cases where Qt Concurrent is iterating
over a large number of lightweight items, since they allow skipping to any point over a large number of lightweight items, since they allow skipping to any point
in the container. In addition, using random access iterators allows Qt Concurrent in the container. In addition, using random access iterators allows Qt Concurrent
to provide progress information trough QFuture::progressValue() and QFutureWatcher:: to provide progress information trough QFuture::progressValue() and
progressValueChanged(). QFutureWatcher::progressValueChanged().
The non in-place modifying functions such as mapped() and filtered() makes a The non in-place modifying functions such as mapped() and filtered() makes a
copy of the container when called. If you are using STL containers this copy operation copy of the container when called. If you are using STL containers this copy operation

View File

@ -47,7 +47,7 @@
\brief The <QtConcurrentFilter> header provides concurrent Filter and \brief The <QtConcurrentFilter> header provides concurrent Filter and
Filter-Reduce. Filter-Reduce.
These functions are a part of the \l {Concurrent Programming}{Qt Concurrent} framework. These functions are a part of the \l {Qt Concurrent} framework.
The QtConcurrent::filter(), QtConcurrent::filtered() and The QtConcurrent::filter(), QtConcurrent::filtered() and
QtConcurrent::filteredReduced() functions filter items in a sequence such QtConcurrent::filteredReduced() functions filter items in a sequence such

View File

@ -47,8 +47,8 @@
possible to write multi-threaded programs without using low-level possible to write multi-threaded programs without using low-level
threading primitives. threading primitives.
See the \l {Concurrent Programming}{Qt Concurrent} chapter in See the \l {Qt Concurrent} module documentation for an overview of available
the \l{threads.html}{threading} documentation. functions, or see below for detailed information on each function.
\inheaderfile QtConcurrent \inheaderfile QtConcurrent
\ingroup thread \ingroup thread
@ -74,7 +74,7 @@
\brief The <QtConcurrentMap> header provides concurrent Map and MapReduce. \brief The <QtConcurrentMap> header provides concurrent Map and MapReduce.
These functions are a part of the \l {Concurrent Programming}{Qt Concurrent} framework. These functions are a part of the \l {Qt Concurrent} framework.
The QtConcurrent::map(), QtConcurrent::mapped() and The QtConcurrent::map(), QtConcurrent::mapped() and
QtConcurrent::mappedReduced() functions run computations in parallel on QtConcurrent::mappedReduced() functions run computations in parallel on

View File

@ -48,7 +48,7 @@
\ingroup thread \ingroup thread
This function is a part of the \l {Concurrent Programming}{Qt Concurrent} framework. This function is a part of the \l {Qt Concurrent} framework.
The QtConcurrent::run() function runs a function in a separate thread. The QtConcurrent::run() function runs a function in a separate thread.
The return value of the function is made available through the QFuture API. The return value of the function is made available through the QFuture API.

View File

@ -63,7 +63,6 @@
\li \l{Synchronizing Threads} \li \l{Synchronizing Threads}
\li \l{Reentrancy and Thread-Safety} \li \l{Reentrancy and Thread-Safety}
\li \l{Threads and QObjects} \li \l{Threads and QObjects}
\li \l{Concurrent Programming}
\li \l{Thread-Support in Qt Modules} \li \l{Thread-Support in Qt Modules}
\endlist \endlist
@ -449,7 +448,7 @@
\previouspage Reentrancy and Thread Safety \previouspage Reentrancy and Thread Safety
\contentspage Thread Support in Qt \contentspage Thread Support in Qt
\nextpage Concurrent Programming \nextpage Thread-Support in Qt Modules
QThread inherits QObject. It emits signals to indicate that the QThread inherits QObject. It emits signals to indicate that the
thread started or finished executing, and provides a few slots as thread started or finished executing, and provides a few slots as
@ -645,114 +644,11 @@
a TCP server asynchronously. a TCP server asynchronously.
*/ */
/*!
\page threads-qtconcurrent.html
\title Concurrent Programming
\previouspage Threads and QObjects
\contentspage Thread Support in Qt
\nextpage Thread-Support in Qt Modules
\target qtconcurrent intro
The QtConcurrent namespace provides high-level APIs that make it
possible to write multi-threaded programs without using low-level
threading primitives such as mutexes, read-write locks, wait
conditions, or semaphores. Programs written with QtConcurrent
automatically adjust the number of threads used according to the
number of processor cores available. This means that applications
written today will continue to scale when deployed on multi-core
systems in the future.
QtConcurrent includes functional programming style APIs for
parallel list processing, including a MapReduce and FilterReduce
implementation for shared-memory (non-distributed) systems, and
classes for managing asynchronous computations in GUI
applications:
\list
\li QtConcurrent::map() applies a function to every item in a container,
modifying the items in-place.
\li QtConcurrent::mapped() is like map(), except that it returns a new
container with the modifications.
\li QtConcurrent::mappedReduced() is like mapped(), except that the
modified results are reduced or folded into a single result.
\li QtConcurrent::filter() removes all items from a container based on the
result of a filter function.
\li QtConcurrent::filtered() is like filter(), except that it returns a new
container with the filtered results.
\li QtConcurrent::filteredReduced() is like filtered(), except that the
filtered results are reduced or folded into a single result.
\li QtConcurrent::run() runs a function in another thread.
\li QFuture represents the result of an asynchronous computation.
\li QFutureIterator allows iterating through results available via QFuture.
\li QFutureWatcher allows monitoring a QFuture using signals-and-slots.
\li QFutureSynchronizer is a convenience class that automatically
synchronizes several QFutures.
\endlist
Qt Concurrent supports several STL-compatible container and iterator types,
but works best with Qt containers that have random-access iterators, such as
QList or QVector. The map and filter functions accept both containers and begin/end iterators.
STL Iterator support overview:
\table
\header
\li Iterator Type
\li Example classes
\li Support status
\row
\li Input Iterator
\li
\li Not Supported
\row
\li Output Iterator
\li
\li Not Supported
\row
\li Forward Iterator
\li std::slist
\li Supported
\row
\li Bidirectional Iterator
\li QLinkedList, std::list
\li Supported
\row
\li Random Access Iterator
\li QList, QVector, std::vector
\li Supported and Recommended
\endtable
Random access iterators can be faster in cases where Qt Concurrent is iterating
over a large number of lightweight items, since they allow skipping to any point
in the container. In addition, using random access iterators allows Qt Concurrent
to provide progress information trough QFuture::progressValue() and QFutureWatcher::
progressValueChanged().
The non in-place modifying functions such as mapped() and filtered() makes a
copy of the container when called. If you are using STL containers this copy operation
might take some time, in this case we recommend specifying the begin and end iterators
for the container instead.
*/
/*! /*!
\page threads-modules.html \page threads-modules.html
\title Thread-Support in Qt Modules \title Thread-Support in Qt Modules
\previouspage Concurrent Programming \previouspage Threads and QObjects
\contentspage Thread Support in Qt \contentspage Thread Support in Qt
\section1 Threads and the SQL Module \section1 Threads and the SQL Module

View File

@ -365,11 +365,11 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
// qDebug() << "inotify event, wd" << event.wd << "mask" << hex << event.mask; // qDebug() << "inotify event, wd" << event.wd << "mask" << hex << event.mask;
int id = event.wd; int id = event.wd;
QString path = idToPath.value(id); QString path = getPathFromID(id);
if (path.isEmpty()) { if (path.isEmpty()) {
// perhaps a directory? // perhaps a directory?
id = -id; id = -id;
path = idToPath.value(id); path = getPathFromID(id);
if (path.isEmpty()) if (path.isEmpty())
continue; continue;
} }
@ -378,8 +378,9 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) { if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) {
pathToID.remove(path); pathToID.remove(path);
idToPath.remove(id); idToPath.remove(id, getPathFromID(id));
inotify_rm_watch(inotifyFd, event.wd); if (!idToPath.contains(id))
inotify_rm_watch(inotifyFd, event.wd);
if (id < 0) if (id < 0)
emit directoryChanged(path, true); emit directoryChanged(path, true);
@ -394,6 +395,18 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
} }
} }
QString QInotifyFileSystemWatcherEngine::getPathFromID(int id) const
{
QHash<int, QString>::const_iterator i = idToPath.find(id);
while (i != idToPath.constEnd() && i.key() == id) {
if ((i + 1) == idToPath.constEnd() || (i + 1).key() != id) {
return i.value();
}
++i;
}
return QString();
}
QT_END_NAMESPACE QT_END_NAMESPACE
#endif // QT_NO_FILESYSTEMWATCHER #endif // QT_NO_FILESYSTEMWATCHER

View File

@ -78,11 +78,14 @@ public:
private Q_SLOTS: private Q_SLOTS:
void readFromInotify(); void readFromInotify();
private:
QString getPathFromID(int id) const;
private: private:
QInotifyFileSystemWatcherEngine(int fd, QObject *parent); QInotifyFileSystemWatcherEngine(int fd, QObject *parent);
int inotifyFd; int inotifyFd;
QHash<QString, int> pathToID; QHash<QString, int> pathToID;
QHash<int, QString> idToPath; QMultiHash<int, QString> idToPath;
QSocketNotifier notifier; QSocketNotifier notifier;
}; };

View File

@ -121,17 +121,33 @@ static const int errorBufferMax = 512;
static int qt_qprocess_deadChild_pipe[2]; static int qt_qprocess_deadChild_pipe[2];
static struct sigaction qt_sa_old_sigchld_handler; static struct sigaction qt_sa_old_sigchld_handler;
static void qt_sa_sigchld_handler(int signum) static void qt_sa_sigchld_sigaction(int signum, siginfo_t *info, void *context)
{ {
// *Never* use the info or contect variables in this function
// (except for passing them to the next signal in the chain).
// We cannot be sure if another library or if the application
// installed a signal handler for SIGCHLD without SA_SIGINFO
// and fails to pass the arguments to us. If they do that,
// these arguments contain garbage and we'd most likely crash.
qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1); qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1);
#if defined (QPROCESS_DEBUG) #if defined (QPROCESS_DEBUG)
fprintf(stderr, "*** SIGCHLD\n"); fprintf(stderr, "*** SIGCHLD\n");
#endif #endif
// load it as volatile // load as volatile
void (*oldAction)(int) = ((volatile struct sigaction *)&qt_sa_old_sigchld_handler)->sa_handler; volatile struct sigaction *vsa = &qt_sa_old_sigchld_handler;
if (oldAction && oldAction != SIG_IGN)
oldAction(signum); if (qt_sa_old_sigchld_handler.sa_flags & SA_SIGINFO) {
void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction;
oldAction(signum, info, context);
} else {
void (*oldAction)(int) = vsa->sa_handler;
if (oldAction && oldAction != SIG_IGN)
oldAction(signum);
}
} }
static inline void add_fd(int &nfds, int fd, fd_set *fdset) static inline void add_fd(int &nfds, int fd, fd_set *fdset)
@ -197,10 +213,16 @@ QProcessManager::QProcessManager()
// set up the SIGCHLD handler, which writes a single byte to the dead // set up the SIGCHLD handler, which writes a single byte to the dead
// child pipe every time a child dies. // child pipe every time a child dies.
struct sigaction action; struct sigaction action;
memset(&action, 0, sizeof(action)); // use the old handler as template, i.e., preserve the signal mask
action.sa_handler = qt_sa_sigchld_handler; // otherwise the original signal handler might be interrupted although it
action.sa_flags = SA_NOCLDSTOP; // was marked to never be interrupted
::sigaction(SIGCHLD, NULL, &action);
action.sa_sigaction = qt_sa_sigchld_sigaction;
// set the SA_SIGINFO flag such that we can use the three argument handler
// function
action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler); ::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler);
processManagerInstance = this; processManagerInstance = this;
@ -225,7 +247,7 @@ QProcessManager::~QProcessManager()
struct sigaction currentAction; struct sigaction currentAction;
::sigaction(SIGCHLD, 0, &currentAction); ::sigaction(SIGCHLD, 0, &currentAction);
if (currentAction.sa_handler == qt_sa_sigchld_handler) { if (currentAction.sa_sigaction == qt_sa_sigchld_sigaction) {
::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0); ::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0);
} }

View File

@ -47,8 +47,7 @@
\ingroup thread \ingroup thread
To start a computation, use one of the APIs in the To start a computation, use one of the APIs in the \l {Qt Concurrent} framework.
\l {Concurrent Programming}{Qt Concurrent} framework.
QFuture allows threads to be synchronized against one or more results QFuture allows threads to be synchronized against one or more results
which will be ready at a later point in time. The result can be of any type which will be ready at a later point in time. The result can be of any type
@ -93,7 +92,7 @@
To interact with running tasks using signals and slots, use QFutureWatcher. To interact with running tasks using signals and slots, use QFutureWatcher.
\sa QFutureWatcher, {Concurrent Programming}{Qt Concurrent} \sa QFutureWatcher, {Qt Concurrent}
*/ */
/*! \fn QFuture::QFuture() /*! \fn QFuture::QFuture()

View File

@ -66,7 +66,7 @@
You can query the status of the cancel-on-wait feature using the You can query the status of the cancel-on-wait feature using the
cancelOnWait() function. cancelOnWait() function.
\sa QFuture, QFutureWatcher, {Concurrent Programming}{Qt Concurrent} \sa QFuture, QFutureWatcher, {Qt Concurrent}
*/ */
/*! /*!

View File

@ -98,7 +98,7 @@ QT_BEGIN_NAMESPACE
QFutureWatcher<void> as well. This is useful if only status or progress QFutureWatcher<void> as well. This is useful if only status or progress
information is needed; not the actual result data. information is needed; not the actual result data.
\sa QFuture, {Concurrent Programming}{Qt Concurrent} \sa QFuture, {Qt Concurrent}
*/ */
/*! \fn QFutureWatcher::QFutureWatcher(QObject *parent) /*! \fn QFutureWatcher::QFutureWatcher(QObject *parent)

View File

@ -1,5 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal ** Contact: http://www.qt-project.org/legal
** **
@ -280,6 +281,15 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal
image.setColorCount(2); image.setColorCount(2);
image.setColor(1, qRgb(0,0,0)); image.setColor(1, qRgb(0,0,0));
image.setColor(0, qRgb(255,255,255)); image.setColor(0, qRgb(255,255,255));
if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
const int g = trans_color_p->gray;
// the image has white in the first position of the color table,
// black in the second. g is 0 for black, 1 for white.
if (g == 0)
image.setColor(1, qRgba(0, 0, 0, 0));
else if (g == 1)
image.setColor(0, qRgba(255, 255, 255, 0));
}
} else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_expand(png_ptr); png_set_expand(png_ptr);
png_set_strip_16(png_ptr); png_set_strip_16(png_ptr);
@ -406,14 +416,14 @@ static void read_image_scaled(QImage *outImage, png_structp png_ptr, png_infop i
QPngHandlerPrivate::AllocatedMemoryPointers &amp, QSize scaledSize) QPngHandlerPrivate::AllocatedMemoryPointers &amp, QSize scaledSize)
{ {
png_uint_32 width; png_uint_32 width = 0;
png_uint_32 height; png_uint_32 height = 0;
png_int_32 offset_x; png_int_32 offset_x = 0;
png_int_32 offset_y; png_int_32 offset_y = 0;
int bit_depth; int bit_depth = 0;
int color_type; int color_type = 0;
int unit_type; int unit_type = PNG_OFFSET_PIXEL;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type); png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type);
uchar *data = outImage->bits(); uchar *data = outImage->bits();

View File

@ -2293,13 +2293,30 @@ bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
return qFuzzyCompare(xScale, yScale); return qFuzzyCompare(xScale, yScale);
} }
const qreal xScale = transform.m11() * transform.m11() // rotate then scale: compare columns
const qreal xScale1 = transform.m11() * transform.m11()
+ transform.m21() * transform.m21(); + transform.m21() * transform.m21();
const qreal yScale = transform.m12() * transform.m12() const qreal yScale1 = transform.m12() * transform.m12()
+ transform.m22() * transform.m22(); + transform.m22() * transform.m22();
if (scale)
*scale = qSqrt(qMax(xScale, yScale)); // scale then rotate: compare rows
return type == QTransform::TxRotate && qFuzzyCompare(xScale, yScale); const qreal xScale2 = transform.m11() * transform.m11()
+ transform.m12() * transform.m12();
const qreal yScale2 = transform.m21() * transform.m21()
+ transform.m22() * transform.m22();
// decide the order of rotate and scale operations
if (qAbs(xScale1 - yScale1) > qAbs(xScale2 - yScale2)) {
if (scale)
*scale = qSqrt(qMax(xScale1, yScale1));
return type == QTransform::TxRotate && qFuzzyCompare(xScale1, yScale1);
} else {
if (scale)
*scale = qSqrt(qMax(xScale2, yScale2));
return type == QTransform::TxRotate && qFuzzyCompare(xScale2, yScale2);
}
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -509,7 +509,7 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
// Send "Authorization" header, but not if it's NTLM and the socket is already authenticated. // Send "Authorization" header, but not if it's NTLM and the socket is already authenticated.
if (channels[i].authMethod != QAuthenticatorPrivate::None) { if (channels[i].authMethod != QAuthenticatorPrivate::None) {
if (!(channels[i].authMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 401)) { if ((channels[i].authMethod != QAuthenticatorPrivate::Ntlm && request.headerField("Authorization").isEmpty()) || channels[i].lastStatus == 401) {
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator); QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator);
if (priv && priv->method != QAuthenticatorPrivate::None) { if (priv && priv->method != QAuthenticatorPrivate::None) {
QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false)); QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false));

View File

@ -236,8 +236,8 @@ bool QHttpNetworkConnectionChannel::sendRequest()
QAuthenticator &auth = authenticator; QAuthenticator &auth = authenticator;
if (url.userName() != auth.user() if (url.userName() != auth.user()
|| (!url.password().isEmpty() && url.password() != auth.password())) { || (!url.password().isEmpty() && url.password() != auth.password())) {
auth.setUser(url.userName()); auth.setUser(url.userName(QUrl::FullyDecoded));
auth.setPassword(url.password()); auth.setPassword(url.password(QUrl::FullyDecoded));
connection->d_func()->copyCredentials(connection->d_func()->indexOf(socket), &auth, false); connection->d_func()->copyCredentials(connection->d_func()->indexOf(socket), &auth, false);
} }
// clear the userinfo, since we use the same request for resending // clear the userinfo, since we use the same request for resending

View File

@ -1358,8 +1358,8 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authen
// if credentials are included in the url, then use them // if credentials are included in the url, then use them
if (!url.userName().isEmpty() if (!url.userName().isEmpty()
&& !url.password().isEmpty()) { && !url.password().isEmpty()) {
authenticator->setUser(url.userName()); authenticator->setUser(url.userName(QUrl::FullyDecoded));
authenticator->setPassword(url.password()); authenticator->setPassword(url.password(QUrl::FullyDecoded));
*urlForLastAuthentication = url; *urlForLastAuthentication = url;
authenticationManager->cacheCredentials(url, authenticator); authenticationManager->cacheCredentials(url, authenticator);
return; return;

View File

@ -115,7 +115,7 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec
QToolButton *tb = qobject_cast<QToolButton*>(widget); QToolButton *tb = qobject_cast<QToolButton*>(widget);
if (!tb->menu()) if (!tb->menu())
role = tb->isCheckable() ? QAccessible::CheckBox : QAccessible::PushButton; role = tb->isCheckable() ? QAccessible::CheckBox : QAccessible::PushButton;
else if (!tb->popupMode() != QToolButton::DelayedPopup) else if (tb->popupMode() == QToolButton::DelayedPopup)
role = QAccessible::ButtonDropDown; role = QAccessible::ButtonDropDown;
else else
#endif #endif

View File

@ -125,7 +125,7 @@ public:
QList<int> possibleKeys(const QKeyEvent *event) const; QList<int> possibleKeys(const QKeyEvent *event) const;
void updateScreens(); void updateScreens();
QCocoaScreen *screenAtIndex(int index) const { return mScreens.at(index); } QCocoaScreen *screenAtIndex(int index);
private: private:

View File

@ -343,6 +343,14 @@ void QCocoaIntegration::updateScreens()
screen->setVirtualSiblings(siblings); screen->setVirtualSiblings(siblings);
} }
QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
{
if (index >= mScreens.count())
updateScreens();
return mScreens.at(index);
}
bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{ {
switch (cap) { switch (cap) {

View File

@ -157,12 +157,122 @@ private:
QByteArray format_atoms; QByteArray format_atoms;
}; };
class INCRTransaction;
typedef QMap<xcb_window_t,INCRTransaction*> TransactionMap;
static TransactionMap *transactions = 0;
//#define INCR_DEBUG
class INCRTransaction : public QObject
{
Q_OBJECT
public:
INCRTransaction(QXcbConnection *c, xcb_window_t w, xcb_atom_t p,
QByteArray d, uint i, xcb_atom_t t, int f, int to) :
conn(c), win(w), property(p), data(d), increment(i),
target(t), format(f), timeout(to), offset(0)
{
const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
xcb_change_window_attributes(conn->xcb_connection(), win,
XCB_CW_EVENT_MASK, values);
if (!transactions) {
#ifdef INCR_DEBUG
qDebug("INCRTransaction: creating the TransactionMap");
#endif
transactions = new TransactionMap;
conn->clipboard()->setProcessIncr(true);
}
transactions->insert(win, this);
abort_timer = startTimer(timeout);
}
~INCRTransaction()
{
if (abort_timer)
killTimer(abort_timer);
abort_timer = 0;
transactions->remove(win);
if (transactions->isEmpty()) {
#ifdef INCR_DEBUG
qDebug("INCRTransaction: no more INCR transactions left in the TransactionMap");
#endif
delete transactions;
transactions = 0;
conn->clipboard()->setProcessIncr(false);
}
}
void updateIncrProperty(xcb_property_notify_event_t *event, bool &accepted)
{
xcb_connection_t *c = conn->xcb_connection();
if (event->atom == property && event->state == XCB_PROPERTY_DELETE) {
accepted = true;
// restart the timer
if (abort_timer)
killTimer(abort_timer);
abort_timer = startTimer(timeout);
unsigned int bytes_left = data.size() - offset;
if (bytes_left > 0) {
unsigned int bytes_to_send = qMin(increment, bytes_left);
#ifdef INCR_DEBUG
qDebug("INCRTransaction: sending %d bytes, %d remaining (INCR transaction %p)",
bytes_to_send, bytes_left - bytes_to_send, this);
#endif
int dataSize = bytes_to_send / (format / 8);
xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property,
target, format, dataSize, data.constData() + offset);
offset += bytes_to_send;
} else {
#ifdef INCR_DEBUG
qDebug("INCRTransaction: INCR transaction %p completed", this);
#endif
xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property,
target, format, 0, (const void *)0);
const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT };
xcb_change_window_attributes(conn->xcb_connection(), win,
XCB_CW_EVENT_MASK, values);
// self destroy
delete this;
}
}
}
protected:
void timerEvent(QTimerEvent *ev)
{
if (ev->timerId() == abort_timer) {
// this can happen when the X client we are sending data
// to decides to exit (normally or abnormally)
#ifdef INCR_DEBUG
qDebug("INCRTransaction: Timed out while sending data to %p", this);
#endif
delete this;
}
}
private:
QXcbConnection *conn;
xcb_window_t win;
xcb_atom_t property;
QByteArray data;
uint increment;
xcb_atom_t target;
int format;
int timeout;
uint offset;
int abort_timer;
};
const int QXcbClipboard::clipboard_timeout = 5000; const int QXcbClipboard::clipboard_timeout = 5000;
QXcbClipboard::QXcbClipboard(QXcbConnection *c) QXcbClipboard::QXcbClipboard(QXcbConnection *c)
: QXcbObject(c), QPlatformClipboard() : QXcbObject(c), QPlatformClipboard()
, m_requestor(XCB_NONE) , m_requestor(XCB_NONE)
, m_owner(XCB_NONE) , m_owner(XCB_NONE)
, m_incr_active(false)
, m_clipboard_closing(false)
, m_incr_receive_time(0)
{ {
Q_ASSERT(QClipboard::Clipboard == 0); Q_ASSERT(QClipboard::Clipboard == 0);
Q_ASSERT(QClipboard::Selection == 1); Q_ASSERT(QClipboard::Selection == 1);
@ -200,6 +310,7 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
QXcbClipboard::~QXcbClipboard() QXcbClipboard::~QXcbClipboard()
{ {
m_clipboard_closing = true;
// Transfer the clipboard content to the clipboard manager if we own a selection // Transfer the clipboard content to the clipboard manager if we own a selection
if (m_timestamp[QClipboard::Clipboard] != XCB_CURRENT_TIME || if (m_timestamp[QClipboard::Clipboard] != XCB_CURRENT_TIME ||
m_timestamp[QClipboard::Selection] != XCB_CURRENT_TIME) { m_timestamp[QClipboard::Selection] != XCB_CURRENT_TIME) {
@ -224,6 +335,17 @@ QXcbClipboard::~QXcbClipboard()
} }
} }
void QXcbClipboard::incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted)
{
uint response_type = ge->response_type & ~0x80;
if (response_type == XCB_PROPERTY_NOTIFY) {
xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge;
TransactionMap::Iterator it = transactions->find(event->window);
if (it != transactions->end()) {
(*it)->updateIncrProperty(event, accepted);
}
}
}
xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const
{ {
@ -415,16 +537,17 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win
// Motif clients (since Motif doesn't support INCR) // Motif clients (since Motif doesn't support INCR)
static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::CLIP_TEMPORARY); static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::CLIP_TEMPORARY);
bool allow_incr = property != motif_clip_temporary; bool allow_incr = property != motif_clip_temporary;
// This 'bool' can be removed once there is a proper fix for QTBUG-32853
if (m_clipboard_closing)
allow_incr = false;
// X_ChangeProperty protocol request is 24 bytes // X_ChangeProperty protocol request is 24 bytes
const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24;
if (data.size() > increment && allow_incr) { if (data.size() > increment && allow_incr) {
long bytes = data.size(); long bytes = data.size();
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property,
atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes);
new INCRTransaction(connection(), window, property, data, increment,
// (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment); atomFormat, dataFormat, clipboard_timeout);
qWarning("QXcbClipboard: INCR is unimplemented");
return property; return property;
} }
@ -611,7 +734,7 @@ static inline int maxSelectionIncr(xcb_connection_t *c)
return (l > 65536 ? 65536*4 : l*4) - 100; return (l > 65536 ? 65536*4 : l*4) - 100;
} }
bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format)
{ {
int maxsize = maxSelectionIncr(xcb_connection()); int maxsize = maxSelectionIncr(xcb_connection());
ulong bytes_left; // bytes_after ulong bytes_left; // bytes_after
@ -687,7 +810,8 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property,
// correct size, not 0-term. // correct size, not 0-term.
if (size) if (size)
*size = buffer_offset; *size = buffer_offset;
if (*type == atom(QXcbAtom::INCR))
m_incr_receive_time = connection()->getTimestamp();
if (deleteProperty) if (deleteProperty)
xcb_delete_property(xcb_connection(), win, property); xcb_delete_property(xcb_connection(), win, property);
@ -791,6 +915,7 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
bool alloc_error = false; bool alloc_error = false;
int length; int length;
int offset = 0; int offset = 0;
xcb_timestamp_t prev_time = m_incr_receive_time;
if (nbytes > 0) { if (nbytes > 0) {
// Reserve buffer + zero-terminator (for text data) // Reserve buffer + zero-terminator (for text data)
@ -805,10 +930,14 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout); xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout);
if (!ge) if (!ge)
break; break;
xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge;
if (event->atom != property || event->state != XCB_PROPERTY_NEW_VALUE)
if (event->atom != property
|| event->state != XCB_PROPERTY_NEW_VALUE
|| event->time < prev_time)
continue; continue;
prev_time = event->time;
if (clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) { if (clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) {
if (length == 0) { // no more data, we're done if (length == 0) { // no more data, we're done
if (nullterm) { if (nullterm) {

View File

@ -78,11 +78,15 @@ public:
void handleSelectionClearRequest(xcb_selection_clear_event_t *event); void handleSelectionClearRequest(xcb_selection_clear_event_t *event);
void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event); void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event);
bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const; bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format);
QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm); QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm);
QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom); QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom);
void setProcessIncr(bool process) { m_incr_active = process; }
bool processIncr() { return m_incr_active; }
void incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted);
xcb_window_t getSelectionOwner(xcb_atom_t atom) const; xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0); QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0);
@ -107,6 +111,9 @@ private:
static const int clipboard_timeout; static const int clipboard_timeout;
bool m_incr_active;
bool m_clipboard_closing;
xcb_timestamp_t m_incr_receive_time;
}; };
#endif // QT_NO_CLIPBOARD #endif // QT_NO_CLIPBOARD

View File

@ -1164,6 +1164,12 @@ void QXcbConnection::processXcbEvents()
continue; continue;
} }
bool accepted = false;
if (clipboard()->processIncr())
clipboard()->incrTransactionPeeker(event, accepted);
if (accepted)
continue;
QVector<PeekFunc>::iterator it = m_peekFuncs.begin(); QVector<PeekFunc>::iterator it = m_peekFuncs.begin();
while (it != m_peekFuncs.end()) { while (it != m_peekFuncs.end()) {
// These callbacks return true if the event is what they were // These callbacks return true if the event is what they were

View File

@ -648,7 +648,6 @@ void QXcbWindow::show()
if (!transientXcbParent) if (!transientXcbParent)
transientXcbParent = static_cast<QXcbScreen *>(screen())->clientLeader(); transientXcbParent = static_cast<QXcbScreen *>(screen())->clientLeader();
if (transientXcbParent) { // ICCCM 4.1.2.6 if (transientXcbParent) { // ICCCM 4.1.2.6
m_gravity = XCB_GRAVITY_CENTER;
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
1, &transientXcbParent)); 1, &transientXcbParent));
@ -1304,9 +1303,6 @@ QRect QXcbWindow::windowToWmGeometry(QRect r) const
r.translate(m_frameMargins.left(), m_frameMargins.top()); r.translate(m_frameMargins.left(), m_frameMargins.top());
} else if (!frameInclusive && m_gravity == XCB_GRAVITY_NORTH_WEST) { } else if (!frameInclusive && m_gravity == XCB_GRAVITY_NORTH_WEST) {
r.translate(-m_frameMargins.left(), -m_frameMargins.top()); r.translate(-m_frameMargins.left(), -m_frameMargins.top());
} else if (!frameInclusive && m_gravity == XCB_GRAVITY_CENTER) {
r.translate(-(m_frameMargins.left() - m_frameMargins.right())/2,
-(m_frameMargins.top() - m_frameMargins.bottom())/2);
} }
return r; return r;
} }

View File

@ -197,7 +197,7 @@ void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality)
// close down during the cleanup (QTBUG-17913): // close down during the cleanup (QTBUG-17913):
qApp->processEvents(QEventLoop::ExcludeUserInputEvents, QEventLoop::ExcludeSocketNotifiers); qApp->processEvents(QEventLoop::ExcludeUserInputEvents, QEventLoop::ExcludeSocketNotifiers);
QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) alloc] init]; QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) alloc] initWithNSPrintInfo:printInfo];
if (modality == Qt::ApplicationModal || !q->parentWidget()) { if (modality == Qt::ApplicationModal || !q->parentWidget()) {
if (modality == Qt::NonModal) if (modality == Qt::NonModal)
qWarning("QPrintDialog is required to be modal on OS X"); qWarning("QPrintDialog is required to be modal on OS X");

View File

@ -52,12 +52,12 @@ if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*")==0) {
//! [1] //! [1]
if (v.typeName() == "PGconn*") { if (qstrcmp(v.typeName(), "PGconn*")) {
PGconn *handle = *static_cast<PGconn **>(v.data()); PGconn *handle = *static_cast<PGconn **>(v.data());
if (handle != 0) ... if (handle != 0) ...
} }
if (v.typeName() == "MYSQL*") { if (qstrcmp(v.typeName(), "MYSQL*")) {
MYSQL *handle = *static_cast<MYSQL **>(v.data()); MYSQL *handle = *static_cast<MYSQL **>(v.data());
if (handle != 0) ... if (handle != 0) ...
} }

View File

@ -79,6 +79,8 @@ private slots:
void QTBUG2331(); void QTBUG2331();
void QTBUG2331_data() { basicTest_data(); } void QTBUG2331_data() { basicTest_data(); }
void signalsEmittedAfterFileMoved();
private: private:
QString m_tempDirPattern; QString m_tempDirPattern;
}; };
@ -596,5 +598,84 @@ void tst_QFileSystemWatcher::QTBUG2331()
QCOMPARE(watcher.directories(), QStringList()); QCOMPARE(watcher.directories(), QStringList());
} }
class SignalReceiver : public QObject
{
Q_OBJECT
public:
SignalReceiver(const QDir &moveSrcDir,
const QString &moveDestination,
QFileSystemWatcher *watcher,
QObject *parent = 0)
: QObject(parent),
added(false),
moveSrcDir(moveSrcDir),
moveDestination(QDir(moveDestination)),
watcher(watcher)
{}
public slots:
void fileChanged(const QString &path)
{
QFileInfo finfo(path);
QCOMPARE(finfo.absolutePath(), moveSrcDir.absolutePath());
if (!added) {
foreach (const QFileInfo &fi, moveDestination.entryInfoList(QDir::Files | QDir::NoSymLinks))
watcher->addPath(fi.absoluteFilePath());
added = true;
}
}
private:
bool added;
QDir moveSrcDir;
QDir moveDestination;
QFileSystemWatcher *watcher;
};
// regression test for QTBUG-33211.
// using inotify backend if a file is moved and then added to the watcher
// before all the fileChanged signals are emitted the remaining signals are
// emitted with the destination path instead of the starting path
void tst_QFileSystemWatcher::signalsEmittedAfterFileMoved()
{
QTemporaryDir temporaryDirectory(m_tempDirPattern);
QVERIFY(temporaryDirectory.isValid());
QDir testDir(temporaryDirectory.path());
QVERIFY(testDir.mkdir("movehere"));
QString movePath = testDir.filePath("movehere");
for (int i = 0; i < 10; i++) {
QFile f(testDir.filePath(QString("test%1.txt").arg(i)));
QVERIFY(f.open(QIODevice::WriteOnly));
f.write(QByteArray("i am " + i));
f.close();
}
QFileSystemWatcher watcher;
QVERIFY(watcher.addPath(testDir.path()));
QVERIFY(watcher.addPath(movePath));
// add files to watcher
QFileInfoList files = testDir.entryInfoList(QDir::Files | QDir::NoSymLinks);
foreach (const QFileInfo &finfo, files)
QVERIFY(watcher.addPath(finfo.absoluteFilePath()));
// create the signal receiver
SignalReceiver signalReceiver(testDir, movePath, &watcher);
connect(&watcher, SIGNAL(fileChanged(QString)), &signalReceiver, SLOT(fileChanged(QString)));
// watch signals
QSignalSpy changedSpy(&watcher, SIGNAL(fileChanged(QString)));
QVERIFY(changedSpy.isValid());
// move files to second directory
foreach (const QFileInfo &finfo, files)
QVERIFY(testDir.rename(finfo.fileName(), QString("movehere/%2").arg(finfo.fileName())));
QTRY_COMPARE(changedSpy.count(), 10);
}
QTEST_MAIN(tst_QFileSystemWatcher) QTEST_MAIN(tst_QFileSystemWatcher)
#include "tst_qfilesystemwatcher.moc" #include "tst_qfilesystemwatcher.moc"

View File

@ -1587,6 +1587,8 @@ void tst_QTextLayout::testTabDPIScale()
case QPaintDevice::PdmPhysicalDpiX: case QPaintDevice::PdmPhysicalDpiX:
case QPaintDevice::PdmPhysicalDpiY: case QPaintDevice::PdmPhysicalDpiY:
return 72; return 72;
case QPaintDevice::PdmDevicePixelRatio:
; // fall through
} }
return 0; return 0;
} }

View File

@ -114,6 +114,7 @@ private slots:
void about(); void about();
void detailsText(); void detailsText();
void detailsButtonText(); void detailsButtonText();
void expandDetails_QTBUG_32473();
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
void shortcut(); void shortcut();
@ -137,6 +138,19 @@ private:
QTimer keySendTimer; QTimer keySendTimer;
}; };
class tst_ResizingMessageBox : public QMessageBox
{
public:
tst_ResizingMessageBox() : QMessageBox(), resized(false) { }
bool resized;
protected:
void resizeEvent ( QResizeEvent * event ) {
resized = true;
QMessageBox::resizeEvent(event);
}
};
tst_QMessageBox::tst_QMessageBox() : keyToSend(-1) tst_QMessageBox::tst_QMessageBox() : keyToSend(-1)
{ {
} }
@ -603,6 +617,37 @@ void tst_QMessageBox::detailsButtonText()
} }
} }
void tst_QMessageBox::expandDetails_QTBUG_32473()
{
tst_ResizingMessageBox box;
box.setDetailedText("bla");
box.show();
QApplication::postEvent(&box, new QEvent(QEvent::LanguageChange));
QApplication::processEvents();
QDialogButtonBox* bb = box.findChild<QDialogButtonBox*>("qt_msgbox_buttonbox");
QVERIFY(bb);
QList<QAbstractButton *> list = bb->buttons();
QAbstractButton* moreButton = NULL;
foreach (QAbstractButton* btn, list)
if (btn && bb->buttonRole(btn) == QDialogButtonBox::ActionRole)
moreButton = btn;
QVERIFY(moreButton);
QVERIFY(QTest::qWaitForWindowExposed(&box));
QRect geom = box.geometry();
box.resized = false;
moreButton->click();
QTRY_VERIFY(box.resized);
// After we receive the expose event for a second widget, it's likely
// that the window manager is also done manipulating the first QMessageBox.
QWidget fleece;
fleece.show();
QTest::qWaitForWindowExposed(&fleece);
if (geom.topLeft() == box.geometry().topLeft())
QTest::qWait(500);
QCOMPARE(geom.topLeft(), box.geometry().topLeft());
}
void tst_QMessageBox::incorrectDefaultButton() void tst_QMessageBox::incorrectDefaultButton()
{ {
keyToSend = Qt::Key_Escape; keyToSend = Qt::Key_Escape;