summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Boddie <dboddie@trolltech.com>2009-07-13 11:49:08 (GMT)
committerDavid Boddie <dboddie@trolltech.com>2009-07-13 11:49:08 (GMT)
commit821c7c1486beb6d5e65bd3ac8ba74752fec37fe8 (patch)
tree042ad778ccdfacd2dc1b4751a98e83889e5e10e3 /src
parent85fbffa12bcd38b08030561335305c3226312bc6 (diff)
parentcc24c46c117248ecb98200416e7f25375e6bb476 (diff)
downloadQt-821c7c1486beb6d5e65bd3ac8ba74752fec37fe8.zip
Qt-821c7c1486beb6d5e65bd3ac8ba74752fec37fe8.tar.gz
Qt-821c7c1486beb6d5e65bd3ac8ba74752fec37fe8.tar.bz2
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/phonon/ds9/videowidget.cpp2
-rw-r--r--src/corelib/animation/qpropertyanimation.cpp18
-rw-r--r--src/corelib/codecs/qiconvcodec.cpp6
-rw-r--r--src/corelib/global/qglobal.h2
-rw-r--r--src/corelib/io/qbuffer.cpp2
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.cpp25
-rw-r--r--src/corelib/kernel/qcore_unix_p.h7
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp42
-rw-r--r--src/corelib/plugin/qplugin.h19
-rw-r--r--src/corelib/thread/qthread.cpp11
-rw-r--r--src/corelib/tools/qringbuffer_p.h5
-rw-r--r--src/corelib/tools/qstring.h2
-rw-r--r--src/corelib/tools/qstringbuilder.h14
-rw-r--r--src/dbus/qdbusconnection.cpp7
-rw-r--r--src/gui/dialogs/qfiledialog_p.h1
-rw-r--r--src/gui/dialogs/qsidebar.cpp13
-rw-r--r--src/gui/graphicsview/graphicsview.pri51
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp211
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h53
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h61
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp1743
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h40
-rw-r--r--src/gui/graphicsview/qgraphicsscene_bsp.cpp56
-rw-r--r--src/gui/graphicsview/qgraphicsscene_bsp_p.h9
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h127
-rw-r--r--src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp782
-rw-r--r--src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h213
-rw-r--r--src/gui/graphicsview/qgraphicssceneindex.cpp659
-rw-r--r--src/gui/graphicsview/qgraphicssceneindex_p.h182
-rw-r--r--src/gui/graphicsview/qgraphicsscenelinearindex.cpp62
-rw-r--r--src/gui/graphicsview/qgraphicsscenelinearindex_p.h109
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp216
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h10
-rw-r--r--src/gui/itemviews/qabstractitemview.cpp50
-rw-r--r--src/gui/itemviews/qabstractitemview_p.h11
-rw-r--r--src/gui/itemviews/qitemselectionmodel.cpp35
-rw-r--r--src/gui/itemviews/qlistview.cpp146
-rw-r--r--src/gui/itemviews/qlistview_p.h24
-rw-r--r--src/gui/itemviews/qtableview.cpp8
-rw-r--r--src/gui/itemviews/qtreeview.cpp140
-rw-r--r--src/gui/itemviews/qtreeview.h5
-rw-r--r--src/gui/itemviews/qtreeview_p.h36
-rw-r--r--src/gui/kernel/qapplication.cpp9
-rw-r--r--src/gui/kernel/qapplication_mac.mm12
-rw-r--r--src/gui/kernel/qapplication_p.h10
-rw-r--r--src/gui/kernel/qapplication_win.cpp49
-rw-r--r--src/gui/kernel/qcocoapanel_mac.mm6
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm116
-rw-r--r--src/gui/kernel/qcocoaview_mac_p.h4
-rw-r--r--src/gui/kernel/qcocoawindow_mac.mm6
-rw-r--r--src/gui/kernel/qmultitouch_mac.mm6
-rw-r--r--src/gui/kernel/qmultitouch_mac_p.h4
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac.mm34
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac_p.h3
-rw-r--r--src/gui/kernel/qt_mac.cpp6
-rw-r--r--src/gui/kernel/qwidget.cpp12
-rw-r--r--src/gui/kernel/qwidget_mac.mm10
-rw-r--r--src/gui/math3d/qgenericmatrix.h4
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp7
-rw-r--r--src/gui/math3d/qquaternion.cpp4
-rw-r--r--src/gui/math3d/qvector2d.cpp4
-rw-r--r--src/gui/math3d/qvector3d.cpp4
-rw-r--r--src/gui/math3d/qvector4d.cpp4
-rw-r--r--src/gui/text/qsyntaxhighlighter.cpp40
-rw-r--r--src/gui/text/qsyntaxhighlighter.h1
-rw-r--r--src/gui/widgets/qabstractscrollarea_p.h2
-rw-r--r--src/gui/widgets/qabstractspinbox.cpp2
-rw-r--r--src/gui/widgets/qdockarealayout.cpp2
-rw-r--r--src/gui/widgets/qeffects.cpp3
-rw-r--r--src/gui/widgets/qgroupbox.cpp6
-rw-r--r--src/gui/widgets/qmainwindow.cpp13
-rw-r--r--src/gui/widgets/qmainwindowlayout.cpp81
-rw-r--r--src/gui/widgets/qmainwindowlayout_mac.mm31
-rw-r--r--src/gui/widgets/qmainwindowlayout_p.h2
-rw-r--r--src/gui/widgets/qprogressbar.cpp2
-rw-r--r--src/gui/widgets/qspinbox.cpp7
-rw-r--r--src/gui/widgets/qtabbar.cpp66
-rw-r--r--src/gui/widgets/qtabbar.h2
-rw-r--r--src/gui/widgets/qtabbar_p.h68
-rw-r--r--src/gui/widgets/qtoolbar.cpp29
-rw-r--r--src/gui/widgets/qwidgetanimator.cpp1
-rw-r--r--src/gui/widgets/qwidgetanimator_p.h1
-rw-r--r--src/network/access/qhttpnetworkreply.cpp6
-rw-r--r--src/network/access/qhttpnetworkreply_p.h1
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp4
-rw-r--r--src/network/kernel/qnetworkproxy.cpp2
-rw-r--r--src/network/socket/qlocalsocket_win.cpp10
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp177
-rw-r--r--src/plugins/kbddrivers/sl5000/main.cpp3
-rw-r--r--src/plugins/kbddrivers/vr41xx/main.cpp3
-rw-r--r--src/plugins/kbddrivers/yopy/main.cpp3
-rw-r--r--src/sql/drivers/oci/qsql_oci.cpp2
-rw-r--r--src/sql/drivers/odbc/qsql_odbc.cpp16
-rw-r--r--src/sql/drivers/psql/qsql_psql.cpp49
-rw-r--r--src/sql/models/qsqltablemodel.cpp3
-rw-r--r--src/svg/qsvghandler.cpp105
-rw-r--r--src/svg/qsvgstyle.cpp14
-rw-r--r--src/svg/qsvgstyle_p.h28
98 files changed, 3850 insertions, 2464 deletions
diff --git a/src/3rdparty/phonon/ds9/videowidget.cpp b/src/3rdparty/phonon/ds9/videowidget.cpp
index 0ef653f..34ff8cb 100644
--- a/src/3rdparty/phonon/ds9/videowidget.cpp
+++ b/src/3rdparty/phonon/ds9/videowidget.cpp
@@ -153,7 +153,7 @@ namespace Phonon
}
} else if (!isEmbedded()) {
m_currentRenderer = m_node->switchRendering(m_currentRenderer);
- setAttribute(Qt::WA_PaintOnScreen, true);
+ setAttribute(Qt::WA_PaintOnScreen, false);
}
}
diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp
index 7526a81..5f224aa 100644
--- a/src/corelib/animation/qpropertyanimation.cpp
+++ b/src/corelib/animation/qpropertyanimation.cpp
@@ -100,10 +100,6 @@
QT_BEGIN_NAMESPACE
-typedef QPair<QObject *, QByteArray> QPropertyAnimationPair;
-typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash;
-Q_GLOBAL_STATIC(QPropertyAnimationHash, _q_runningAnimations)
-
void QPropertyAnimationPrivate::updateMetaProperty()
{
if (!target || propertyName.isEmpty())
@@ -286,19 +282,21 @@ void QPropertyAnimation::updateState(QAbstractAnimation::State oldState,
QPropertyAnimation *animToStop = 0;
{
- QPropertyAnimationHash * hash = _q_runningAnimations();
- QMutexLocker locker(QMutexPool::globalInstanceGet(hash));
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&staticMetaObject));
+ typedef QPair<QObject *, QByteArray> QPropertyAnimationPair;
+ typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash;
+ static QPropertyAnimationHash hash;
QPropertyAnimationPair key(d->target, d->propertyName);
if (newState == Running) {
d->updateMetaProperty();
- animToStop = hash->value(key, 0);
- hash->insert(key, this);
+ animToStop = hash.value(key, 0);
+ hash.insert(key, this);
// update the default start value
if (oldState == Stopped) {
d->setDefaultStartValue(d->target->property(d->propertyName.constData()));
}
- } else if (hash->value(key) == this) {
- hash->remove(key);
+ } else if (hash.value(key) == this) {
+ hash.remove(key);
}
}
diff --git a/src/corelib/codecs/qiconvcodec.cpp b/src/corelib/codecs/qiconvcodec.cpp
index 1bf76ea..188ac8c 100644
--- a/src/corelib/codecs/qiconvcodec.cpp
+++ b/src/corelib/codecs/qiconvcodec.cpp
@@ -225,10 +225,11 @@ QString QIconvCodec::convertToUnicode(const char* chars, int len, ConverterState
char *inBytes = const_cast<char *>(chars);
#endif
+ QByteArray in;
if (remainingCount) {
// we have to prepend the remaining bytes from the previous conversion
inBytesLeft += remainingCount;
- QByteArray in(inBytesLeft, Qt::Uninitialized);
+ in.resize(inBytesLeft);
inBytes = in.data();
memcpy(in.data(), remainingBuffer, remainingCount);
@@ -362,9 +363,10 @@ QByteArray QIconvCodec::convertFromUnicode(const QChar *uc, int len, ConverterSt
inBytes = const_cast<char *>(reinterpret_cast<const char *>(uc));
inBytesLeft = len * sizeof(QChar);
+ QByteArray in;
if (convState && convState->remainingChars) {
// we have one surrogate char to be prepended
- QByteArray in(sizeof(QChar) + len, Qt::Uninitialized);
+ in.resize(sizeof(QChar) + len);
inBytes = in.data();
QChar remaining = convState->state_data[0];
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index a139a55..d6c708c 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -2062,7 +2062,7 @@ public:
inline bool operator!() const { return !i; }
- inline bool testFlag(Enum f) const { return (i & f) == f; }
+ inline bool testFlag(Enum f) const { return (i & f) == f && (f != 0 || i == f ); }
};
#define Q_DECLARE_FLAGS(Flags, Enum)\
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
index aed5b82..3883d30 100644
--- a/src/corelib/io/qbuffer.cpp
+++ b/src/corelib/io/qbuffer.cpp
@@ -452,7 +452,7 @@ qint64 QBuffer::writeData(const char *data, qint64 len)
*/
void QBuffer::connectNotify(const char *signal)
{
- if (strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)"))
+ if (strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)") == 0)
d_func()->signalConnectionCount++;
}
diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp
index a98d005..e2682f5 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.cpp
+++ b/src/corelib/kernel/qabstracteventdispatcher.cpp
@@ -398,20 +398,23 @@ void QAbstractEventDispatcher::closingDown()
*/
/*!
- Sets the event filter \a filter. Returns a pointer to the filter
- function previously defined.
-
- The event filter is a function that receives all messages taken
- from the system event loop before the event is dispatched to the
- respective target. This includes messages that are not sent to Qt
+ Replaces the event filter function for this
+ QAbstractEventDispatcher with \a filter and returns the replaced
+ event filter function. Only the current event filter function is
+ called. If you want to use both filter functions, save the
+ replaced EventFilter in a place where yours can call it.
+
+ The event filter function set here is called for all messages
+ taken from the system event loop before the event is dispatched to
+ the respective target, including the messages not meant for Qt
objects.
- The function can return true to stop the event to be processed by
- Qt, or false to continue with the standard event processing.
+ The event filter function should return true if the message should
+ be filtered, (i.e. stopped). It should return false to allow
+ processing the message to continue.
- Only one filter can be defined, but the filter can use the return
- value to call the previously set event filter. By default, no
- filter is set (i.e. the function returns 0).
+ By default, no event filter function is set (i.e., this function
+ returns a null EventFilter the first time it is called).
*/
QAbstractEventDispatcher::EventFilter QAbstractEventDispatcher::setEventFilter(EventFilter filter)
{
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
index 1bf2425..8d43897 100644
--- a/src/corelib/kernel/qcore_unix_p.h
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -69,19 +69,19 @@
struct sockaddr;
-QT_BEGIN_NAMESPACE
-
#if defined(Q_OS_LINUX) && defined(O_CLOEXEC) && defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0204
// Linux supports thread-safe FD_CLOEXEC
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1
+QT_BEGIN_NAMESPACE
namespace QtLibcSupplement {
Q_CORE_EXPORT int accept4(int, sockaddr *, QT_SOCKLEN_T *, int flags);
Q_CORE_EXPORT int dup3(int oldfd, int newfd, int flags);
Q_CORE_EXPORT int pipe2(int pipes[], int flags);
}
+QT_END_NAMESPACE
+using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement);
-using namespace QtLibcSupplement;
#else
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 0
#endif
@@ -91,6 +91,7 @@ using namespace QtLibcSupplement;
var = cmd; \
} while (var == -1 && errno == EINTR)
+QT_BEGIN_NAMESPACE
// don't call QT_OPEN or ::open
// call qt_safe_open
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 054be70..706dc54 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -2183,21 +2183,37 @@ void QCoreApplication::removeLibraryPath(const QString &path)
/*!
\fn EventFilter QCoreApplication::setEventFilter(EventFilter filter)
- Sets the event filter \a filter. Returns a pointer to the filter
- function previously defined.
-
- The event filter is a function that is called for every message
- received in all threads. This does \e not include messages to
+ Replaces the event filter function for the QCoreApplication with
+ \a filter and returns the pointer to the replaced event filter
+ function. Only the current event filter function is called. If you
+ want to use both filter functions, save the replaced EventFilter
+ in a place where yours can call it.
+
+ The event filter function set here is called for all messages
+ received by all threads meant for all Qt objects. It is \e not
+ called for messages that are not meant for Qt objects.
+
+ The event filter function should return true if the message should
+ be filtered, (i.e. stopped). It should return false to allow
+ processing the message to continue.
+
+ By default, no event filter function is set (i.e., this function
+ returns a null EventFilter the first time it is called).
+
+ \note The filter function set here receives native messages,
+ i.e. MSG or XEvent structs, that are going to Qt objects. It is
+ called by QCoreApplication::filterEvent(). If the filter function
+ returns false to indicate the message should be processed further,
+ the native message can then be translated into a QEvent and
+ handled by the standard Qt \l{QEvent} {event} filering, e.g.
+ QObject::installEventFilter().
+
+ \note The filter function set here is different form the filter
+ function set via QAbstractEventDispatcher::setEventFilter(), which
+ gets all messages received by its thread, even messages meant for
objects that are not handled by Qt.
- The function can return true to stop the event to be processed by
- Qt, or false to continue with the standard event processing.
-
- Only one filter can be defined, but the filter can use the return
- value to call the previously set event filter. By default, no
- filter is set (i.e., the function returns 0).
-
- \sa installEventFilter()
+ \sa QObject::installEventFilter(), QAbstractEventDispatcher::setEventFilter()
*/
QCoreApplication::EventFilter
QCoreApplication::setEventFilter(QCoreApplication::EventFilter filter)
diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h
index ff2b412..233b4f9 100644
--- a/src/corelib/plugin/qplugin.h
+++ b/src/corelib/plugin/qplugin.h
@@ -63,21 +63,6 @@ typedef QObject *(*QtPluginInstanceFunction)();
void Q_CORE_EXPORT qRegisterStaticPluginInstanceFunction(QtPluginInstanceFunction function);
-struct qt_plugin_instance_deleter
-{
- qt_plugin_instance_deleter(QPointer<QObject> &instance)
- : instance_(instance)
- {
- }
-
- ~qt_plugin_instance_deleter()
- {
- delete instance_;
- }
-
- QPointer<QObject> &instance_;
-};
-
#define Q_IMPORT_PLUGIN(PLUGIN) \
extern QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance_##PLUGIN(); \
class Static##PLUGIN##PluginInstance{ \
@@ -91,10 +76,8 @@ struct qt_plugin_instance_deleter
#define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \
{ \
static QT_PREPEND_NAMESPACE(QPointer)<QT_PREPEND_NAMESPACE(QObject)> _instance; \
- if (!_instance) { \
- static QT_PREPEND_NAMESPACE(qt_plugin_instance_deleter) deleter(_instance); \
+ if (!_instance) \
_instance = new IMPLEMENTATION; \
- } \
return _instance; \
}
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index 24522f2..2e31c6d 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -261,9 +261,14 @@ void QAdoptedThread::run()
Returns the thread handle of the currently executing thread.
\warning The handle returned by this function is used for internal
- purposes and should not be used in any application code. On
- Windows, the returned value is a pseudo-handle for the current
- thread that cannot be used for numerical comparison.
+ purposes and should not be used in any application code.
+
+ \warning On Windows, the returned value is a pseudo-handle for the
+ current thread. It can't be used for numerical comparison. i.e.,
+ this function returns the DWORD (Windows-Thread ID) returned by
+ the Win32 function getCurrentThreadId(), not the HANDLE
+ (Windows-Thread HANDLE) returned by the Win32 function
+ getCurrentThread().
*/
/*!
diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h
index f3daca7..008c068 100644
--- a/src/corelib/tools/qringbuffer_p.h
+++ b/src/corelib/tools/qringbuffer_p.h
@@ -303,6 +303,9 @@ public:
// read an unspecified amount (will read the first buffer)
inline QByteArray read() {
+ if (bufferSize == 0)
+ return QByteArray();
+
// multiple buffers, just take the first one
if (head == 0 && tailBuffer != 0) {
QByteArray qba = buffers.takeFirst();
@@ -325,7 +328,7 @@ public:
// We can avoid by initializing the QRingBuffer with basicBlockSize of 0
// and only using this read() function.
QByteArray qba(readPointer(), nextDataBlockSize());
- buffers.takeFirst();
+ buffers.removeFirst();
head = 0;
if (tailBuffer == 0) {
buffers << QByteArray();
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 6bb0d8e..235c603 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -1235,6 +1235,8 @@ inline int QStringRef::localeAwareCompare(const QStringRef &s1, const QStringRef
QT_END_NAMESPACE
+QT_END_HEADER
+
#ifdef QT_USE_FAST_CONCATENATION
#include <QtCore/qstringbuilder.h>
#endif
diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h
index 852c072..3b43253 100644
--- a/src/corelib/tools/qstringbuilder.h
+++ b/src/corelib/tools/qstringbuilder.h
@@ -69,7 +69,7 @@ private:
};
-template <typename T> class QConcatenable {};
+template <typename T> struct QConcatenable {};
template <typename A, typename B>
class QStringBuilder
@@ -202,6 +202,18 @@ template <> struct QConcatenable<const char *>
*out++ = QLatin1Char(*a++);
}
};
+
+template <> struct QConcatenable<QByteArray>
+{
+ typedef QByteArray type;
+ static int size(const QByteArray &ba) { return qstrnlen(ba.constData(), ba.size()); }
+ static inline void appendTo(const QByteArray &ba, QChar *&out)
+ {
+ const char *data = ba.constData();
+ while (*data)
+ *out++ = QLatin1Char(*data++);
+ }
+};
#endif
template <typename A, typename B>
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp
index 6777aa5..14cadd9 100644
--- a/src/dbus/qdbusconnection.cpp
+++ b/src/dbus/qdbusconnection.cpp
@@ -973,8 +973,15 @@ QDBusConnection QDBusConnection::systemBus()
}
/*!
+ \nonreentrant
+
Returns the connection that sent the signal, if called in a slot activated
by QDBus; otherwise it returns 0.
+
+ \note Please avoid this function. This function is not thread-safe, so if
+ there's any other thread delivering a D-Bus call, this function may return
+ the wrong connection. In new code, please use QDBusContext::connection()
+ (see that class for a description on how to use it).
*/
QDBusConnection QDBusConnection::sender()
{
diff --git a/src/gui/dialogs/qfiledialog_p.h b/src/gui/dialogs/qfiledialog_p.h
index d798f9d..4c599cc 100644
--- a/src/gui/dialogs/qfiledialog_p.h
+++ b/src/gui/dialogs/qfiledialog_p.h
@@ -73,7 +73,6 @@
#include <qabstractproxymodel.h>
#include <qcompleter.h>
#include <qpointer.h>
-#include <qtimeline.h>
#include <qdebug.h>
#include "qsidebar_p.h"
diff --git a/src/gui/dialogs/qsidebar.cpp b/src/gui/dialogs/qsidebar.cpp
index 1915e21..e4821ad 100644
--- a/src/gui/dialogs/qsidebar.cpp
+++ b/src/gui/dialogs/qsidebar.cpp
@@ -247,11 +247,16 @@ void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move)
QUrl url = list.at(i);
if (!url.isValid() || url.scheme() != QLatin1String("file"))
continue;
+ //this makes sure the url is clean
+ const QString cleanUrl = QDir::cleanPath(url.toLocalFile());
+ url = QUrl::fromLocalFile(cleanUrl);
+
for (int j = 0; move && j < rowCount(); ++j) {
+ QString local = index(j, 0).data(UrlRole).toUrl().toLocalFile();
#if defined(Q_OS_WIN)
- if (QDir::cleanPath(index(j, 0).data(UrlRole).toUrl().toLocalFile()).toLower() == QDir::cleanPath(url.toLocalFile()).toLower()) {
+ if (index(j, 0).data(UrlRole).toUrl().toLocalFile().toLower() == cleanUrl.toLower()) {
#else
- if (QDir::cleanPath(index(j, 0).data(UrlRole).toUrl().toLocalFile()) == QDir::cleanPath(url.toLocalFile())) {
+ if (index(j, 0).data(UrlRole).toUrl().toLocalFile() == cleanUrl) {
#endif
removeRow(j);
if (j <= row)
@@ -260,12 +265,12 @@ void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move)
}
}
row = qMax(row, 0);
- QModelIndex idx = fileSystemModel->index(url.toLocalFile());
+ QModelIndex idx = fileSystemModel->index(cleanUrl);
if (!fileSystemModel->isDir(idx))
continue;
insertRows(row, 1);
setUrl(index(row, 0), url, idx);
- watching.append(QPair<QModelIndex, QString>(idx, url.toLocalFile()));
+ watching.append(qMakePair(idx, cleanUrl));
}
}
diff --git a/src/gui/graphicsview/graphicsview.pri b/src/gui/graphicsview/graphicsview.pri
index 4cee6d6..0c0747e 100644
--- a/src/gui/graphicsview/graphicsview.pri
+++ b/src/gui/graphicsview/graphicsview.pri
@@ -1,37 +1,42 @@
# Qt graphicsview module
-HEADERS += graphicsview/qgraphicsitem.h \
+HEADERS += graphicsview/qgraphicsgridlayout.h \
+ graphicsview/qgraphicsitem.h \
graphicsview/qgraphicsitem_p.h \
graphicsview/qgraphicsitemanimation.h \
- graphicsview/qgraphicsscene.h \
- graphicsview/qgraphicsscene_p.h \
- graphicsview/qgraphicsscene_bsp_p.h \
- graphicsview/qgraphicssceneevent.h \
- graphicsview/qgraphicsview_p.h \
- graphicsview/qgraphicsview.h
-SOURCES += graphicsview/qgraphicsitem.cpp \
- graphicsview/qgraphicsitemanimation.cpp \
- graphicsview/qgraphicsscene.cpp \
- graphicsview/qgraphicsscene_bsp.cpp \
- graphicsview/qgraphicssceneevent.cpp \
- graphicsview/qgraphicsview.cpp
-
-# Widgets on the canvas
-HEADERS += graphicsview/qgraphicslayout.h \
+ graphicsview/qgraphicslayout.h \
graphicsview/qgraphicslayout_p.h \
graphicsview/qgraphicslayoutitem.h \
graphicsview/qgraphicslayoutitem_p.h \
graphicsview/qgraphicslinearlayout.h \
+ graphicsview/qgraphicsproxywidget.h \
+ graphicsview/qgraphicsscene.h \
+ graphicsview/qgraphicsscene_bsp_p.h \
+ graphicsview/qgraphicsscene_p.h \
+ graphicsview/qgraphicsscenebsptreeindex_p.h \
+ graphicsview/qgraphicssceneevent.h \
+ graphicsview/qgraphicssceneindex_p.h \
+ graphicsview/qgraphicsscenelinearindex_p.h \
+ graphicsview/qgraphicsview.h \
+ graphicsview/qgraphicsview_p.h \
graphicsview/qgraphicswidget.h \
graphicsview/qgraphicswidget_p.h \
- graphicsview/qgridlayoutengine_p.h \
- graphicsview/qgraphicsproxywidget.h \
- graphicsview/qgraphicsgridlayout.h
-SOURCES += graphicsview/qgraphicslayout.cpp \
+ graphicsview/qgridlayoutengine_p.h
+
+SOURCES += graphicsview/qgraphicsgridlayout.cpp \
+ graphicsview/qgraphicsitem.cpp \
+ graphicsview/qgraphicsitemanimation.cpp \
+ graphicsview/qgraphicslayout.cpp \
graphicsview/qgraphicslayout_p.cpp \
graphicsview/qgraphicslayoutitem.cpp \
graphicsview/qgraphicslinearlayout.cpp \
+ graphicsview/qgraphicsproxywidget.cpp \
+ graphicsview/qgraphicsscene.cpp \
+ graphicsview/qgraphicsscene_bsp.cpp \
+ graphicsview/qgraphicsscenebsptreeindex.cpp \
+ graphicsview/qgraphicssceneevent.cpp \
+ graphicsview/qgraphicssceneindex.cpp \
+ graphicsview/qgraphicsscenelinearindex.cpp \
+ graphicsview/qgraphicsview.cpp \
graphicsview/qgraphicswidget.cpp \
graphicsview/qgraphicswidget_p.cpp \
- graphicsview/qgridlayoutengine.cpp \
- graphicsview/qgraphicsproxywidget.cpp \
- graphicsview/qgraphicsgridlayout.cpp
+ graphicsview/qgridlayoutengine.cpp
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index a5ee7e6..03014d8 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -558,6 +558,7 @@
#include "qgraphicsview.h"
#include "qgraphicswidget.h"
#include "qgraphicsproxywidget.h"
+#include "qgraphicsscenebsptreeindex_p.h"
#include <QtCore/qbitarray.h>
#include <QtCore/qdebug.h>
#include <QtCore/qpoint.h>
@@ -588,17 +589,6 @@
QT_BEGIN_NAMESPACE
-// QRectF::intersects() returns false always if either the source or target
-// rectangle's width or height are 0. This works around that problem.
-static inline void _q_adjustRect(QRectF *rect)
-{
- Q_ASSERT(rect);
- if (!rect->width())
- rect->adjust(-0.00001, 0, 0.00001, 0);
- if (!rect->height())
- rect->adjust(0, -0.00001, 0, 0.00001);
-}
-
static inline void _q_adjustRect(QRect *rect)
{
Q_ASSERT(rect);
@@ -832,6 +822,42 @@ void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTran
}
}
+void QGraphicsItemPrivate::updateSceneTransformFromParent()
+{
+ if (parent) {
+ Q_ASSERT(!parent->d_ptr->dirtySceneTransform);
+ if (parent->d_ptr->sceneTransformTranslateOnly) {
+ sceneTransform = QTransform::fromTranslate(parent->d_ptr->sceneTransform.dx() + pos.x(),
+ parent->d_ptr->sceneTransform.dy() + pos.y());
+ } else {
+ sceneTransform = parent->d_ptr->sceneTransform;
+ sceneTransform.translate(pos.x(), pos.y());
+ }
+ if (transformData) {
+ sceneTransform = transformData->computedFullTransform(&sceneTransform);
+ sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+ } else {
+ sceneTransformTranslateOnly = parent->d_ptr->sceneTransformTranslateOnly;
+ }
+ } else if (!transformData) {
+ sceneTransform = QTransform::fromTranslate(pos.x(), pos.y());
+ sceneTransformTranslateOnly = 1;
+ } else if (transformData->onlyTransform) {
+ sceneTransform = transformData->transform;
+ if (!pos.isNull())
+ sceneTransform *= QTransform::fromTranslate(pos.x(), pos.y());
+ sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+ } else if (pos.isNull()) {
+ sceneTransform = transformData->computedFullTransform();
+ sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+ } else {
+ sceneTransform = QTransform::fromTranslate(pos.x(), pos.y());
+ sceneTransform = transformData->computedFullTransform(&sceneTransform);
+ sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+ }
+ dirtySceneTransform = 0;
+}
+
/*!
\internal
@@ -871,6 +897,11 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
if (newParent == parent)
return;
+ if (scene) {
+ // Deliver the change to the index
+ scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParentVariant);
+ }
+
if (QGraphicsWidget *w = isWidget ? static_cast<QGraphicsWidget *>(q) : q->parentWidget()) {
// Update the child focus chain; when reparenting a widget that has a
// focus child, ensure that that focus child clears its focus child
@@ -958,12 +989,6 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
}
}
- if (scene) {
- // Invalidate any sort caching; arrival of a new item means we need to
- // resort.
- scene->d_func()->invalidateSortCache();
- }
-
// Resolve depth.
resolveDepth(parent ? parent->d_ptr->depth : -1);
dirtySceneTransform = 1;
@@ -1442,6 +1467,8 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags)
flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt());
if (quint32(d_ptr->flags) == quint32(flags))
return;
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, quint32(flags));
// Flags that alter the geometry of the item (or its children).
const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations);
@@ -1800,6 +1827,8 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo
if (q_ptr->isSelected())
q_ptr->setSelected(false);
} else {
+ geometryChanged = 1;
+ paintedViewBoundingRectsNeedRepaint = 1;
if (isWidget && scene) {
QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
if (widget->windowType() == Qt::Popup)
@@ -3160,7 +3189,8 @@ void QGraphicsItem::setTransformOrigin(const QPointF &origin)
*/
QMatrix QGraphicsItem::sceneMatrix() const
{
- return sceneTransform().toAffine();
+ d_ptr->ensureSceneTransform();
+ return d_ptr->sceneTransform.toAffine();
}
@@ -3183,16 +3213,7 @@ QMatrix QGraphicsItem::sceneMatrix() const
*/
QTransform QGraphicsItem::sceneTransform() const
{
- if (d_ptr->dirtySceneTransform) {
- // This item and all its descendants have dirty scene transforms.
- // We're about to validate this item's scene transform, so we have to
- // invalidate all the children; otherwise there's no way for the descendants
- // to detect that the ancestor has changed.
- d_ptr->invalidateChildrenSceneTransform();
- }
-
- QGraphicsItem *that = const_cast<QGraphicsItem *>(this);
- d_ptr->ensureSceneTransformRecursive(&that);
+ d_ptr->ensureSceneTransform();
return d_ptr->sceneTransform;
}
@@ -3222,8 +3243,10 @@ QTransform QGraphicsItem::sceneTransform() const
QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) const
{
// Ensure we return the standard transform if we're not untransformable.
- if (!d_ptr->itemIsUntransformable())
- return sceneTransform() * viewportTransform;
+ if (!d_ptr->itemIsUntransformable()) {
+ d_ptr->ensureSceneTransform();
+ return d_ptr->sceneTransform * viewportTransform;
+ }
// Find the topmost item that ignores view transformations.
const QGraphicsItem *untransformedAncestor = this;
@@ -3242,7 +3265,8 @@ QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) c
}
// First translate the base untransformable item.
- QPointF mappedPoint = (untransformedAncestor->sceneTransform() * viewportTransform).map(QPointF(0, 0));
+ untransformedAncestor->d_ptr->ensureSceneTransform();
+ QPointF mappedPoint = (untransformedAncestor->d_ptr->sceneTransform * viewportTransform).map(QPointF(0, 0));
// COMBINE
QTransform matrix = QTransform::fromTranslate(mappedPoint.x(), mappedPoint.y());
@@ -3335,8 +3359,11 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co
// Find the closest common ancestor. If the two items don't share an
// ancestor, then the only way is to combine their scene transforms.
const QGraphicsItem *commonAncestor = commonAncestorItem(other);
- if (!commonAncestor)
- return sceneTransform() * other->sceneTransform().inverted(ok);
+ if (!commonAncestor) {
+ d_ptr->ensureSceneTransform();
+ other->d_ptr->ensureSceneTransform();
+ return d_ptr->sceneTransform * other->d_ptr->sceneTransform.inverted(ok);
+ }
// If the two items are cousins (in sibling branches), map both to the
// common ancestor, and combine the two transforms.
@@ -3627,18 +3654,20 @@ void QGraphicsItem::setZValue(qreal z)
qreal newZ = qreal(newZVariant.toDouble());
if (newZ == d_ptr->z)
return;
+
+ if (d_ptr->scene) {
+ // Z Value has changed, we have to notify the index.
+ d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, newZVariant);
+ }
+
d_ptr->z = newZ;
if (d_ptr->parent)
d_ptr->parent->d_ptr->needSortChildren = 1;
else if (d_ptr->scene)
d_ptr->scene->d_func()->needSortTopLevelItems = 1;
- if (d_ptr->scene) {
+ if (d_ptr->scene)
d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
- // Invalidate any sort caching; arrival of a new item means we need to
- // resort.
- d_ptr->scene->d_func()->invalidateSortCache();
- }
itemChange(ItemZValueHasChanged, newZVariant);
@@ -3729,7 +3758,13 @@ QRectF QGraphicsItem::sceneBoundingRect() const
QRectF br = boundingRect();
br.translate(offset);
- return !parentItem ? br : parentItem->sceneTransform().mapRect(br);
+ if (!parentItem)
+ return br;
+ if (parentItem->d_ptr->hasTranslateOnlySceneTransform()) {
+ br.translate(parentItem->d_ptr->sceneTransform.dx(), parentItem->d_ptr->sceneTransform.dy());
+ return br;
+ }
+ return parentItem->d_ptr->sceneTransform.mapRect(br);
}
/*!
@@ -4104,7 +4139,7 @@ bool QGraphicsItem::isObscuredBy(const QGraphicsItem *item) const
{
if (!item)
return false;
- return QGraphicsScenePrivate::closestItemFirst_withoutCache(item, this)
+ return QGraphicsSceneBspTreeIndexPrivate::closestItemFirst_withoutCache(item, this)
&& qt_QGraphicsItem_isObscured(this, item, boundingRect());
}
@@ -4297,12 +4332,11 @@ bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping, bool ignore
{
// No scene, or if the scene is updating everything, means we have nothing
// to do. The only exception is if the scene tracks the growing scene rect.
- return (!visible && !ignoreVisibleBit)
+ return !scene
+ || (!visible && !ignoreVisibleBit && !this->ignoreVisible)
|| (!ignoreDirtyBit && fullUpdatePending)
- || !scene
- || (scene->d_func()->updateAll && scene->d_func()->hasSceneRect)
|| (!ignoreClipping && (childrenClippedToShape() && isClippedAway()))
- || (!ignoreOpacity && childrenCombineOpacity() && isFullyTransparent());
+ || (!ignoreOpacity && !this->ignoreOpacity && childrenCombineOpacity() && isFullyTransparent());
}
/*!
@@ -4323,6 +4357,7 @@ void QGraphicsItemPrivate::resolveDepth(int parentDepth)
void QGraphicsItemPrivate::addChild(QGraphicsItem *child)
{
needSortChildren = 1;
+ child->d_ptr->siblingIndex = children.size();
children.append(child);
}
@@ -4332,6 +4367,10 @@ void QGraphicsItemPrivate::addChild(QGraphicsItem *child)
void QGraphicsItemPrivate::removeChild(QGraphicsItem *child)
{
children.removeOne(child);
+ // NB! Do not use children.removeAt(child->d_ptr->siblingIndex) because
+ // the child is not guaranteed to be at the index after the list is sorted.
+ // (see ensureSortedChildren()).
+ child->d_ptr->siblingIndex = -1;
}
/*!
@@ -4492,9 +4531,22 @@ void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMost
}
// COMBINE my transform with the parent's scene transform.
- sceneTransform = parent ? parent->d_ptr->sceneTransform : QTransform();
- combineTransformFromParent(&sceneTransform);
- dirtySceneTransform = 0;
+ updateSceneTransformFromParent();
+ Q_ASSERT(!dirtySceneTransform);
+}
+
+void QGraphicsItemPrivate::ensureSceneTransform()
+{
+ if (dirtySceneTransform) {
+ // This item and all its descendants have dirty scene transforms.
+ // We're about to validate this item's scene transform, so we have to
+ // invalidate all the children; otherwise there's no way for the descendants
+ // to detect that the ancestor has changed.
+ invalidateChildrenSceneTransform();
+ }
+
+ QGraphicsItem *that = q_func();
+ ensureSceneTransformRecursive(&that);
}
/*!
@@ -4835,7 +4887,9 @@ QPointF QGraphicsItem::mapToParent(const QPointF &point) const
*/
QPointF QGraphicsItem::mapToScene(const QPointF &point) const
{
- return sceneTransform().map(point);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return QPointF(point.x() + d_ptr->sceneTransform.dx(), point.y() + d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.map(point);
}
/*!
@@ -4902,7 +4956,9 @@ QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const
*/
QPolygonF QGraphicsItem::mapToScene(const QRectF &rect) const
{
- return sceneTransform().map(rect);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.map(rect);
}
/*!
@@ -4975,7 +5031,9 @@ QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const
*/
QRectF QGraphicsItem::mapRectToScene(const QRectF &rect) const
{
- return sceneTransform().mapRect(rect);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.mapRect(rect);
}
/*!
@@ -5049,7 +5107,9 @@ QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const
*/
QRectF QGraphicsItem::mapRectFromScene(const QRectF &rect) const
{
- return sceneTransform().inverted().mapRect(rect);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().mapRect(rect);
}
/*!
@@ -5101,7 +5161,9 @@ QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const
*/
QPolygonF QGraphicsItem::mapToScene(const QPolygonF &polygon) const
{
- return sceneTransform().map(polygon);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return polygon.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.map(polygon);
}
/*!
@@ -5146,7 +5208,9 @@ QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const
*/
QPainterPath QGraphicsItem::mapToScene(const QPainterPath &path) const
{
- return sceneTransform().map(path);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return path.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.map(path);
}
/*!
@@ -5207,7 +5271,9 @@ QPointF QGraphicsItem::mapFromParent(const QPointF &point) const
*/
QPointF QGraphicsItem::mapFromScene(const QPointF &point) const
{
- return sceneTransform().inverted().map(point);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return QPointF(point.x() - d_ptr->sceneTransform.dx(), point.y() - d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().map(point);
}
/*!
@@ -5275,7 +5341,9 @@ QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const
*/
QPolygonF QGraphicsItem::mapFromScene(const QRectF &rect) const
{
- return sceneTransform().inverted().map(rect);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().map(rect);
}
/*!
@@ -5325,7 +5393,9 @@ QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const
*/
QPolygonF QGraphicsItem::mapFromScene(const QPolygonF &polygon) const
{
- return sceneTransform().inverted().map(polygon);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return polygon.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().map(polygon);
}
/*!
@@ -5368,7 +5438,9 @@ QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const
*/
QPainterPath QGraphicsItem::mapFromScene(const QPainterPath &path) const
{
- return sceneTransform().inverted().map(path);
+ if (d_ptr->hasTranslateOnlySceneTransform())
+ return path.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+ return d_ptr->sceneTransform.inverted().map(path);
}
/*!
@@ -6333,7 +6405,7 @@ void QGraphicsItem::addToIndex()
return;
}
if (d_ptr->scene)
- d_ptr->scene->d_func()->addToIndex(this);
+ d_ptr->scene->d_func()->index->addItem(this);
}
/*!
@@ -6350,7 +6422,7 @@ void QGraphicsItem::removeFromIndex()
return;
}
if (d_ptr->scene)
- d_ptr->scene->d_func()->removeFromIndex(this);
+ d_ptr->scene->d_func()->index->removeItem(this);
}
/*!
@@ -6369,10 +6441,12 @@ void QGraphicsItem::removeFromIndex()
void QGraphicsItem::prepareGeometryChange()
{
if (d_ptr->scene) {
+ d_ptr->scene->d_func()->dirtyGrowingItemsBoundingRect = true;
d_ptr->geometryChanged = 1;
d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
+ scenePrivate->index->prepareBoundingRectChange(this);
scenePrivate->markDirty(this, QRectF(),
/*invalidateChildren=*/true,
/*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper);
@@ -6383,10 +6457,13 @@ void QGraphicsItem::prepareGeometryChange()
// _q_processDirtyItems is called before _q_emitUpdated.
if ((scenePrivate->connectedSignals & scenePrivate->changedSignalMask)
|| scenePrivate->views.isEmpty()) {
- d_ptr->scene->update(sceneTransform().mapRect(boundingRect()));
+ if (d_ptr->hasTranslateOnlySceneTransform()) {
+ d_ptr->scene->update(boundingRect().translated(d_ptr->sceneTransform.dx(),
+ d_ptr->sceneTransform.dy()));
+ } else {
+ d_ptr->scene->update(d_ptr->sceneTransform.mapRect(boundingRect()));
+ }
}
-
- scenePrivate->removeFromIndex(this);
}
QGraphicsItem *parent = this;
@@ -9706,17 +9783,11 @@ QDebug operator<<(QDebug debug, QGraphicsItem *item)
return debug;
}
- QStringList flags;
- if (item->isVisible()) flags << QLatin1String("isVisible");
- if (item->isEnabled()) flags << QLatin1String("isEnabled");
- if (item->isSelected()) flags << QLatin1String("isSelected");
- if (item->hasFocus()) flags << QLatin1String("HasFocus");
-
debug << "QGraphicsItem(this =" << ((void*)item)
<< ", parent =" << ((void*)item->parentItem())
<< ", pos =" << item->pos()
- << ", z =" << item->zValue() << ", flags = {"
- << flags.join(QLatin1String("|")) << " })";
+ << ", z =" << item->zValue() << ", flags = "
+ << item->flags() << ")";
return debug;
}
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index d26110a..72c4830 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -142,7 +142,7 @@ public:
QGraphicsItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -209,8 +209,8 @@ public:
Qt::MouseButtons acceptedMouseButtons() const;
void setAcceptedMouseButtons(Qt::MouseButtons buttons);
- bool acceptsHoverEvents() const; // obsolete
- void setAcceptsHoverEvents(bool enabled); // obsolete
+ bool acceptsHoverEvents() const; // ### obsolete
+ void setAcceptsHoverEvents(bool enabled); // ### obsolete
bool acceptHoverEvents() const;
void setAcceptHoverEvents(bool enabled);
bool acceptTouchEvents() const;
@@ -437,11 +437,16 @@ private:
friend class QGraphicsScene;
friend class QGraphicsScenePrivate;
friend class QGraphicsSceneFindItemBspTreeVisitor;
+ friend class QGraphicsSceneBspTree;
friend class QGraphicsView;
friend class QGraphicsViewPrivate;
friend class QGraphicsWidget;
friend class QGraphicsWidgetPrivate;
friend class QGraphicsProxyWidgetPrivate;
+ friend class QGraphicsSceneIndex;
+ friend class QGraphicsSceneIndexPrivate;
+ friend class QGraphicsSceneBspTreeIndex;
+ friend class QGraphicsSceneBspTreeIndexPrivate;
friend class ::tst_QGraphicsItem;
friend bool qt_closestLeaf(const QGraphicsItem *, const QGraphicsItem *);
friend bool qt_closestItemFirst(const QGraphicsItem *, const QGraphicsItem *);
@@ -533,7 +538,7 @@ class Q_GUI_EXPORT QAbstractGraphicsShapeItem : public QGraphicsItem
public:
QAbstractGraphicsShapeItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -563,13 +568,13 @@ class Q_GUI_EXPORT QGraphicsPathItem : public QAbstractGraphicsShapeItem
public:
QGraphicsPathItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsPathItem(const QPainterPath &path, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -606,19 +611,19 @@ class Q_GUI_EXPORT QGraphicsRectItem : public QAbstractGraphicsShapeItem
public:
QGraphicsRectItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsRectItem(const QRectF &rect, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsRectItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -659,19 +664,19 @@ class Q_GUI_EXPORT QGraphicsEllipseItem : public QAbstractGraphicsShapeItem
public:
QGraphicsEllipseItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsEllipseItem(const QRectF &rect, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsEllipseItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -718,14 +723,14 @@ class Q_GUI_EXPORT QGraphicsPolygonItem : public QAbstractGraphicsShapeItem
public:
QGraphicsPolygonItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsPolygonItem(const QPolygonF &polygon,
QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -765,19 +770,19 @@ class Q_GUI_EXPORT QGraphicsLineItem : public QGraphicsItem
public:
QGraphicsLineItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsLineItem(const QLineF &line, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsLineItem(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -825,13 +830,13 @@ public:
QGraphicsPixmapItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -887,13 +892,13 @@ class Q_GUI_EXPORT QGraphicsTextItem : public QGraphicsObject
public:
QGraphicsTextItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsTextItem(const QString &text, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -988,13 +993,13 @@ class Q_GUI_EXPORT QGraphicsSimpleTextItem : public QAbstractGraphicsShapeItem
public:
QGraphicsSimpleTextItem(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
QGraphicsSimpleTextItem(const QString &text, QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
@@ -1034,7 +1039,7 @@ class Q_GUI_EXPORT QGraphicsItemGroup : public QGraphicsItem
public:
QGraphicsItemGroup(QGraphicsItem *parent = 0
#ifndef Q_QDOC
- // obsolete argument
+ // ### obsolete argument
, QGraphicsScene *scene = 0
#endif
);
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 46ec6fe..9bdd273 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -119,6 +119,7 @@ public:
parent(0),
transformData(0),
index(-1),
+ siblingIndex(-1),
depth(0),
acceptedMouseButtons(0x1f),
visible(1),
@@ -149,13 +150,14 @@ public:
dirtyChildrenBoundingRect(1),
paintedViewBoundingRectsNeedRepaint(0),
dirtySceneTransform(1),
- geometryChanged(0),
+ geometryChanged(1),
inDestructor(0),
isObject(0),
ignoreVisible(0),
ignoreOpacity(0),
acceptTouchEvents(0),
acceptedTouchBeginEvent(0),
+ sceneTransformTranslateOnly(0),
globalStackingOrder(-1),
q_ptr(0)
{
@@ -164,6 +166,15 @@ public:
inline virtual ~QGraphicsItemPrivate()
{ }
+ static const QGraphicsItemPrivate *get(const QGraphicsItem *item)
+ {
+ return item->d_ptr;
+ }
+ static QGraphicsItemPrivate *get(QGraphicsItem *item)
+ {
+ return item->d_ptr;
+ }
+
void updateAncestorFlag(QGraphicsItem::GraphicsItemFlag childFlag,
AncestorFlag flag = NoFlag, bool enabled = false, bool root = true);
void setIsMemberOfGroup(bool enabled);
@@ -177,6 +188,7 @@ public:
void combineTransformToParent(QTransform *x, const QTransform *viewTransform = 0) const;
void combineTransformFromParent(QTransform *x, const QTransform *viewTransform = 0) const;
+ void updateSceneTransformFromParent();
// ### Qt 5: Remove. Workaround for reimplementation added after Qt 4.4.
virtual QVariant inputMethodQueryHelper(Qt::InputMethodQuery query) const;
@@ -286,6 +298,13 @@ public:
void invalidateCachedClipPathRecursively(bool childrenOnly = false, const QRectF &emptyIfOutsideThisRect = QRectF());
void updateCachedClipPathFromSetPosHelper(const QPointF &newPos);
void ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem);
+ void ensureSceneTransform();
+
+ inline bool hasTranslateOnlySceneTransform()
+ {
+ ensureSceneTransform();
+ return sceneTransformTranslateOnly;
+ }
inline void invalidateChildrenSceneTransform()
{
@@ -370,6 +389,7 @@ public:
}
inline QTransform transformToParent() const;
+ inline void ensureSortedChildren();
QPainterPath cachedClipPath;
QRectF childrenBoundingRect;
@@ -385,6 +405,7 @@ public:
TransformData *transformData;
QTransform sceneTransform;
int index;
+ int siblingIndex;
int depth;
// Packed 32 bytes
@@ -426,7 +447,8 @@ public:
quint32 ignoreOpacity : 1;
quint32 acceptTouchEvents : 1;
quint32 acceptedTouchBeginEvent : 1;
- quint32 unused : 9; // feel free to use
+ quint32 sceneTransformTranslateOnly : 1;
+ quint32 unused : 8; // feel free to use
// Optional stacking order
int globalStackingOrder;
@@ -457,6 +479,10 @@ struct QGraphicsItemPrivate::TransformData {
if (onlyTransform) {
if (!postmultiplyTransform)
return transform;
+ if (postmultiplyTransform->isIdentity())
+ return transform;
+ if (transform.isIdentity())
+ return *postmultiplyTransform;
QTransform x(transform);
x *= *postmultiplyTransform;
return x;
@@ -477,6 +503,29 @@ struct QGraphicsItemPrivate::TransformData {
}
};
+/*!
+ \internal
+*/
+inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{
+ // Return true if sibling item1 is on top of item2.
+ const QGraphicsItemPrivate *d1 = item1->d_ptr;
+ const QGraphicsItemPrivate *d2 = item2->d_ptr;
+ bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent;
+ bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent;
+ if (f1 != f2)
+ return f2;
+ if (d1->z != d2->z)
+ return d1->z > d2->z;
+ return d1->siblingIndex > d2->siblingIndex;
+}
+
+/*!
+ \internal
+*/
+static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{ return qt_closestLeaf(item2, item1); }
+
/*
return the full transform of the item to the parent. This include the position and all the transform data
*/
@@ -487,6 +536,14 @@ inline QTransform QGraphicsItemPrivate::transformToParent() const
return matrix;
}
+inline void QGraphicsItemPrivate::ensureSortedChildren()
+{
+ if (needSortChildren) {
+ qSort(children.begin(), children.end(), qt_notclosestLeaf);
+ needSortChildren = 0;
+ }
+}
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 0c3abd4..c8e178a 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -39,7 +39,6 @@
**
****************************************************************************/
-
/*!
\class QGraphicsScene
\brief The QGraphicsScene class provides a surface for managing a large
@@ -218,6 +217,9 @@
#include "qgraphicsview_p.h"
#include "qgraphicswidget.h"
#include "qgraphicswidget_p.h"
+#include "qgraphicssceneindex_p.h"
+#include "qgraphicsscenebsptreeindex_p.h"
+#include "qgraphicsscenelinearindex_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qlist.h>
@@ -251,67 +253,6 @@
QT_BEGIN_NAMESPACE
-static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2);
-
-static inline bool QRectF_intersects(const QRectF &s, const QRectF &r)
-{
- qreal xp = s.left();
- qreal yp = s.top();
- qreal w = s.width();
- qreal h = s.height();
- qreal l1 = xp;
- qreal r1 = xp;
- if (w < 0)
- l1 += w;
- else
- r1 += w;
-
- qreal l2 = r.left();
- qreal r2 = r.left();
- if (w < 0)
- l2 += r.width();
- else
- r2 += r.width();
-
- if (l1 >= r2 || l2 >= r1)
- return false;
-
- qreal t1 = yp;
- qreal b1 = yp;
- if (h < 0)
- t1 += h;
- else
- b1 += h;
-
- qreal t2 = r.top();
- qreal b2 = r.top();
- if (r.height() < 0)
- t2 += r.height();
- else
- b2 += r.height();
-
- return !(t1 >= b2 || t2 >= b1);
-}
-
-// QRectF::intersects() returns false always if either the source or target
-// rectangle's width or height are 0. This works around that problem.
-static inline void _q_adjustRect(QRectF *rect)
-{
- Q_ASSERT(rect);
- if (!rect->width())
- rect->adjust(-0.00001, 0, 0.00001, 0);
- if (!rect->height())
- rect->adjust(0, -0.00001, 0, 0.00001);
-}
-
-static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
-{
- Q_ASSERT(item);
- QRectF boundingRect(item->boundingRect());
- _q_adjustRect(&boundingRect);
- return boundingRect;
-}
-
static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
{
hover->setWidget(mouseEvent->widget());
@@ -331,18 +272,15 @@ static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraph
QGraphicsScenePrivate::QGraphicsScenePrivate()
: changedSignalMask(0),
indexMethod(QGraphicsScene::BspTreeIndex),
- bspTreeDepth(0),
+ index(0),
lastItemCount(0),
hasSceneRect(false),
+ dirtyGrowingItemsBoundingRect(true),
updateAll(false),
calledEmitUpdated(false),
processDirtyItemsEmitted(false),
selectionChanging(0),
needSortTopLevelItems(true),
- regenerateIndex(true),
- purgePending(false),
- indexTimerId(0),
- restartIndexTimer(false),
stickyFocus(false),
hasFocus(false),
focusItem(0),
@@ -359,7 +297,6 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
allItemsUseDefaultCursor(true),
painterStateProtection(true),
sortCacheEnabled(false),
- updatingSortCache(false),
style(0),
allItemsIgnoreTouchEvents(true)
{
@@ -372,6 +309,8 @@ void QGraphicsScenePrivate::init()
{
Q_Q(QGraphicsScene);
+ index = new QGraphicsSceneBspTreeIndex(q);
+
// Keep this index so we can check for connected slots later on.
changedSignalMask = (1 << q->metaObject()->indexOfSignal("changed(QList<QRectF>)"));
qApp->d_func()->scene_list.append(q);
@@ -381,223 +320,25 @@ void QGraphicsScenePrivate::init()
/*!
\internal
*/
-QList<QGraphicsItem *> QGraphicsScenePrivate::estimateItemsInRect(const QRectF &rect) const
-{
- const_cast<QGraphicsScenePrivate *>(this)->purgeRemovedItems();
- const_cast<QGraphicsScenePrivate *>(this)->_q_updateSortCache();
-
- if (indexMethod == QGraphicsScene::BspTreeIndex) {
- // ### Only do this once in a while.
- QGraphicsScenePrivate *that = const_cast<QGraphicsScenePrivate *>(this);
-
- // Get items from BSP tree
- QList<QGraphicsItem *> items = that->bspTree.items(rect);
-
- // Fill in with any unindexed items
- for (int i = 0; i < unindexedItems.size(); ++i) {
- if (QGraphicsItem *item = unindexedItems.at(i)) {
- if (!item->d_ptr->itemDiscovered && item->d_ptr->visible && !(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
- QRectF boundingRect = item->sceneBoundingRect();
- if (QRectF_intersects(boundingRect, rect)) {
- item->d_ptr->itemDiscovered = 1;
- items << item;
- }
- }
- }
- }
-
- // Reset the discovered state of all discovered items
- for (int i = 0; i < items.size(); ++i)
- items.at(i)->d_func()->itemDiscovered = 0;
- return items;
- }
-
- QList<QGraphicsItem *> itemsInRect;
- for (int i = 0; i < unindexedItems.size(); ++i) {
- if (QGraphicsItem *item = unindexedItems.at(i)) {
- if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
- continue;
- if (item->d_ptr->visible && !item->d_ptr->isFullyTransparent())
- itemsInRect << item;
- }
- }
- for (int i = 0; i < indexedItems.size(); ++i) {
- if (QGraphicsItem *item = indexedItems.at(i)) {
- if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
- continue;
- if (item->d_ptr->visible && !item->d_ptr->isFullyTransparent())
- itemsInRect << item;
- }
- }
-
- return itemsInRect;
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::addToIndex(QGraphicsItem *item)
-{
- if (indexMethod == QGraphicsScene::BspTreeIndex) {
- if (item->d_func()->index != -1) {
- bspTree.insertItem(item, item->sceneBoundingRect());
- foreach (QGraphicsItem *child, item->children())
- child->addToIndex();
- } else {
- // The BSP tree is regenerated if the number of items grows to a
- // certain threshold, or if the bounding rect of the graph doubles in
- // size.
- startIndexTimer();
- }
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::removeFromIndex(QGraphicsItem *item)
-{
- if (indexMethod == QGraphicsScene::BspTreeIndex) {
- int index = item->d_func()->index;
- if (index != -1) {
- bspTree.removeItem(item, item->sceneBoundingRect());
- freeItemIndexes << index;
- indexedItems[index] = 0;
- item->d_func()->index = -1;
- unindexedItems << item;
-
- foreach (QGraphicsItem *child, item->children())
- child->removeFromIndex();
- }
-
- startIndexTimer();
- }
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::resetIndex()
-{
- purgeRemovedItems();
- if (indexMethod == QGraphicsScene::BspTreeIndex) {
- for (int i = 0; i < indexedItems.size(); ++i) {
- if (QGraphicsItem *item = indexedItems.at(i)) {
- item->d_ptr->index = -1;
- unindexedItems << item;
- }
- }
- indexedItems.clear();
- freeItemIndexes.clear();
- regenerateIndex = true;
- startIndexTimer();
- }
-}
-
-static inline int intmaxlog(int n)
+QGraphicsScenePrivate *QGraphicsScenePrivate::get(QGraphicsScene *q)
{
- return (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0);
+ return q->d_func();
}
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::_q_updateIndex()
+void QGraphicsScenePrivate::_q_emitUpdated()
{
- if (!indexTimerId)
- return;
-
Q_Q(QGraphicsScene);
- q->killTimer(indexTimerId);
- indexTimerId = 0;
-
- purgeRemovedItems();
-
- // Add unindexedItems to indexedItems
- QRectF unindexedItemsBoundingRect;
- for (int i = 0; i < unindexedItems.size(); ++i) {
- if (QGraphicsItem *item = unindexedItems.at(i)) {
- unindexedItemsBoundingRect |= item->sceneBoundingRect();
- if (!freeItemIndexes.isEmpty()) {
- int freeIndex = freeItemIndexes.takeFirst();
- item->d_func()->index = freeIndex;
- indexedItems[freeIndex] = item;
- } else {
- item->d_func()->index = indexedItems.size();
- indexedItems << item;
- }
- }
- }
-
- // Update growing scene rect.
- QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
- growingItemsBoundingRect |= unindexedItemsBoundingRect;
-
- // Determine whether we should regenerate the BSP tree.
- if (indexMethod == QGraphicsScene::BspTreeIndex) {
- int depth = bspTreeDepth;
- if (depth == 0) {
- int oldDepth = intmaxlog(lastItemCount);
- depth = intmaxlog(indexedItems.size());
- static const int slack = 100;
- if (bspTree.leafCount() == 0 || (oldDepth != depth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
- // ### Crude algorithm.
- regenerateIndex = true;
- }
- }
-
- // Regenerate the tree.
- if (regenerateIndex) {
- regenerateIndex = false;
- bspTree.initialize(q->sceneRect(), depth);
- unindexedItems = indexedItems;
- lastItemCount = indexedItems.size();
- q->update();
-
- // Take this opportunity to reset our largest-item counter for
- // untransformable items. When the items are inserted into the BSP
- // tree, we'll get an accurate calculation.
- largestUntransformableItem = QRectF();
- }
- }
+ calledEmitUpdated = false;
- // Insert all unindexed items into the tree.
- for (int i = 0; i < unindexedItems.size(); ++i) {
- if (QGraphicsItem *item = unindexedItems.at(i)) {
- QRectF rect = item->sceneBoundingRect();
- if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
- continue;
- if (indexMethod == QGraphicsScene::BspTreeIndex)
- bspTree.insertItem(item, rect);
-
- // If the item ignores view transformations, update our
- // largest-item-counter to ensure that the view can accurately
- // discover untransformable items when drawing.
- if (item->d_ptr->itemIsUntransformable()) {
- QGraphicsItem *topmostUntransformable = item;
- while (topmostUntransformable && (topmostUntransformable->d_ptr->ancestorFlags
- & QGraphicsItemPrivate::AncestorIgnoresTransformations)) {
- topmostUntransformable = topmostUntransformable->parentItem();
- }
- // ### Verify that this is the correct largest untransformable rectangle.
- largestUntransformableItem |= item->mapToItem(topmostUntransformable, item->boundingRect()).boundingRect();
- }
+ if (dirtyGrowingItemsBoundingRect) {
+ if (!hasSceneRect) {
+ const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
+ growingItemsBoundingRect |= q->itemsBoundingRect();
+ if (oldGrowingItemsBoundingRect != growingItemsBoundingRect)
+ emit q->sceneRectChanged(growingItemsBoundingRect);
}
+ dirtyGrowingItemsBoundingRect = false;
}
- unindexedItems.clear();
-
- // Notify scene rect changes.
- if (!hasSceneRect && growingItemsBoundingRect != oldGrowingItemsBoundingRect)
- emit q->sceneRectChanged(growingItemsBoundingRect);
-}
-
-/*!
- \internal
-*/
-void QGraphicsScenePrivate::_q_emitUpdated()
-{
- Q_Q(QGraphicsScene);
- calledEmitUpdated = false;
// Ensure all views are connected if anything is connected. This disables
// the optimization that items send updates directly to the views, but it
@@ -633,6 +374,7 @@ void QGraphicsScenePrivate::_q_emitUpdated()
void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
{
needSortTopLevelItems = true;
+ item->d_ptr->siblingIndex = topLevelItems.size();
topLevelItems.append(item);
}
@@ -642,19 +384,10 @@ void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
{
topLevelItems.removeOne(item);
-}
-
-/*!
- \internal
-
- Updates all items in the pending update list. At this point, the list is
- unlikely to contain partially constructed items.
-*/
-void QGraphicsScenePrivate::_q_updateLater()
-{
- foreach (QGraphicsItem *item, pendingUpdateItems)
- item->update();
- pendingUpdateItems.clear();
+ // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because
+ // the item is not guaranteed to be at the index after the list is sorted
+ // (see ensureSortedTopLevelItems()).
+ item->d_ptr->siblingIndex = -1;
}
/*!
@@ -680,9 +413,23 @@ void QGraphicsScenePrivate::_q_processDirtyItems()
{
processDirtyItemsEmitted = false;
+ if (updateAll) {
+ Q_ASSERT(calledEmitUpdated);
+ // No need for further processing (except resetting the dirty states).
+ // The growingItemsBoundingRect is updated in _q_emitUpdated.
+ for (int i = 0; i < topLevelItems.size(); ++i)
+ resetDirtyItem(topLevelItems.at(i), /*recursive=*/true);
+ return;
+ }
+
const bool wasPendingSceneUpdate = calledEmitUpdated;
const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
- processDirtyItemsRecursive(0);
+
+ // Process items recursively.
+ for (int i = 0; i < topLevelItems.size(); ++i)
+ processDirtyItemsRecursive(topLevelItems.at(i));
+
+ dirtyGrowingItemsBoundingRect = false;
if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
emit q_func()->sceneRectChanged(growingItemsBoundingRect);
@@ -727,22 +474,16 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
// Clear focus on the item to remove any reference in the focusWidget chain.
item->clearFocus();
+
markDirty(item, QRectF(), false, false, false, false, /*removingItemFromScene=*/true);
- if (!item->d_ptr->inDestructor) {
+ if (item->d_ptr->inDestructor) {
+ // The item is actually in its destructor, we call the special method in the index.
+ index->deleteItem(item);
+ } else {
// Can potentially call item->boundingRect() (virtual function), that's why
// we only can call this function if the item is not in its destructor.
- removeFromIndex(item);
- } else if (item->d_ptr->index != -1) {
- // Important: The index is useless until purgeRemovedItems() is called.
- indexedItems[item->d_ptr->index] = (QGraphicsItem *)0;
- if (!purgePending)
- purgePending = true;
- removedItems << item;
- } else {
- // Recently added items are purged immediately. unindexedItems() never
- // contains stale items.
- unindexedItems.removeAll(item);
+ index->removeItem(item);
}
if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
@@ -763,17 +504,6 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
unregisterTopLevelItem(item);
}
- if (!item->d_ptr->inDestructor) {
- // Remove from our item lists.
- int index = item->d_func()->index;
- if (index != -1) {
- freeItemIndexes << index;
- indexedItems[index] = 0;
- } else {
- unindexedItems.removeAll(item);
- }
- }
-
// Reset the mouse grabber and focus item data.
if (item == focusItem)
focusItem = 0;
@@ -793,7 +523,6 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
hoverItems.removeAll(item);
cachedItemsUnderMouse.removeAll(item);
unpolishedItems.removeAll(item);
- pendingUpdateItems.removeAll(item);
resetDirtyItem(item);
//We remove all references of item from the sceneEventFilter arrays
@@ -831,45 +560,6 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
/*!
\internal
-
- Removes stale pointers from all data structures.
-*/
-void QGraphicsScenePrivate::purgeRemovedItems()
-{
- if (!purgePending && removedItems.isEmpty())
- return;
-
- // Remove stale items from the BSP tree.
- if (indexMethod != QGraphicsScene::NoIndex)
- bspTree.removeItems(removedItems);
-
- // Purge this list.
- removedItems.clear();
- freeItemIndexes.clear();
- for (int i = 0; i < indexedItems.size(); ++i) {
- if (!indexedItems.at(i))
- freeItemIndexes << i;
- }
- purgePending = false;
-}
-
-/*!
- \internal
-
- Starts or restarts the timer used for reindexing unindexed items.
-*/
-void QGraphicsScenePrivate::startIndexTimer(int interval)
-{
- Q_Q(QGraphicsScene);
- if (indexTimerId) {
- restartIndexTimer = true;
- } else {
- indexTimerId = q->startTimer(interval);
- }
-}
-
-/*!
- \internal
*/
void QGraphicsScenePrivate::addPopup(QGraphicsWidget *widget)
{
@@ -1104,41 +794,20 @@ QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &scre
{
Q_Q(const QGraphicsScene);
QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
- QList<QGraphicsItem *> items;
- if (view)
- items = view->items(view->viewport()->mapFromGlobal(screenPos));
- else
- items = q->items(scenePos);
- return items;
-}
+ if (!view)
+ return q->items(scenePos, Qt::IntersectsItemShape, Qt::AscendingOrder, QTransform());
-/*!
- \internal
+ const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));
+ if (!view->isTransformed())
+ return q->items(pointRect, Qt::IntersectsItemShape, Qt::AscendingOrder);
- Checks if item collides with the path and mode, but also checks that if it
- doesn't collide, maybe its frame rect will.
-*/
-bool QGraphicsScenePrivate::itemCollidesWithPath(QGraphicsItem *item,
- const QPainterPath &path,
- Qt::ItemSelectionMode mode)
-{
- if (item->collidesWithPath(path, mode))
- return true;
- if (item->isWidget()) {
- // Check if this is a window, and if its frame rect collides.
- QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
- if (widget->isWindow()) {
- QRectF frameRect = widget->windowFrameRect();
- QPainterPath framePath;
- framePath.addRect(frameRect);
- bool intersects = path.intersects(frameRect);
- if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
- return intersects || path.contains(frameRect.topLeft())
- || framePath.contains(path.elementAt(0));
- return !intersects && path.contains(frameRect.topLeft());
- }
+ const QTransform viewTransform = view->viewportTransform();
+ if (viewTransform.type() <= QTransform::TxScale) {
+ return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape,
+ Qt::AscendingOrder, viewTransform);
}
- return false;
+ return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape,
+ Qt::AscendingOrder, viewTransform);
}
/*!
@@ -1150,7 +819,7 @@ void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouse
if (event->buttons() & i) {
mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(),
- event->widget()));
+ event->widget()));
mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
}
@@ -1428,779 +1097,6 @@ QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item)
return 0;
}
-QList<QGraphicsItem *> QGraphicsScenePrivate::topLevelItemsInStackingOrder(const QTransform *const viewTransform,
- QRegion *exposedRegion)
-{
- if (indexMethod == QGraphicsScene::NoIndex || !exposedRegion) {
- if (needSortTopLevelItems) {
- needSortTopLevelItems = false;
- qStableSort(topLevelItems.begin(), topLevelItems.end(), qt_notclosestLeaf);
- }
- return topLevelItems;
- }
-
- const QRectF exposedRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
- QRectF sceneRect;
- QTransform invertedViewTransform(Qt::Uninitialized);
- if (!viewTransform) {
- sceneRect = exposedRect;
- } else {
- invertedViewTransform = viewTransform->inverted();
- sceneRect = invertedViewTransform.mapRect(exposedRect);
- }
- if (!largestUntransformableItem.isEmpty()) {
- // ### Nuke this when we move the indexing code into a separate
- // class. All the largestUntransformableItem code should then go
- // away, and the estimate function should return untransformable
- // items as well.
- QRectF untr = largestUntransformableItem;
- QRectF ltri = !viewTransform ? untr : invertedViewTransform.mapRect(untr);
- ltri.adjust(-untr.width(), -untr.height(), untr.width(), untr.height());
- sceneRect.adjust(-ltri.width(), -ltri.height(), ltri.width(), ltri.height());
- }
-
- QList<QGraphicsItem *> tmp = estimateItemsInRect(sceneRect);
- for (int i = 0; i < tmp.size(); ++i)
- tmp.at(i)->topLevelItem()->d_ptr->itemDiscovered = 1;
-
- // Sort if the toplevel list is unsorted.
- if (needSortTopLevelItems) {
- needSortTopLevelItems = false;
- qStableSort(topLevelItems.begin(), topLevelItems.end(), qt_notclosestLeaf);
- }
-
- QList<QGraphicsItem *> tli;
- for (int i = 0; i < topLevelItems.size(); ++i) {
- // ### Investigate smarter ways. Looping through all top level
- // items is not optimal. If the BSP tree is to have maximum
- // effect, it should be possible to sort the subset of items
- // quickly. We must use this approach for now, as it's the only
- // current way to keep the stable sorting order (insertion order).
- QGraphicsItem *item = topLevelItems.at(i);
- if (item->d_ptr->itemDiscovered) {
- item->d_ptr->itemDiscovered = 0;
- tli << item;
- }
- }
- return tli;
-}
-
-void QGraphicsScenePrivate::recursive_items_helper(QGraphicsItem *item, QRectF rect,
- QList<QGraphicsItem *> *items,
- const QTransform &parentTransform,
- const QTransform &viewTransform,
- Qt::ItemSelectionMode mode, Qt::SortOrder order,
- qreal parentOpacity) const
-{
- // Calculate opacity.
- qreal opacity;
- if (item) {
- if (!item->d_ptr->visible)
- return;
- QGraphicsItem *p = item->d_ptr->parent;
- bool itemIgnoresParentOpacity = item->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity;
- bool parentDoesntPropagateOpacity = (p && (p->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren));
- if (!itemIgnoresParentOpacity && !parentDoesntPropagateOpacity) {
- opacity = parentOpacity * item->opacity();
- } else {
- opacity = item->d_ptr->opacity;
- }
- if (opacity == 0.0 && !(item->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren))
- return;
- } else {
- opacity = parentOpacity;
- }
-
- // Calculate the full transform for this item.
- QTransform transform = parentTransform;
- bool keep = false;
- if (item) {
- item->d_ptr->combineTransformFromParent(&transform, &viewTransform);
-
- // ### This does not take the clip into account.
- QRectF brect = item->boundingRect();
- _q_adjustRect(&brect);
-
- keep = true;
- if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
- keep = rect.contains(transform.mapRect(brect)) && rect != brect;
- else
- keep = rect.intersects(transform.mapRect(brect));
-
- if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
- QPainterPath rectPath;
- rectPath.addRect(rect);
- keep = itemCollidesWithPath(item, transform.inverted().map(rectPath), mode);
- }
- }
-
- bool childClip = (item && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape));
- bool dontProcessItem = !item || !keep;
- bool dontProcessChildren = item && dontProcessItem && childClip;
-
- // Find and sort children.
- QList<QGraphicsItem *> &children = item ? item->d_ptr->children : const_cast<QGraphicsScenePrivate *>(this)->topLevelItems;
- if (!dontProcessChildren) {
- if (item && item->d_ptr->needSortChildren) {
- item->d_ptr->needSortChildren = 0;
- qStableSort(children.begin(), children.end(), qt_notclosestLeaf);
- } else if (!item && needSortTopLevelItems) {
- const_cast<QGraphicsScenePrivate *>(this)->needSortTopLevelItems = false;
- qStableSort(children.begin(), children.end(), qt_notclosestLeaf);
- }
- }
-
- childClip &= !dontProcessChildren & !children.isEmpty();
-
- // Clip.
- if (childClip)
- rect &= transform.map(item->shape()).controlPointRect();
-
- // Process children behind
- int i = 0;
- if (!dontProcessChildren) {
- for (i = 0; i < children.size(); ++i) {
- QGraphicsItem *child = children.at(i);
- if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
- break;
- recursive_items_helper(child, rect, items, transform, viewTransform,
- mode, order, opacity);
- }
- }
-
- // Process item
- if (!dontProcessItem)
- items->append(item);
-
- // Process children in front
- if (!dontProcessChildren) {
- for (; i < children.size(); ++i)
- recursive_items_helper(children.at(i), rect, items, transform, viewTransform,
- mode, order, opacity);
- }
-
- if (!item && order == Qt::AscendingOrder) {
- int n = items->size();
- for (int i = 0; i < n / 2; ++i) {
- QGraphicsItem *tmp = (*items)[n - i - 1];
- (*items)[n - i - 1] = (*items)[i];
- (*items)[i] = tmp;
- }
- }
-}
-
-QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPointF &pos) const
-{
- QList<QGraphicsItem *> items;
-
- // The index returns a rough estimate of what items are inside the rect.
- // Refine it by iterating through all returned items.
- QRectF adjustedRect = QRectF(pos, QSize(1,1));
- foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {
- // Find the item's scene transform in a clever way.
- QTransform x = item->sceneTransform();
- bool keep = false;
-
- // ### _q_adjustedRect is only needed because QRectF::intersects,
- // QRectF::contains and QTransform::map() and friends don't work with
- // flat rectangles.
- const QRectF br(adjustedItemBoundingRect(item));
- // Rect intersects/contains item's shape
- if (QRectF_intersects(adjustedRect, x.mapRect(br))) {
- bool ok;
- QTransform xinv = x.inverted(&ok);
- if (ok) {
- if (item->contains(xinv.map(pos))) {
- items << item;
- keep = true;
- }
- }
- }
-
- if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
- // Recurse into children that clip children.
- bool ok;
- QTransform xinv = x.inverted(&ok);
- if (ok)
- childItems_helper(&items, item, xinv.map(pos));
- }
- }
-
- sortItems(&items, Qt::AscendingOrder, sortCacheEnabled);
- return items;
-}
-
-QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect,
- Qt::ItemSelectionMode mode,
- Qt::SortOrder order) const
-{
- QList<QGraphicsItem *> items;
-
- QPainterPath path;
-
- // The index returns a rough estimate of what items are inside the rect.
- // Refine it by iterating through all returned items.
- QRectF adjustedRect(rect);
- _q_adjustRect(&adjustedRect);
- foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {
- // Find the item's scene transform in a clever way.
- QTransform x = item->sceneTransform();
- bool keep = false;
-
- // ### _q_adjustedRect is only needed because QRectF::intersects,
- // QRectF::contains and QTransform::map() and friends don't work with
- // flat rectangles.
- const QRectF br(adjustedItemBoundingRect(item));
- if (mode >= Qt::ContainsItemBoundingRect) {
- // Rect intersects/contains item's bounding rect
- QRectF mbr = x.mapRect(br);
- if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))
- || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(mbr))) {
- items << item;
- keep = true;
- }
- } else {
- // Rect intersects/contains item's shape
- if (QRectF_intersects(adjustedRect, x.mapRect(br))) {
- bool ok;
- QTransform xinv = x.inverted(&ok);
- if (ok) {
- if (path.isEmpty())
- path.addRect(rect);
- if (itemCollidesWithPath(item, xinv.map(path), mode)) {
- items << item;
- keep = true;
- }
- }
- }
- }
-
- if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
- // Recurse into children that clip children.
- bool ok;
- QTransform xinv = x.inverted(&ok);
- if (ok) {
- if (x.type() <= QTransform::TxScale) {
- // Rect
- childItems_helper(&items, item, xinv.mapRect(rect), mode);
- } else {
- // Polygon
- childItems_helper(&items, item, xinv.map(rect), mode);
- }
- }
- }
- }
-
- if (order != Qt::SortOrder(-1))
- sortItems(&items, order, sortCacheEnabled);
- return items;
-}
-
-QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPolygonF &polygon,
- Qt::ItemSelectionMode mode,
- Qt::SortOrder order) const
-{
- QList<QGraphicsItem *> items;
-
- QRectF polyRect(polygon.boundingRect());
- _q_adjustRect(&polyRect);
- QPainterPath path;
-
- // The index returns a rough estimate of what items are inside the rect.
- // Refine it by iterating through all returned items.
- foreach (QGraphicsItem *item, estimateItemsInRect(polyRect)) {
- // Find the item's scene transform in a clever way.
- QTransform x = item->sceneTransform();
- bool keep = false;
-
- // ### _q_adjustedRect is only needed because QRectF::intersects,
- // QRectF::contains and QTransform::map() and friends don't work with
- // flat rectangles.
- const QRectF br(adjustedItemBoundingRect(item));
- if (mode >= Qt::ContainsItemBoundingRect) {
- // Polygon contains/intersects item's bounding rect
- if (path == QPainterPath())
- path.addPolygon(polygon);
- if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))
- || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {
- items << item;
- keep = true;
- }
- } else {
- // Polygon contains/intersects item's shape
- if (QRectF_intersects(polyRect, x.mapRect(br))) {
- bool ok;
- QTransform xinv = x.inverted(&ok);
- if (ok) {
- if (path == QPainterPath())
- path.addPolygon(polygon);
- if (itemCollidesWithPath(item, xinv.map(path), mode)) {
- items << item;
- keep = true;
- }
- }
- }
- }
-
- if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
- // Recurse into children that clip children.
- bool ok;
- QTransform xinv = x.inverted(&ok);
- if (ok)
- childItems_helper(&items, item, xinv.map(polygon), mode);
- }
- }
-
- if (order != Qt::SortOrder(-1))
- sortItems(&items, order, sortCacheEnabled);
- return items;
-}
-
-QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPainterPath &path,
- Qt::ItemSelectionMode mode,
- Qt::SortOrder order) const
-{
- QList<QGraphicsItem *> items;
- QRectF pathRect(path.controlPointRect());
- _q_adjustRect(&pathRect);
-
- // The index returns a rough estimate of what items are inside the rect.
- // Refine it by iterating through all returned items.
- foreach (QGraphicsItem *item, estimateItemsInRect(pathRect)) {
- // Find the item's scene transform in a clever way.
- QTransform x = item->sceneTransform();
- bool keep = false;
-
- // ### _q_adjustedRect is only needed because QRectF::intersects,
- // QRectF::contains and QTransform::map() and friends don't work with
- // flat rectangles.
- const QRectF br(adjustedItemBoundingRect(item));
- if (mode >= Qt::ContainsItemBoundingRect) {
- // Path contains/intersects item's bounding rect
- if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))
- || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {
- items << item;
- keep = true;
- }
- } else {
- // Path contains/intersects item's shape
- if (QRectF_intersects(pathRect, x.mapRect(br))) {
- bool ok;
- QTransform xinv = x.inverted(&ok);
- if (ok) {
- if (itemCollidesWithPath(item, xinv.map(path), mode)) {
- items << item;
- keep = true;
- }
- }
- }
- }
-
- if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
- bool ok;
- QTransform xinv = x.inverted(&ok);
- if (ok)
- childItems_helper(&items, item, xinv.map(path), mode);
- }
- }
-
- if (order != Qt::SortOrder(-1))
- sortItems(&items, order, sortCacheEnabled);
- return items;
-}
-
-void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
- const QGraphicsItem *parent,
- const QPointF &pos) const
-{
- bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
- if (parentClip && parent->d_ptr->isClippedAway())
- return;
- // ### is this needed?
- if (parentClip && !parent->boundingRect().contains(pos))
- return;
-
- QList<QGraphicsItem *> &children = parent->d_ptr->children;
- for (int i = 0; i < children.size(); ++i) {
- QGraphicsItem *item = children.at(i);
- if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible())
- continue;
-
- // Skip invisible items and all their children.
- if (item->d_ptr->isInvisible())
- continue;
-
- bool keep = false;
- if (!item->d_ptr->isClippedAway()) {
- if (item->contains(item->mapFromParent(pos))) {
- items->append(item);
- keep = true;
- }
- }
-
- if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty())
- // Recurse into children.
- childItems_helper(items, item, item->mapFromParent(pos));
- }
-}
-
-
-void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
- const QGraphicsItem *parent,
- const QRectF &rect,
- Qt::ItemSelectionMode mode) const
-{
- bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
- if (parentClip && parent->d_ptr->isClippedAway())
- return;
- QRectF adjustedRect(rect);
- _q_adjustRect(&adjustedRect);
- QRectF r = !parentClip ? adjustedRect : adjustedRect.intersected(adjustedItemBoundingRect(parent));
- if (r.isEmpty())
- return;
-
- QPainterPath path;
- QList<QGraphicsItem *> &children = parent->d_ptr->children;
- for (int i = 0; i < children.size(); ++i) {
- QGraphicsItem *item = children.at(i);
- if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible())
- continue;
-
- // Skip invisible items and all their children.
- if (item->d_ptr->isInvisible())
- continue;
-
- bool keep = false;
- if (!item->d_ptr->isClippedAway()) {
- // ### _q_adjustedRect is only needed because QRectF::intersects,
- // QRectF::contains and QTransform::map() and friends don't work with
- // flat rectangles.
- const QRectF br(adjustedItemBoundingRect(item));
- QRectF mbr = item->mapRectToParent(br);
- if (mode >= Qt::ContainsItemBoundingRect) {
- // Rect intersects/contains item's bounding rect
- if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))
- || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) {
- items->append(item);
- keep = true;
- }
- } else {
- // Rect intersects/contains item's shape
- if (QRectF_intersects(rect, mbr)) {
- if (path == QPainterPath())
- path.addRect(rect);
- if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
- items->append(item);
- keep = true;
- }
- }
- }
- }
-
- if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
- // Recurse into children.
- if (!item->d_ptr->transformData || item->d_ptr->transformData->computedFullTransform().type() <= QTransform::TxScale) {
- // Rect
- childItems_helper(items, item, item->mapRectFromParent(rect), mode);
- } else {
- // Polygon
- childItems_helper(items, item, item->mapFromParent(rect), mode);
- }
- }
- }
-}
-
-
-void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
- const QGraphicsItem *parent,
- const QPolygonF &polygon,
- Qt::ItemSelectionMode mode) const
-{
- bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
- if (parentClip && parent->d_ptr->isClippedAway())
- return;
- QRectF polyRect(polygon.boundingRect());
- _q_adjustRect(&polyRect);
- QRectF r = !parentClip ? polyRect : polyRect.intersected(adjustedItemBoundingRect(parent));
- if (r.isEmpty())
- return;
-
- QPainterPath path;
- QList<QGraphicsItem *> &children = parent->d_ptr->children;
- for (int i = 0; i < children.size(); ++i) {
- QGraphicsItem *item = children.at(i);
- if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible())
- continue;
-
- // Skip invisible items.
- if (item->d_ptr->isInvisible())
- continue;
-
- bool keep = false;
- if (!item->d_ptr->isClippedAway()) {
- // ### _q_adjustedRect is only needed because QRectF::intersects,
- // QRectF::contains and QTransform::map() and friends don't work with
- // flat rectangles.
- const QRectF br(adjustedItemBoundingRect(item));
- if (mode >= Qt::ContainsItemBoundingRect) {
- // Polygon contains/intersects item's bounding rect
- if (path == QPainterPath())
- path.addPolygon(polygon);
- if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))
- || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {
- items->append(item);
- keep = true;
- }
- } else {
- // Polygon contains/intersects item's shape
- if (QRectF_intersects(polyRect, item->mapRectToParent(br))) {
- if (path == QPainterPath())
- path.addPolygon(polygon);
- if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
- items->append(item);
- keep = true;
- }
- }
- }
- }
-
- if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
- // Recurse into children that clip children.
- childItems_helper(items, item, item->mapFromParent(polygon), mode);
- }
- }
-}
-
-void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
- const QGraphicsItem *parent,
- const QPainterPath &path,
- Qt::ItemSelectionMode mode) const
-{
- bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
- if (parentClip && parent->d_ptr->isClippedAway())
- return;
- QRectF pathRect(path.boundingRect());
- _q_adjustRect(&pathRect);
- QRectF r = !parentClip ? pathRect : pathRect.intersected(adjustedItemBoundingRect(parent));
- if (r.isEmpty())
- return;
-
- QList<QGraphicsItem *> &children = parent->d_ptr->children;
- for (int i = 0; i < children.size(); ++i) {
- QGraphicsItem *item = children.at(i);
- if (item->d_ptr->transformData && !item->d_ptr->transformData->computedFullTransform().isInvertible())
- continue;
-
- // Skip invisible items.
- if (item->d_ptr->isInvisible())
- continue;
-
- bool keep = false;
- if (!item->d_ptr->isClippedAway()) {
- // ### _q_adjustedRect is only needed because QRectF::intersects,
- // QRectF::contains and QTransform::map() and friends don't work with
- // flat rectangles.
- const QRectF br(adjustedItemBoundingRect(item));
- if (mode >= Qt::ContainsItemBoundingRect) {
- // Polygon contains/intersects item's bounding rect
- if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))
- || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {
- items->append(item);
- keep = true;
- }
- } else {
- // Path contains/intersects item's shape
- if (QRectF_intersects(pathRect, item->mapRectToParent(br))) {
- if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
- items->append(item);
- keep = true;
- }
- }
- }
- }
-
- if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
- // Recurse into children that clip children.
- childItems_helper(items, item, item->mapFromParent(path), mode);
- }
- }
-}
-
-void QGraphicsScenePrivate::invalidateSortCache()
-{
- Q_Q(QGraphicsScene);
- if (!sortCacheEnabled || updatingSortCache)
- return;
-
- updatingSortCache = true;
- QMetaObject::invokeMethod(q, "_q_updateSortCache", Qt::QueuedConnection);
-}
-
-/*!
- \internal
-
- Should not be exported, but we can't change that now.
- ### Qt 5: Remove symbol / make static
-*/
-inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
-{
- // Return true if sibling item1 is on top of item2.
- const QGraphicsItemPrivate *d1 = item1->d_ptr;
- const QGraphicsItemPrivate *d2 = item2->d_ptr;
- bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent;
- bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent;
- if (f1 != f2) return f2;
- qreal z1 = d1->z;
- qreal z2 = d2->z;
- return z1 > z2;
-}
-
-static inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
-{
- return qt_closestLeaf(item2, item1);
-}
-
-/*!
- \internal
-
- Should not be exported, but we can't change that now.
-*/
-inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2)
-{
- return QGraphicsScenePrivate::closestItemFirst_withoutCache(item1, item2);
-}
-
-/*!
- Returns true if \a item1 is on top of \a item2.
-
- \internal
-*/
-bool QGraphicsScenePrivate::closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
-{
- // Siblings? Just check their z-values.
- const QGraphicsItemPrivate *d1 = item1->d_ptr;
- const QGraphicsItemPrivate *d2 = item2->d_ptr;
- if (d1->parent == d2->parent)
- return qt_closestLeaf(item1, item2);
-
- // Find common ancestor, and each item's ancestor closest to the common
- // ancestor.
- int item1Depth = d1->depth;
- int item2Depth = d2->depth;
- const QGraphicsItem *p = item1;
- const QGraphicsItem *t1 = item1;
- while (item1Depth > item2Depth && (p = p->d_ptr->parent)) {
- if (p == item2) {
- // item2 is one of item1's ancestors; item1 is on top
- return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
- }
- t1 = p;
- --item1Depth;
- }
- p = item2;
- const QGraphicsItem *t2 = item2;
- while (item2Depth > item1Depth && (p = p->d_ptr->parent)) {
- if (p == item1) {
- // item1 is one of item2's ancestors; item1 is not on top
- return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
- }
- t2 = p;
- --item2Depth;
- }
-
- // item1Ancestor is now at the same level as item2Ancestor, but not the same.
- const QGraphicsItem *a1 = t1;
- const QGraphicsItem *a2 = t2;
- while (a1) {
- const QGraphicsItem *p1 = a1;
- const QGraphicsItem *p2 = a2;
- a1 = a1->parentItem();
- a2 = a2->parentItem();
- if (a1 && a1 == a2)
- return qt_closestLeaf(p1, p2);
- }
-
- // No common ancestor? Then just compare the items' toplevels directly.
- return qt_closestLeaf(t1->topLevelItem(), t2->topLevelItem());
-}
-
-/*!
- Returns true if \a item2 is on top of \a item1.
-
- \internal
-*/
-bool QGraphicsScenePrivate::closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
-{
- return closestItemFirst_withoutCache(item2, item1);
-}
-
-void QGraphicsScenePrivate::climbTree(QGraphicsItem *item, int *stackingOrder)
-{
- if (!item->d_ptr->children.isEmpty()) {
- QList<QGraphicsItem *> childList = item->d_ptr->children;
- qSort(childList.begin(), childList.end(), qt_closestLeaf);
- for (int i = 0; i < childList.size(); ++i) {
- QGraphicsItem *item = childList.at(i);
- if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))
- climbTree(childList.at(i), stackingOrder);
- }
- item->d_ptr->globalStackingOrder = (*stackingOrder)++;
- for (int i = 0; i < childList.size(); ++i) {
- QGraphicsItem *item = childList.at(i);
- if (item->flags() & QGraphicsItem::ItemStacksBehindParent)
- climbTree(childList.at(i), stackingOrder);
- }
- } else {
- item->d_ptr->globalStackingOrder = (*stackingOrder)++;
- }
-}
-
-void QGraphicsScenePrivate::_q_updateSortCache()
-{
- _q_updateIndex();
-
- if (!sortCacheEnabled || !updatingSortCache)
- return;
-
- updatingSortCache = false;
- int stackingOrder = 0;
-
- QList<QGraphicsItem *> topLevels;
-
- for (int i = 0; i < indexedItems.size(); ++i) {
- QGraphicsItem *item = indexedItems.at(i);
- if (item && item->parentItem() == 0)
- topLevels << item;
- }
- for (int i = 0; i < unindexedItems.size(); ++i) {
- QGraphicsItem *item = unindexedItems.at(i);
- if (item->parentItem() == 0)
- topLevels << item;
- }
-
- qSort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
- for (int i = 0; i < topLevels.size(); ++i)
- climbTree(topLevels.at(i), &stackingOrder);
-}
-
-void QGraphicsScenePrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
- bool sortCacheEnabled)
-{
- if (sortCacheEnabled) {
- if (order == Qt::AscendingOrder) {
- qSort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
- } else if (order == Qt::DescendingOrder) {
- qSort(itemList->begin(), itemList->end(), closestItemLast_withCache);
- }
- } else {
- if (order == Qt::AscendingOrder) {
- qSort(itemList->begin(), itemList->end(), closestItemFirst_withoutCache);
- } else if (order == Qt::DescendingOrder) {
- qSort(itemList->begin(), itemList->end(), closestItemLast_withoutCache);
- }
- }
-}
-
/*!
\internal
@@ -2333,8 +1229,8 @@ QGraphicsScene::QGraphicsScene(QObject *parent)
QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
: QObject(*new QGraphicsScenePrivate, parent)
{
- setSceneRect(sceneRect);
d_func()->init();
+ setSceneRect(sceneRect);
}
/*!
@@ -2348,8 +1244,8 @@ QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
: QObject(*new QGraphicsScenePrivate, parent)
{
- setSceneRect(x, y, width, height);
d_func()->init();
+ setSceneRect(x, y, width, height);
}
/*!
@@ -2386,8 +1282,19 @@ QGraphicsScene::~QGraphicsScene()
QRectF QGraphicsScene::sceneRect() const
{
Q_D(const QGraphicsScene);
- const_cast<QGraphicsScenePrivate *>(d)->_q_updateIndex();
- return d->hasSceneRect ? d->sceneRect : d->growingItemsBoundingRect;
+ if (d->hasSceneRect)
+ return d->sceneRect;
+
+ if (d->dirtyGrowingItemsBoundingRect) {
+ // Lazily update the growing items bounding rect
+ QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d);
+ QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect;
+ thatd->growingItemsBoundingRect |= itemsBoundingRect();
+ thatd->dirtyGrowingItemsBoundingRect = false;
+ if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect)
+ emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect);
+ }
+ return d->growingItemsBoundingRect;
}
void QGraphicsScene::setSceneRect(const QRectF &rect)
{
@@ -2395,8 +1302,7 @@ void QGraphicsScene::setSceneRect(const QRectF &rect)
if (rect != d->sceneRect) {
d->hasSceneRect = !rect.isNull();
d->sceneRect = rect;
- d->resetIndex();
- emit sceneRectChanged(rect);
+ emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect);
}
}
@@ -2437,6 +1343,8 @@ void QGraphicsScene::setSceneRect(const QRectF &rect)
void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
Qt::AspectRatioMode aspectRatioMode)
{
+ // ### Switch to using the recursive rendering algorithm instead.
+
// Default source rect = scene rect
QRectF sourceRect = source;
if (sourceRect.isNull())
@@ -2531,8 +1439,19 @@ QGraphicsScene::ItemIndexMethod QGraphicsScene::itemIndexMethod() const
void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
{
Q_D(QGraphicsScene);
- d->resetIndex();
+ if (d->indexMethod == method)
+ return;
+
d->indexMethod = method;
+
+ QList<QGraphicsItem *> oldItems = d->index->items(Qt::AscendingOrder);
+ delete d->index;
+ if (method == BspTreeIndex)
+ d->index = new QGraphicsSceneBspTreeIndex(this);
+ else
+ d->index = new QGraphicsSceneLinearIndex(this);
+ for (int i = oldItems.size() - 1; i >= 0; --i)
+ d->index->addItem(oldItems.at(i));
}
/*!
@@ -2570,35 +1489,32 @@ void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
int QGraphicsScene::bspTreeDepth() const
{
Q_D(const QGraphicsScene);
- return d->bspTreeDepth;
+ QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
+ return bspTree ? bspTree->bspTreeDepth() : 0;
}
void QGraphicsScene::setBspTreeDepth(int depth)
{
Q_D(QGraphicsScene);
- if (d->bspTreeDepth == depth)
- return;
-
if (depth < 0) {
qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
return;
}
- d->bspTreeDepth = depth;
- d->resetIndex();
+ QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
+ if (!bspTree) {
+ qWarning("QGraphicsScene::setBspTreeDepth: can not apply if indexing method is not BSP");
+ return;
+ }
+ bspTree->setBspTreeDepth(depth);
}
/*!
\property QGraphicsScene::sortCacheEnabled
\brief whether sort caching is enabled
\since 4.5
+ \obsolete
- When enabled, this property adds a cache that speeds up sorting and
- transformations for scenes with deep hierarchies (i.e., items with many
- levels of descendents), at the cost of using more memory (approx. 100 more
- bytes of memory per item).
-
- Items that are not part of a deep hierarchy suffer no penalty from this
- cache.
+ Since Qt 4.6, this property has no effect.
*/
bool QGraphicsScene::isSortCacheEnabled() const
{
@@ -2608,10 +1524,9 @@ bool QGraphicsScene::isSortCacheEnabled() const
void QGraphicsScene::setSortCacheEnabled(bool enabled)
{
Q_D(QGraphicsScene);
- if (enabled == d->sortCacheEnabled)
+ if (d->sortCacheEnabled == enabled)
return;
- if ((d->sortCacheEnabled = enabled))
- d->invalidateSortCache();
+ d->sortCacheEnabled = enabled;
}
/*!
@@ -2623,6 +1538,7 @@ void QGraphicsScene::setSortCacheEnabled(bool enabled)
*/
QRectF QGraphicsScene::itemsBoundingRect() const
{
+ // Does not take untransformable items into account.
QRectF boundingRect;
foreach (QGraphicsItem *item, items())
boundingRect |= item->sceneBoundingRect();
@@ -2637,29 +1553,24 @@ QRectF QGraphicsScene::itemsBoundingRect() const
QList<QGraphicsItem *> QGraphicsScene::items() const
{
Q_D(const QGraphicsScene);
- const_cast<QGraphicsScenePrivate *>(d)->purgeRemovedItems();
+ return d->index->items(Qt::AscendingOrder);
+}
- // If freeItemIndexes is empty, we know there are no holes in indexedItems and
- // unindexedItems.
- if (d->freeItemIndexes.isEmpty()) {
- if (d->unindexedItems.isEmpty())
- return d->indexedItems;
- return d->indexedItems + d->unindexedItems;
- }
+/*!
+ Returns an ordered list of all items on the scene. \a order decides the
+ sorting.
- // Rebuild the list of items to avoid holes. ### We could also just
- // compress the item lists at this point.
- QList<QGraphicsItem *> itemList;
- foreach (QGraphicsItem *item, d->indexedItems + d->unindexedItems) {
- if (item)
- itemList << item;
- }
- return itemList;
+ \sa addItem(), removeItem()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const
+{
+ Q_D(const QGraphicsScene);
+ return d->index->items(order);
}
/*!
Returns all visible items at position \a pos in the scene. The items are
- listed in descending Z order (i.e., the first item in the list is the
+ listed in descending stacking order (i.e., the first item in the list is the
top-most item, and the last item is the bottom-most item).
\sa itemAt()
@@ -2667,7 +1578,7 @@ QList<QGraphicsItem *> QGraphicsScene::items() const
QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
{
Q_D(const QGraphicsScene);
- return d->items_helper(pos);
+ return d->index->items(pos, Qt::IntersectsItemShape, Qt::AscendingOrder);
}
/*!
@@ -2686,9 +1597,7 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode) const
{
Q_D(const QGraphicsScene);
- QList<QGraphicsItem *> itemList;
- d->recursive_items_helper(0, rect, &itemList, QTransform(), QTransform(), mode, Qt::AscendingOrder);
- return itemList;
+ return d->index->items(rect, mode, Qt::AscendingOrder);
}
/*!
@@ -2712,7 +1621,7 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelecti
QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
{
Q_D(const QGraphicsScene);
- return d->items_helper(polygon, mode, Qt::AscendingOrder);
+ return d->index->items(polygon, mode, Qt::AscendingOrder);
}
/*!
@@ -2729,7 +1638,85 @@ QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemS
QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
{
Q_D(const QGraphicsScene);
- return d->items_helper(path, mode, Qt::AscendingOrder);
+ return d->index->items(path, mode, Qt::AscendingOrder);
+}
+
+/*!
+ Returns all visible items that, depending on \a mode, are at the specified \a pos
+ and return a list sorted using \a order.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with \a pos are returned.
+
+ \a deviceTransform is the transformation apply to the view.
+
+ \sa itemAt()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform) const
+{
+ Q_D(const QGraphicsScene);
+ return d->index->items(pos, mode, order, deviceTransform);
+}
+
+/*!
+ \overload
+
+ Returns all visible items that, depending on \a mode, are either inside or
+ intersect with the specified \a rect and return a list sorted using \a order.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a rect are returned.
+
+ \a deviceTransform is the transformation apply to the view.
+
+ \sa itemAt()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform) const
+{
+ Q_D(const QGraphicsScene);
+ return d->index->items(rect, mode, order, deviceTransform);
+}
+
+/*!
+ \overload
+
+ Returns all visible items that, depending on \a mode, are either inside or
+ intersect with the specified \a polygon and return a list sorted using \a order.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a polygon are returned.
+
+ \a deviceTransform is the transformation apply to the view.
+
+ \sa itemAt()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform) const
+{
+ Q_D(const QGraphicsScene);
+ return d->index->items(polygon, mode, order, deviceTransform);
+}
+
+/*!
+ \overload
+
+ Returns all visible items that, depending on \a mode, are either inside or
+ intersect with the specified \a path and return a list sorted using \a order.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a path are returned.
+
+ \a deviceTransform is the transformation apply to the view.
+
+ \sa itemAt()
+*/
+QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform) const
+{
+ Q_D(const QGraphicsScene);
+ return d->index->items(path, mode, order, deviceTransform);
}
/*!
@@ -2752,12 +1739,12 @@ QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
return QList<QGraphicsItem *>();
}
+ // Does not support ItemIgnoresTransformations.
QList<QGraphicsItem *> tmp;
- foreach (QGraphicsItem *itemInVicinity, d->estimateItemsInRect(item->sceneBoundingRect())) {
+ foreach (QGraphicsItem *itemInVicinity, d->index->estimateItems(item->sceneBoundingRect(), Qt::AscendingOrder)) {
if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
tmp << itemInVicinity;
}
- d->sortItems(&tmp, Qt::AscendingOrder, d->sortCacheEnabled);
return tmp;
}
@@ -2777,6 +1764,13 @@ QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos) const
return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
}
+QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos, const QTransform &deviceTransform) const
+{
+ QList<QGraphicsItem *> itemsAtPoint = items(pos, Qt::IntersectsItemShape,
+ Qt::AscendingOrder, deviceTransform);
+ return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
+}
+
/*!
\fn QGraphicsScene::itemAt(qreal x, qreal y) const
\overload
@@ -2852,6 +1846,21 @@ void QGraphicsScene::setSelectionArea(const QPainterPath &path)
*/
void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode)
{
+ setSelectionArea(path, mode, QTransform());
+}
+
+/*!
+ \overload
+ \since 4.3
+
+ Sets the selection area to \a path using \a mode to determine if items are
+ included in the selection area.
+
+ \sa clearSelection(), selectionArea()
+*/
+void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode,
+ const QTransform &deviceTransform)
+{
Q_D(QGraphicsScene);
// Note: with boolean path operations, we can improve performance here
@@ -2867,7 +1876,7 @@ void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectio
bool changed = false;
// Set all items in path to selected.
- foreach (QGraphicsItem *item, items(path, mode)) {
+ foreach (QGraphicsItem *item, items(path, mode, Qt::AscendingOrder, deviceTransform)) {
if (item->flags() & QGraphicsItem::ItemIsSelectable) {
if (!item->isSelected())
changed = true;
@@ -2924,26 +1933,13 @@ void QGraphicsScene::clearSelection()
void QGraphicsScene::clear()
{
Q_D(QGraphicsScene);
- // Recursive descent delete
- for (int i = 0; i < d->indexedItems.size(); ++i) {
- if (QGraphicsItem *item = d->indexedItems.at(i)) {
- if (!item->parentItem())
- delete item;
- }
- }
- QList<QGraphicsItem *> unindexedParents;
- for (int i = 0; i < d->unindexedItems.size(); ++i) {
- QGraphicsItem *item = d->unindexedItems.at(i);
- if (!item->parentItem())
- unindexedParents << item;
- }
- d->unindexedItems.clear();
- qDeleteAll(unindexedParents);
- d->indexedItems.clear();
- d->freeItemIndexes.clear();
+ // NB! We have to clear the index before deleting items; otherwise the
+ // index might try to access dangling item pointers.
+ d->index->clear();
+ const QList<QGraphicsItem *> items = d->topLevelItems;
+ qDeleteAll(items);
+ Q_ASSERT(d->topLevelItems.isEmpty());
d->lastItemCount = 0;
- d->bspTree.clear();
- d->largestUntransformableItem = QRectF();
d->allItemsIgnoreHoverEvents = true;
d->allItemsUseDefaultCursor = true;
d->allItemsIgnoreTouchEvents = true;
@@ -3065,14 +2061,6 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
return;
}
- // Prevent reusing a recently deleted pointer: purge all removed items
- // from our lists.
- d->purgeRemovedItems();
-
- // Invalidate any sort caching; arrival of a new item means we need to
- // resort.
- d->invalidateSortCache();
-
// Detach this item from its parent if the parent's scene is different
// from this scene.
if (QGraphicsItem *itemParent = item->parentItem()) {
@@ -3083,29 +2071,18 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
// Add the item to this scene
item->d_func()->scene = targetScene;
- // Indexing requires sceneBoundingRect(), but because \a item might
- // not be completely constructed at this point, we need to store it in
- // a temporary list and schedule an indexing for later.
- d->unindexedItems << item;
- item->d_func()->index = -1;
- d->startIndexTimer(0);
+ // Add the item in the index
+ d->index->addItem(item);
// Add to list of toplevels if this item is a toplevel.
if (!item->d_ptr->parent)
d->registerTopLevelItem(item);
- // Update the scene's sort cache settings.
- item->d_ptr->globalStackingOrder = -1;
- d->invalidateSortCache();
-
// Add to list of items that require an update. We cannot assume that the
// item is fully constructed, so calling item->update() can lead to a pure
// virtual function call to boundingRect().
- if (!d->updateAll) {
- if (d->pendingUpdateItems.isEmpty())
- QMetaObject::invokeMethod(this, "_q_updateLater", Qt::QueuedConnection);
- d->pendingUpdateItems << item;
- }
+ d->markDirty(item);
+ d->dirtyGrowingItemsBoundingRect = true;
// Disable selectionChanged() for individual items
++d->selectionChanging;
@@ -4039,16 +3016,6 @@ bool QGraphicsScene::event(QEvent *event)
case QEvent::TouchEnd:
d->touchEventHandler(static_cast<QTouchEvent *>(event));
break;
- case QEvent::Timer:
- if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
- if (d->restartIndexTimer) {
- d->restartIndexTimer = false;
- } else {
- // this call will kill the timer
- d->_q_updateIndex();
- }
- }
- // Fallthrough intended - support timers in subclasses.
default:
return QObject::event(event);
}
@@ -5137,6 +4104,20 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
}
}
+void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform,
+ QRegion *exposedRegion, QWidget *widget)
+{
+ QRectF exposedSceneRect;
+ if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
+ exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
+ if (viewTransform)
+ exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
+ }
+ const QList<QGraphicsItem *> tli = index->estimateTopLevelItems(exposedSceneRect, Qt::DescendingOrder);
+ for (int i = 0; i < tli.size(); ++i)
+ drawSubtreeRecursive(tli.at(i), painter, viewTransform, exposedRegion, widget);
+}
+
void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
const QTransform *const viewTransform,
QRegion *exposedRegion, QWidget *widget,
@@ -5159,6 +4140,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
QTransform transform(Qt::Uninitialized);
QTransform *transformPtr = 0;
+ bool translateOnlyTransform = false;
#define ENSURE_TRANSFORM_PTR \
if (!transformPtr) { \
Q_ASSERT(!itemIsUntransformable); \
@@ -5168,6 +4150,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
transformPtr = &transform; \
} else { \
transformPtr = &item->d_ptr->sceneTransform; \
+ translateOnlyTransform = item->d_ptr->sceneTransformTranslateOnly; \
} \
}
@@ -5179,10 +4162,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
transform = item->deviceTransform(viewTransform ? *viewTransform : QTransform());
transformPtr = &transform;
} else if (item->d_ptr->dirtySceneTransform) {
- item->d_ptr->sceneTransform = item->d_ptr->parent ? item->d_ptr->parent->d_ptr->sceneTransform
- : QTransform();
- item->d_ptr->combineTransformFromParent(&item->d_ptr->sceneTransform);
- item->d_ptr->dirtySceneTransform = 0;
+ item->d_ptr->updateSceneTransformFromParent();
+ Q_ASSERT(!item->d_ptr->dirtySceneTransform);
wasDirtyParentSceneTransform = true;
}
@@ -5191,7 +4172,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
if (drawItem) {
const QRectF brect = adjustedItemBoundingRect(item);
ENSURE_TRANSFORM_PTR
- QRect viewBoundingRect = transformPtr->mapRect(brect).toRect();
+ QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect()
+ : transformPtr->mapRect(brect).toRect();
item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
viewBoundingRect.adjust(-1, -1, 1, 1);
drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty();
@@ -5208,10 +4190,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
int i = 0;
if (itemHasChildren) {
- if (item->d_ptr->needSortChildren) {
- item->d_ptr->needSortChildren = 0;
- qStableSort(item->d_ptr->children.begin(), item->d_ptr->children.end(), qt_notclosestLeaf);
- }
+ item->d_ptr->ensureSortedChildren();
if (itemClipsChildrenToShape) {
painter->save();
@@ -5237,7 +4216,8 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
if (drawItem) {
Q_ASSERT(!itemIsFullyTransparent);
Q_ASSERT(itemHasContents);
- item->d_ptr->initStyleOption(&styleOptionTmp, transform, exposedRegion
+ ENSURE_TRANSFORM_PTR
+ item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
? *exposedRegion : QRegion(), exposedRegion == 0);
const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
@@ -5245,10 +4225,9 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
if (savePainter)
painter->save();
- if (!itemHasChildren || !itemClipsChildrenToShape) {
- ENSURE_TRANSFORM_PTR
+ if (!itemHasChildren || !itemClipsChildrenToShape)
painter->setWorldTransform(*transformPtr);
- }
+
if (itemClipsToShape)
painter->setClipPath(item->shape(), Qt::IntersectClip);
painter->setOpacity(opacity);
@@ -5291,6 +4270,16 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b
/*ignoreVisibleBit=*/force,
/*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
/*ignoreOpacity=*/ignoreOpacity)) {
+ if (item->d_ptr->dirty) {
+ // The item is already marked as dirty and will be processed later. However,
+ // we have to make sure ignoreVisible and ignoreOpacity are set properly;
+ // otherwise things like: item->update(); item->hide() (force is now true)
+ // won't work as expected.
+ if (force)
+ item->d_ptr->ignoreVisible = 1;
+ if (ignoreOpacity)
+ item->d_ptr->ignoreOpacity = 1;
+ }
return;
}
@@ -5350,65 +4339,121 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b
}
static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item,
- const QRectF &rect, const QTransform &xform)
+ const QRectF &rect, bool itemIsUntransformable)
{
Q_ASSERT(view);
Q_ASSERT(item);
- if (item->hasBoundingRegionGranularity)
+
+ QGraphicsItem *itemq = static_cast<QGraphicsItem *>(item->q_ptr);
+ QGraphicsView *viewq = static_cast<QGraphicsView *>(view->q_ptr);
+
+ if (itemIsUntransformable) {
+ const QTransform xform = itemq->deviceTransform(viewq->viewportTransform());
+ if (!item->hasBoundingRegionGranularity)
+ return view->updateRect(xform.mapRect(rect).toRect());
return view->updateRegion(xform.map(QRegion(rect.toRect())));
- return view->updateRect(xform.mapRect(rect).toRect());
+ }
+
+ if (item->sceneTransformTranslateOnly && view->identityMatrix) {
+ const qreal dx = item->sceneTransform.dx();
+ const qreal dy = item->sceneTransform.dy();
+ if (!item->hasBoundingRegionGranularity) {
+ QRectF r(rect);
+ r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
+ return view->updateRect(r.toRect());
+ }
+ QRegion r(rect.toRect());
+ r.translate(qRound(dx) - view->horizontalScroll(), qRound(dy) - view->verticalScroll());
+ return view->updateRegion(r);
+ }
+
+ if (!viewq->isTransformed()) {
+ if (!item->hasBoundingRegionGranularity)
+ return view->updateRect(item->sceneTransform.mapRect(rect).toRect());
+ return view->updateRegion(item->sceneTransform.map(QRegion(rect.toRect())));
+ }
+
+ QTransform xform = item->sceneTransform;
+ xform *= viewq->viewportTransform();
+ if (!item->hasBoundingRegionGranularity)
+ return view->updateRect(xform.mapRect(rect).toRect());
+ return view->updateRegion(xform.map(QRegion(rect.toRect())));
}
void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren,
qreal parentOpacity)
{
Q_Q(QGraphicsScene);
+ Q_ASSERT(item);
+ Q_ASSERT(!updateAll);
- bool wasDirtyParentViewBoundingRects = false;
- bool wasDirtyParentSceneTransform = false;
- qreal opacity = parentOpacity;
+ if (!item->d_ptr->dirty && !item->d_ptr->dirtyChildren) {
+ resetDirtyItem(item);
+ return;
+ }
- if (item) {
- wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint;
- opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
- const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible;
- const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity && opacity == 0.0;
-
- if (item->d_ptr->dirtySceneTransform && !itemIsHidden && !item->d_ptr->itemIsUntransformable()
- && !(itemIsFullyTransparent && item->d_ptr->childrenCombineOpacity())) {
- // Calculate the full scene transform for this item.
- item->d_ptr->sceneTransform = item->d_ptr->parent ? item->d_ptr->parent->d_ptr->sceneTransform
- : QTransform();
- item->d_ptr->combineTransformFromParent(&item->d_ptr->sceneTransform);
- item->d_ptr->dirtySceneTransform = 0;
- wasDirtyParentSceneTransform = true;
- }
+ const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible;
+ if (itemIsHidden) {
+ resetDirtyItem(item, /*recursive=*/true);
+ return;
+ }
+
+ const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
+ const bool itemHasChildren = !item->d_ptr->children.isEmpty();
+ if (!itemHasContents && !itemHasChildren) {
+ resetDirtyItem(item);
+ return; // Item has neither contents nor children!(?)
+ }
+
+ const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
+ const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity && opacity < 0.0001;
+ if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
+ resetDirtyItem(item, /*recursive=*/itemHasChildren);
+ return;
+ }
- if (itemIsHidden || itemIsFullyTransparent || (item->d_ptr->flags & QGraphicsItem::ItemHasNoContents)) {
- // Make sure we don't process invisible items or items with no content.
- item->d_ptr->dirty = 0;
+ bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform;
+ const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
+ if (wasDirtyParentSceneTransform && !itemIsUntransformable) {
+ item->d_ptr->updateSceneTransformFromParent();
+ Q_ASSERT(!item->d_ptr->dirtySceneTransform);
+ }
+
+ const bool wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint;
+ if (itemIsFullyTransparent || !itemHasContents || dirtyAncestorContainsChildren) {
+ // Make sure we don't process invisible items or items with no content.
+ item->d_ptr->dirty = 0;
+ item->d_ptr->fullUpdatePending = 0;
+ // Might have a dirty view bounding rect otherwise.
+ if (itemIsFullyTransparent || !itemHasContents)
item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
+ }
+
+ if (!hasSceneRect && item->d_ptr->geometryChanged && item->d_ptr->visible) {
+ // Update growingItemsBoundingRect.
+ if (item->d_ptr->sceneTransformTranslateOnly) {
+ growingItemsBoundingRect |= item->boundingRect().translated(item->d_ptr->sceneTransform.dx(),
+ item->d_ptr->sceneTransform.dy());
+ } else {
+ growingItemsBoundingRect |= item->d_ptr->sceneTransform.mapRect(item->boundingRect());
}
}
// Process item.
- if (item && (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint)) {
+ if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask);
- const bool untransformableItem = item->d_ptr->itemIsUntransformable();
const QRectF itemBoundingRect = adjustedItemBoundingRect(item);
- if (item->d_ptr->geometryChanged) {
- // Update growingItemsBoundingRect.
- if (!hasSceneRect)
- growingItemsBoundingRect |= item->d_ptr->sceneTransform.mapRect(itemBoundingRect);
- item->d_ptr->geometryChanged = 0;
- }
-
- if (useCompatUpdate && !untransformableItem && qFuzzyIsNull(item->boundingRegionGranularity())) {
+ if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
// This block of code is kept for compatibility. Since 4.5, by default
// QGraphicsView does not connect the signal and we use the below
// method of delivering updates.
- q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect));
+ if (item->d_ptr->sceneTransformTranslateOnly) {
+ q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(),
+ item->d_ptr->sceneTransform.dy()));
+ } else {
+ q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect));
+ }
} else {
QRectF dirtyRect;
bool uninitializedDirtyRect = true;
@@ -5416,30 +4461,31 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
for (int j = 0; j < views.size(); ++j) {
QGraphicsView *view = views.at(j);
QGraphicsViewPrivate *viewPrivate = view->d_func();
- if (viewPrivate->fullUpdatePending)
- continue;
- switch (viewPrivate->viewportUpdateMode) {
- case QGraphicsView::NoViewportUpdate:
- continue;
- case QGraphicsView::FullViewportUpdate:
- view->viewport()->update();
- viewPrivate->fullUpdatePending = 1;
+ QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport];
+ if (viewPrivate->fullUpdatePending
+ || viewPrivate->viewportUpdateMode == QGraphicsView::NoViewportUpdate) {
+ // Okay, if we have a full update pending or no viewport update, this item's
+ // paintedViewBoundingRect will be updated correctly in the next paintEvent if
+ // it is inside the viewport, but for now we can pretend that it is outside.
+ paintedViewBoundingRect = QRect(-1, -1, -1, -1);
continue;
- default:
- break;
}
- QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport];
- if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
- wasDirtyParentViewBoundingRects = true;
+ if (item->d_ptr->paintedViewBoundingRectsNeedRepaint && !paintedViewBoundingRect.isEmpty()) {
paintedViewBoundingRect.translate(viewPrivate->dirtyScrollOffset);
if (!viewPrivate->updateRect(paintedViewBoundingRect))
- paintedViewBoundingRect = QRect();
+ paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
}
if (!item->d_ptr->dirty)
continue;
+ if (!item->d_ptr->paintedViewBoundingRectsNeedRepaint
+ && paintedViewBoundingRect.x() == -1 && paintedViewBoundingRect.y() == -1
+ && paintedViewBoundingRect.width() == -1 && paintedViewBoundingRect.height() == -1) {
+ continue; // Outside viewport.
+ }
+
if (uninitializedDirtyRect) {
dirtyRect = itemBoundingRect;
if (!item->d_ptr->fullUpdatePending) {
@@ -5452,35 +4498,25 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
if (dirtyRect.isEmpty())
continue; // Discard updates outside the bounding rect.
- bool valid = false;
- if (untransformableItem) {
- valid = updateHelper(viewPrivate, item->d_ptr, dirtyRect,
- item->deviceTransform(view->viewportTransform()));
- } else if (!view->isTransformed()) {
- valid = updateHelper(viewPrivate, item->d_ptr, dirtyRect, item->d_ptr->sceneTransform);
- } else {
- QTransform deviceTransform = item->d_ptr->sceneTransform;
- deviceTransform *= view->viewportTransform();
- valid = updateHelper(viewPrivate, item->d_ptr, dirtyRect, deviceTransform);
+ if (!updateHelper(viewPrivate, item->d_ptr, dirtyRect, itemIsUntransformable)
+ && item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
+ paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
}
- if (!valid)
- paintedViewBoundingRect = QRect();
}
}
}
- // Process root items / children.
- if (!item || item->d_ptr->dirtyChildren) {
- QList<QGraphicsItem *> *children = item ? &item->d_ptr->children : &topLevelItems;
- const bool allChildrenDirty = item && item->d_ptr->allChildrenDirty;
+ // Process children.
+ if (itemHasChildren && item->d_ptr->dirtyChildren) {
if (!dirtyAncestorContainsChildren) {
- dirtyAncestorContainsChildren = item && item->d_ptr->fullUpdatePending
+ dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
&& (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
}
- const bool parentIgnoresVisible = item && item->d_ptr->ignoreVisible;
- const bool parentIgnoresOpacity = item && item->d_ptr->ignoreOpacity;
- for (int i = 0; i < children->size(); ++i) {
- QGraphicsItem *child = children->at(i);
+ const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
+ const bool parentIgnoresVisible = item->d_ptr->ignoreVisible;
+ const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity;
+ for (int i = 0; i < item->d_ptr->children.size(); ++i) {
+ QGraphicsItem *child = item->d_ptr->children.at(i);
if (wasDirtyParentSceneTransform)
child->d_ptr->dirtySceneTransform = 1;
if (wasDirtyParentViewBoundingRects)
@@ -5489,36 +4525,19 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
child->d_ptr->ignoreVisible = 1;
if (parentIgnoresOpacity)
child->d_ptr->ignoreOpacity = 1;
-
if (allChildrenDirty) {
child->d_ptr->dirty = 1;
child->d_ptr->fullUpdatePending = 1;
child->d_ptr->dirtyChildren = 1;
child->d_ptr->allChildrenDirty = 1;
- } else if (!child->d_ptr->dirty && !child->d_ptr->dirtyChildren) {
- resetDirtyItem(child);
- continue;
- }
-
- if (dirtyAncestorContainsChildren || updateAll) {
- // No need to process this child's dirty rect, hence reset the dirty state.
- // However, we have to continue the recursion because it might have a dirty
- // view bounding rect that needs repaint. We also have to reset the dirty
- // state of its descendants.
- child->d_ptr->dirty = 0;
- child->d_ptr->fullUpdatePending = 0;
- if (updateAll)
- child->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
}
-
processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
}
} else if (wasDirtyParentSceneTransform) {
item->d_ptr->invalidateChildrenSceneTransform();
}
- if (item)
- resetDirtyItem(item);
+ resetDirtyItem(item);
}
/*!
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index 6aaeb91..d790f90 100644
--- a/src/gui/graphicsview/qgraphicsscene.h
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -83,6 +83,7 @@ class QGraphicsSimpleTextItem;
class QGraphicsTextItem;
class QGraphicsView;
class QGraphicsWidget;
+class QGraphicsSceneIndex;
class QHelpEvent;
class QInputMethodEvent;
class QKeyEvent;
@@ -152,22 +153,38 @@ public:
QRectF itemsBoundingRect() const;
QList<QGraphicsItem *> items() const;
- QList<QGraphicsItem *> items(const QPointF &pos) const;
- QList<QGraphicsItem *> items(const QRectF &rect, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
- QList<QGraphicsItem *> items(const QPolygonF &polygon, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
- QList<QGraphicsItem *> items(const QPainterPath &path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
+ QList<QGraphicsItem *> items(Qt::SortOrder order) const; // ### Qt 5: unify
+
+ QList<QGraphicsItem *> items(const QPointF &pos, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform = QTransform()) const;
+ QList<QGraphicsItem *> items(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform = QTransform()) const;
+ QList<QGraphicsItem *> items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform = QTransform()) const;
+ QList<QGraphicsItem *> items(const QPainterPath &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform = QTransform()) const;
+
+ QList<QGraphicsItem *> items(const QPointF &pos) const; // ### obsolete
+ QList<QGraphicsItem *> items(const QRectF &rect, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const; // ### obsolete
+ QList<QGraphicsItem *> items(const QPolygonF &polygon, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const; // ### obsolete
+ QList<QGraphicsItem *> items(const QPainterPath &path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const; // ### obsolete
+
QList<QGraphicsItem *> collidingItems(const QGraphicsItem *item, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const;
- QGraphicsItem *itemAt(const QPointF &pos) const;
+
+ QGraphicsItem *itemAt(const QPointF &pos) const; // ### obsolete
+ QGraphicsItem *itemAt(const QPointF &pos, const QTransform &deviceTransform) const;
inline QList<QGraphicsItem *> items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const
- { return items(QRectF(x, y, w, h), mode); }
- inline QGraphicsItem *itemAt(qreal x, qreal y) const
+ { return items(QRectF(x, y, w, h), mode); } // ### obsolete
+ inline QList<QGraphicsItem *> items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode, Qt::SortOrder order,
+ const QTransform &deviceTransform = QTransform()) const
+ { return items(QRectF(x, y, w, h), mode, order, deviceTransform); }
+ inline QGraphicsItem *itemAt(qreal x, qreal y) const // ### obsolete
{ return itemAt(QPointF(x, y)); }
+ inline QGraphicsItem *itemAt(qreal x, qreal y, const QTransform &deviceTransform) const
+ { return itemAt(QPointF(x, y), deviceTransform); }
QList<QGraphicsItem *> selectedItems() const;
QPainterPath selectionArea() const;
void setSelectionArea(const QPainterPath &path);
- void setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode);
+ void setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode);
+ void setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode, const QTransform &deviceTransform);
QGraphicsItemGroup *createItemGroup(const QList<QGraphicsItem *> &items);
void destroyItemGroup(QGraphicsItemGroup *group);
@@ -275,11 +292,8 @@ Q_SIGNALS:
private:
Q_DECLARE_PRIVATE(QGraphicsScene)
Q_DISABLE_COPY(QGraphicsScene)
- Q_PRIVATE_SLOT(d_func(), void _q_updateIndex())
Q_PRIVATE_SLOT(d_func(), void _q_emitUpdated())
- Q_PRIVATE_SLOT(d_func(), void _q_updateLater())
Q_PRIVATE_SLOT(d_func(), void _q_polishItems())
- Q_PRIVATE_SLOT(d_func(), void _q_updateSortCache())
Q_PRIVATE_SLOT(d_func(), void _q_processDirtyItems())
friend class QGraphicsItem;
friend class QGraphicsItemPrivate;
@@ -287,6 +301,10 @@ private:
friend class QGraphicsViewPrivate;
friend class QGraphicsWidget;
friend class QGraphicsWidgetPrivate;
+ friend class QGraphicsSceneIndex;
+ friend class QGraphicsSceneIndexPrivate;
+ friend class QGraphicsSceneBspTreeIndex;
+ friend class QGraphicsSceneBspTreeIndexPrivate;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsScene::SceneLayers)
diff --git a/src/gui/graphicsview/qgraphicsscene_bsp.cpp b/src/gui/graphicsview/qgraphicsscene_bsp.cpp
index 3f3e58b..fb4b9a4 100644
--- a/src/gui/graphicsview/qgraphicsscene_bsp.cpp
+++ b/src/gui/graphicsview/qgraphicsscene_bsp.cpp
@@ -70,12 +70,15 @@ class QGraphicsSceneFindItemBspTreeVisitor : public QGraphicsSceneBspTreeVisitor
{
public:
QList<QGraphicsItem *> *foundItems;
+ bool onlyTopLevelItems;
void visit(QList<QGraphicsItem *> *items)
{
for (int i = 0; i < items->size(); ++i) {
QGraphicsItem *item = items->at(i);
- if (!item->d_func()->itemDiscovered && item->isVisible()) {
+ if (onlyTopLevelItems && item->d_ptr->parent)
+ item = item->topLevelItem();
+ if (!item->d_func()->itemDiscovered && item->d_ptr->visible) {
item->d_func()->itemDiscovered = 1;
foundItems->prepend(item);
}
@@ -143,19 +146,15 @@ void QGraphicsSceneBspTree::removeItems(const QSet<QGraphicsItem *> &items)
}
}
-QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QRectF &rect)
+QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QRectF &rect, bool onlyTopLevelItems) const
{
QList<QGraphicsItem *> tmp;
findVisitor->foundItems = &tmp;
+ findVisitor->onlyTopLevelItems = onlyTopLevelItems;
climbTree(findVisitor, rect);
- return tmp;
-}
-
-QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QPointF &pos)
-{
- QList<QGraphicsItem *> tmp;
- findVisitor->foundItems = &tmp;
- climbTree(findVisitor, pos);
+ // Reset discovery bits.
+ for (int i = 0; i < tmp.size(); ++i)
+ tmp.at(i)->d_ptr->itemDiscovered = 0;
return tmp;
}
@@ -235,47 +234,17 @@ void QGraphicsSceneBspTree::initialize(const QRectF &rect, int depth, int index)
}
}
-void QGraphicsSceneBspTree::climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QPointF &pos, int index)
-{
- if (nodes.isEmpty())
- return;
-
- const Node &node = nodes.at(index);
- int childIndex = firstChildIndex(index);
-
- switch (node.type) {
- case Node::Leaf: {
- visitor->visit(&leaves[node.leafIndex]);
- break;
- }
- case Node::Vertical:
- if (pos.x() < node.offset) {
- climbTree(visitor, pos, childIndex);
- } else {
- climbTree(visitor, pos, childIndex + 1);
- }
- break;
- case Node::Horizontal:
- if (pos.y() < node.offset) {
- climbTree(visitor, pos, childIndex);
- } else {
- climbTree(visitor, pos, childIndex + 1);
- }
- break;
- }
-}
-
-void QGraphicsSceneBspTree::climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QRectF &rect, int index)
+void QGraphicsSceneBspTree::climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QRectF &rect, int index) const
{
if (nodes.isEmpty())
return;
const Node &node = nodes.at(index);
- int childIndex = firstChildIndex(index);
+ const int childIndex = firstChildIndex(index);
switch (node.type) {
case Node::Leaf: {
- visitor->visit(&leaves[node.leafIndex]);
+ visitor->visit(const_cast<QList<QGraphicsItem*>*>(&leaves[node.leafIndex]));
break;
}
case Node::Vertical:
@@ -288,7 +257,6 @@ void QGraphicsSceneBspTree::climbTree(QGraphicsSceneBspTreeVisitor *visitor, con
}
break;
case Node::Horizontal:
- int childIndex = firstChildIndex(index);
if (rect.top() < node.offset) {
climbTree(visitor, rect, childIndex);
if (rect.bottom() >= node.offset)
diff --git a/src/gui/graphicsview/qgraphicsscene_bsp_p.h b/src/gui/graphicsview/qgraphicsscene_bsp_p.h
index 73a937f..4cac64a 100644
--- a/src/gui/graphicsview/qgraphicsscene_bsp_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_bsp_p.h
@@ -92,8 +92,7 @@ public:
void removeItem(QGraphicsItem *item, const QRectF &rect);
void removeItems(const QSet<QGraphicsItem *> &items);
- QList<QGraphicsItem *> items(const QRectF &rect);
- QList<QGraphicsItem *> items(const QPointF &pos);
+ QList<QGraphicsItem *> items(const QRectF &rect, bool onlyTopLevelItems = false) const;
int leafCount() const;
inline int firstChildIndex(int index) const
@@ -106,11 +105,7 @@ public:
private:
void initialize(const QRectF &rect, int depth, int index);
- void climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QPointF &pos, int index = 0);
- void climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QRectF &rect, int index = 0);
-
- void findItems(QList<QGraphicsItem *> *foundItems, const QRectF &rect, int index);
- void findItems(QList<QGraphicsItem *> *foundItems, const QPointF &pos, int index);
+ void climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QRectF &rect, int index = 0) const;
QRectF rectForIndex(int index) const;
QVector<Node> nodes;
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index dc720a7..ffd62d5 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -59,7 +59,6 @@
#include "qgraphicssceneevent.h"
#include "qgraphicsview.h"
-#include "qgraphicsscene_bsp_p.h"
#include "qgraphicsitem_p.h"
#include <private/qobject_p.h>
@@ -72,10 +71,9 @@
#include <QtGui/qstyle.h>
#include <QtGui/qstyleoption.h>
-static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
-
QT_BEGIN_NAMESPACE
+class QGraphicsSceneIndex;
class QGraphicsView;
class QGraphicsWidget;
@@ -86,24 +84,19 @@ public:
QGraphicsScenePrivate();
void init();
+ static QGraphicsScenePrivate *get(QGraphicsScene *q);
+
quint32 changedSignalMask;
QGraphicsScene::ItemIndexMethod indexMethod;
- int bspTreeDepth;
-
- QList<QGraphicsItem *> estimateItemsInRect(const QRectF &rect) const;
- void addToIndex(QGraphicsItem *item);
- void removeFromIndex(QGraphicsItem *item);
- void resetIndex();
+ QGraphicsSceneIndex *index;
- QGraphicsSceneBspTree bspTree;
- void _q_updateIndex();
int lastItemCount;
QRectF sceneRect;
bool hasSceneRect;
+ bool dirtyGrowingItemsBoundingRect;
QRectF growingItemsBoundingRect;
- QRectF largestUntransformableItem;
void _q_emitUpdated();
QList<QRectF> updatedRects;
@@ -114,9 +107,6 @@ public:
QPainterPath selectionArea;
int selectionChanging;
QSet<QGraphicsItem *> selectedItems;
- QList<QGraphicsItem *> unindexedItems;
- QList<QGraphicsItem *> indexedItems;
- QList<QGraphicsItem *> pendingUpdateItems;
QList<QGraphicsItem *> unpolishedItems;
QList<QGraphicsItem *> topLevelItems;
bool needSortTopLevelItems;
@@ -128,21 +118,11 @@ public:
void _q_processDirtyItems();
- QList<int> freeItemIndexes;
- bool regenerateIndex;
-
- bool purgePending;
void removeItemHelper(QGraphicsItem *item);
- QSet<QGraphicsItem *> removedItems;
- void purgeRemovedItems();
QBrush backgroundBrush;
QBrush foregroundBrush;
- int indexTimerId;
- bool restartIndexTimer;
- void startIndexTimer(int interval = QGRAPHICSSCENE_INDEXTIMER_TIMEOUT);
-
bool stickyFocus;
bool hasFocus;
QGraphicsItem *focusItem;
@@ -181,7 +161,6 @@ public:
QList<QGraphicsItem *> itemsAtPosition(const QPoint &screenPos,
const QPointF &scenePos,
QWidget *widget) const;
- static bool itemCollidesWithPath(QGraphicsItem *item, const QPainterPath &path, Qt::ItemSelectionMode mode);
void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event);
QList<QGraphicsView *> views;
@@ -210,69 +189,14 @@ public:
void mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent);
QGraphicsWidget *windowForItem(const QGraphicsItem *item) const;
- QList<QGraphicsItem *> topLevelItemsInStackingOrder(const QTransform *const, QRegion *);
- void recursive_items_helper(QGraphicsItem *item, QRectF rect, QList<QGraphicsItem *> *items,
- const QTransform &parentTransform, const QTransform &viewTransform,
- Qt::ItemSelectionMode mode, Qt::SortOrder order, qreal parentOpacity = 1.0) const;
-
- QList<QGraphicsItem *> items_helper(const QPointF &pos) const;
- QList<QGraphicsItem *> items_helper(const QRectF &rect,
- Qt::ItemSelectionMode mode,
- Qt::SortOrder order) const;
- QList<QGraphicsItem *> items_helper(const QPolygonF &rect,
- Qt::ItemSelectionMode mode,
- Qt::SortOrder order) const;
- QList<QGraphicsItem *> items_helper(const QPainterPath &rect,
- Qt::ItemSelectionMode mode,
- Qt::SortOrder order) const;
- void childItems_helper(QList<QGraphicsItem *> *items,
- const QGraphicsItem *parent,
- const QPointF &pos) const;
- void childItems_helper(QList<QGraphicsItem *> *items,
- const QGraphicsItem *parent,
- const QRectF &rect,
- Qt::ItemSelectionMode mode) const;
- void childItems_helper(QList<QGraphicsItem *> *items,
- const QGraphicsItem *parent,
- const QPolygonF &polygon,
- Qt::ItemSelectionMode mode) const;
- void childItems_helper(QList<QGraphicsItem *> *items,
- const QGraphicsItem *parent,
- const QPainterPath &path,
- Qt::ItemSelectionMode mode) const;
-
- bool sortCacheEnabled;
- bool updatingSortCache;
- void invalidateSortCache();
- static void climbTree(QGraphicsItem *item, int *stackingOrder);
- void _q_updateSortCache();
-
- static bool closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2);
- static bool closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2);
-
- static inline bool closestItemFirst_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
- {
- return item1->d_ptr->globalStackingOrder < item2->d_ptr->globalStackingOrder;
- }
- static inline bool closestItemLast_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
- {
- return item1->d_ptr->globalStackingOrder >= item2->d_ptr->globalStackingOrder;
- }
-
- static void sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order, bool cached);
+ bool sortCacheEnabled; // for compatibility
void drawItemHelper(QGraphicsItem *item, QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget,
bool painterStateProtection);
- inline void drawItems(QPainter *painter, const QTransform *const viewTransform,
- QRegion *exposedRegion, QWidget *widget)
- {
- const QList<QGraphicsItem *> tli = topLevelItemsInStackingOrder(viewTransform, exposedRegion);
- for (int i = 0; i < tli.size(); ++i)
- drawSubtreeRecursive(tli.at(i), painter, viewTransform, exposedRegion, widget);
- return;
- }
+ void drawItems(QPainter *painter, const QTransform *const viewTransform,
+ QRegion *exposedRegion, QWidget *widget);
void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform *const,
QRegion *exposedRegion, QWidget *widget, qreal parentOpacity = qreal(1.0));
@@ -282,18 +206,32 @@ public:
void processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren = false,
qreal parentOpacity = qreal(1.0));
- inline void resetDirtyItem(QGraphicsItem *item)
+ inline void resetDirtyItem(QGraphicsItem *item, bool recursive = false)
{
Q_ASSERT(item);
item->d_ptr->dirty = 0;
item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
item->d_ptr->geometryChanged = 0;
+ if (!item->d_ptr->dirtyChildren)
+ recursive = false;
item->d_ptr->dirtyChildren = 0;
item->d_ptr->needsRepaint = QRectF();
item->d_ptr->allChildrenDirty = 0;
item->d_ptr->fullUpdatePending = 0;
item->d_ptr->ignoreVisible = 0;
item->d_ptr->ignoreOpacity = 0;
+ if (recursive) {
+ for (int i = 0; i < item->d_ptr->children.size(); ++i)
+ resetDirtyItem(item->d_ptr->children.at(i), recursive);
+ }
+ }
+
+ inline void ensureSortedTopLevelItems()
+ {
+ if (needSortTopLevelItems) {
+ qSort(topLevelItems.begin(), topLevelItems.end(), qt_notclosestLeaf);
+ needSortTopLevelItems = false;
+ }
}
QStyle *style;
@@ -320,6 +258,25 @@ public:
void updateInputMethodSensitivityInViews();
};
+// QRectF::intersects() returns false always if either the source or target
+// rectangle's width or height are 0. This works around that problem.
+static inline void _q_adjustRect(QRectF *rect)
+{
+ Q_ASSERT(rect);
+ if (!rect->width())
+ rect->adjust(-0.00001, 0, 0.00001, 0);
+ if (!rect->height())
+ rect->adjust(0, -0.00001, 0, 0.00001);
+}
+
+static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
+{
+ Q_ASSERT(item);
+ QRectF boundingRect(item->boundingRect());
+ _q_adjustRect(&boundingRect);
+ return boundingRect;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp
new file mode 100644
index 0000000..a54ade9
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp
@@ -0,0 +1,782 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGraphicsSceneBspTreeIndex
+ \brief The QGraphicsSceneBspTreeIndex class provides an implementation of
+ a BSP indexing algorithm for discovering items in QGraphicsScene.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+ \mainclass
+ \internal
+
+ QGraphicsSceneBspTreeIndex index use a BSP(Binary Space Partitioning)
+ implementation to discover items quickly. This implementation is
+ very efficient for static scene. It has a depth that you can set.
+ The depth directly affects performance and memory usage; the latter
+ growing exponentially with the depth of the tree. With an optimal tree
+ depth, the index can instantly determine the locality of items, even
+ for scenes with thousands or millions of items. This also greatly improves
+ rendering performance.
+
+ By default, the value is 0, in which case Qt will guess a reasonable
+ default depth based on the size, location and number of items in the
+ scene. If these parameters change frequently, however, you may experience
+ slowdowns as the index retunes the depth internally. You can avoid
+ potential slowdowns by fixating the tree depth through setting this
+ property.
+
+ The depth of the tree and the size of the scene rectangle decide the
+ granularity of the scene's partitioning. The size of each scene segment is
+ determined by the following algorithm:
+
+ The BSP tree has an optimal size when each segment contains between 0 and
+ 10 items.
+
+ \sa QGraphicsScene, QGraphicsView, QGraphicsSceneIndex
+*/
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+#include <private/qgraphicsscene_p.h>
+#include <private/qgraphicsscenebsptreeindex_p.h>
+#include <private/qgraphicssceneindex_p.h>
+
+#include <QtCore/qmath.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+static inline int intmaxlog(int n)
+{
+ return (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0);
+}
+
+/*!
+ Constructs a private scene bsp index.
+*/
+QGraphicsSceneBspTreeIndexPrivate::QGraphicsSceneBspTreeIndexPrivate(QGraphicsScene *scene)
+ : QGraphicsSceneIndexPrivate(scene),
+ bspTreeDepth(0),
+ indexTimerId(0),
+ restartIndexTimer(false),
+ regenerateIndex(true),
+ lastItemCount(0),
+ purgePending(false),
+ sortCacheEnabled(false),
+ updatingSortCache(false)
+{
+}
+
+
+/*!
+ This method will update the BSP index by removing the items from the temporary
+ unindexed list and add them in the indexedItems list. This will also
+ update the growingItemsBoundingRect if needed. This will update the BSP
+ implementation as well.
+
+ \internal
+*/
+void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex()
+{
+ Q_Q(QGraphicsSceneBspTreeIndex);
+ if (!indexTimerId)
+ return;
+
+ q->killTimer(indexTimerId);
+ indexTimerId = 0;
+
+ purgeRemovedItems();
+
+ // Add unindexedItems to indexedItems
+ for (int i = 0; i < unindexedItems.size(); ++i) {
+ if (QGraphicsItem *item = unindexedItems.at(i)) {
+ Q_ASSERT(!item->d_ptr->itemDiscovered);
+ if (!freeItemIndexes.isEmpty()) {
+ int freeIndex = freeItemIndexes.takeFirst();
+ item->d_func()->index = freeIndex;
+ indexedItems[freeIndex] = item;
+ } else {
+ item->d_func()->index = indexedItems.size();
+ indexedItems << item;
+ }
+ }
+ }
+
+ // Determine whether we should regenerate the BSP tree.
+ if (bspTreeDepth == 0) {
+ int oldDepth = intmaxlog(lastItemCount);
+ bspTreeDepth = intmaxlog(indexedItems.size());
+ static const int slack = 100;
+ if (bsp.leafCount() == 0 || (oldDepth != bspTreeDepth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
+ // ### Crude algorithm.
+ regenerateIndex = true;
+ }
+ }
+
+ // Regenerate the tree.
+ if (regenerateIndex) {
+ regenerateIndex = false;
+ bsp.initialize(sceneRect, bspTreeDepth);
+ unindexedItems = indexedItems;
+ lastItemCount = indexedItems.size();
+ }
+
+ // Insert all unindexed items into the tree.
+ for (int i = 0; i < unindexedItems.size(); ++i) {
+ if (QGraphicsItem *item = unindexedItems.at(i)) {
+ if (item->d_ptr->itemIsUntransformable()) {
+ untransformableItems << item;
+ continue;
+ }
+ if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+ continue;
+
+ bsp.insertItem(item, item->sceneBoundingRect());
+ }
+ }
+ unindexedItems.clear();
+}
+
+
+/*!
+ \internal
+
+ Removes stale pointers from all data structures.
+*/
+void QGraphicsSceneBspTreeIndexPrivate::purgeRemovedItems()
+{
+ if (!purgePending && removedItems.isEmpty())
+ return;
+
+ // Remove stale items from the BSP tree.
+ bsp.removeItems(removedItems);
+ // Purge this list.
+ removedItems.clear();
+ freeItemIndexes.clear();
+ for (int i = 0; i < indexedItems.size(); ++i) {
+ if (!indexedItems.at(i))
+ freeItemIndexes << i;
+ }
+ purgePending = false;
+}
+
+/*!
+ \internal
+
+ Starts or restarts the timer used for reindexing unindexed items.
+*/
+void QGraphicsSceneBspTreeIndexPrivate::startIndexTimer(int interval)
+{
+ Q_Q(QGraphicsSceneBspTreeIndex);
+ if (indexTimerId) {
+ restartIndexTimer = true;
+ } else {
+ indexTimerId = q->startTimer(interval);
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneBspTreeIndexPrivate::resetIndex()
+{
+ purgeRemovedItems();
+ for (int i = 0; i < indexedItems.size(); ++i) {
+ if (QGraphicsItem *item = indexedItems.at(i)) {
+ item->d_ptr->index = -1;
+ Q_ASSERT(!item->d_ptr->itemDiscovered);
+ unindexedItems << item;
+ }
+ }
+ indexedItems.clear();
+ freeItemIndexes.clear();
+ untransformableItems.clear();
+ regenerateIndex = true;
+ startIndexTimer();
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneBspTreeIndexPrivate::climbTree(QGraphicsItem *item, int *stackingOrder)
+{
+ if (!item->d_ptr->children.isEmpty()) {
+ QList<QGraphicsItem *> childList = item->d_ptr->children;
+ qSort(childList.begin(), childList.end(), qt_closestLeaf);
+ for (int i = 0; i < childList.size(); ++i) {
+ QGraphicsItem *item = childList.at(i);
+ if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))
+ climbTree(childList.at(i), stackingOrder);
+ }
+ item->d_ptr->globalStackingOrder = (*stackingOrder)++;
+ for (int i = 0; i < childList.size(); ++i) {
+ QGraphicsItem *item = childList.at(i);
+ if (item->flags() & QGraphicsItem::ItemStacksBehindParent)
+ climbTree(childList.at(i), stackingOrder);
+ }
+ } else {
+ item->d_ptr->globalStackingOrder = (*stackingOrder)++;
+ }
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneBspTreeIndexPrivate::_q_updateSortCache()
+{
+ Q_Q(QGraphicsSceneBspTreeIndex);
+ _q_updateIndex();
+
+ if (!sortCacheEnabled || !updatingSortCache)
+ return;
+
+ updatingSortCache = false;
+ int stackingOrder = 0;
+
+ QList<QGraphicsItem *> topLevels;
+ const QList<QGraphicsItem *> items = q->items();
+ for (int i = 0; i < items.size(); ++i) {
+ QGraphicsItem *item = items.at(i);
+ if (item && !item->d_ptr->parent)
+ topLevels << item;
+ }
+
+ qSort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
+ for (int i = 0; i < topLevels.size(); ++i)
+ climbTree(topLevels.at(i), &stackingOrder);
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneBspTreeIndexPrivate::invalidateSortCache()
+{
+ Q_Q(QGraphicsSceneBspTreeIndex);
+ if (!sortCacheEnabled || updatingSortCache)
+ return;
+
+ updatingSortCache = true;
+ QMetaObject::invokeMethod(q, "_q_updateSortCache", Qt::QueuedConnection);
+}
+
+void QGraphicsSceneBspTreeIndexPrivate::addItem(QGraphicsItem *item, bool recursive)
+{
+ if (!item)
+ return;
+
+ // Prevent reusing a recently deleted pointer: purge all removed item from our lists.
+ purgeRemovedItems();
+
+ // Invalidate any sort caching; arrival of a new item means we need to resort.
+ // Update the scene's sort cache settings.
+ item->d_ptr->globalStackingOrder = -1;
+ invalidateSortCache();
+
+ // Indexing requires sceneBoundingRect(), but because \a item might
+ // not be completely constructed at this point, we need to store it in
+ // a temporary list and schedule an indexing for later.
+ if (item->d_ptr->index == -1) {
+ Q_ASSERT(!unindexedItems.contains(item));
+ unindexedItems << item;
+ startIndexTimer(0);
+ } else {
+ Q_ASSERT(indexedItems.contains(item));
+ qWarning("QGraphicsSceneBspTreeIndex::addItem: item has already been added to this BSP");
+ }
+
+ if (recursive) {
+ for (int i = 0; i < item->d_ptr->children.size(); ++i)
+ addItem(item->d_ptr->children.at(i), recursive);
+ }
+}
+
+void QGraphicsSceneBspTreeIndexPrivate::removeItem(QGraphicsItem *item, bool recursive,
+ bool moveToUnindexedItems)
+{
+ if (!item)
+ return;
+
+ if (item->d_ptr->index != -1) {
+ Q_ASSERT(item->d_ptr->index < indexedItems.size());
+ Q_ASSERT(indexedItems.at(item->d_ptr->index) == item);
+ Q_ASSERT(!item->d_ptr->itemDiscovered);
+ freeItemIndexes << item->d_ptr->index;
+ indexedItems[item->d_ptr->index] = 0;
+ item->d_ptr->index = -1;
+
+ if (item->d_ptr->itemIsUntransformable()) {
+ untransformableItems.removeOne(item);
+ } else if (item->d_ptr->inDestructor) {
+ // Avoid virtual function calls from the destructor.
+ purgePending = true;
+ removedItems << item;
+ } else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
+ bsp.removeItem(item, item->sceneBoundingRect());
+ }
+ } else {
+ unindexedItems.removeOne(item);
+ }
+ invalidateSortCache(); // ### Only do this when removing from BSP?
+
+ Q_ASSERT(item->d_ptr->index == -1);
+ Q_ASSERT(!indexedItems.contains(item));
+ Q_ASSERT(!unindexedItems.contains(item));
+ Q_ASSERT(!untransformableItems.contains(item));
+
+ if (moveToUnindexedItems)
+ addItem(item);
+
+ if (recursive) {
+ for (int i = 0; i < item->d_ptr->children.size(); ++i)
+ removeItem(item->d_ptr->children.at(i), recursive, moveToUnindexedItems);
+ }
+}
+
+QList<QGraphicsItem *> QGraphicsSceneBspTreeIndexPrivate::estimateItems(const QRectF &rect, Qt::SortOrder order,
+ bool onlyTopLevelItems)
+{
+ Q_Q(QGraphicsSceneBspTreeIndex);
+ if (onlyTopLevelItems && rect.isNull())
+ return q->QGraphicsSceneIndex::estimateTopLevelItems(rect, order);
+
+ purgeRemovedItems();
+ _q_updateSortCache();
+ Q_ASSERT(unindexedItems.isEmpty());
+
+ QList<QGraphicsItem *> rectItems = bsp.items(rect, onlyTopLevelItems);
+ if (onlyTopLevelItems) {
+ for (int i = 0; i < untransformableItems.size(); ++i) {
+ QGraphicsItem *item = untransformableItems.at(i);
+ if (!item->d_ptr->parent) {
+ rectItems << item;
+ } else {
+ item = item->topLevelItem();
+ if (!rectItems.contains(item))
+ rectItems << item;
+ }
+ }
+ } else {
+ rectItems += untransformableItems;
+ }
+
+ sortItems(&rectItems, order, sortCacheEnabled, onlyTopLevelItems);
+ return rectItems;
+}
+
+/*!
+ Returns true if \a item1 is on top of \a item2.
+
+ \internal
+*/
+bool QGraphicsSceneBspTreeIndexPrivate::closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{
+ // Siblings? Just check their z-values.
+ const QGraphicsItemPrivate *d1 = item1->d_ptr;
+ const QGraphicsItemPrivate *d2 = item2->d_ptr;
+ if (d1->parent == d2->parent)
+ return qt_closestLeaf(item1, item2);
+
+ // Find common ancestor, and each item's ancestor closest to the common
+ // ancestor.
+ int item1Depth = d1->depth;
+ int item2Depth = d2->depth;
+ const QGraphicsItem *p = item1;
+ const QGraphicsItem *t1 = item1;
+ while (item1Depth > item2Depth && (p = p->d_ptr->parent)) {
+ if (p == item2) {
+ // item2 is one of item1's ancestors; item1 is on top
+ return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
+ }
+ t1 = p;
+ --item1Depth;
+ }
+ p = item2;
+ const QGraphicsItem *t2 = item2;
+ while (item2Depth > item1Depth && (p = p->d_ptr->parent)) {
+ if (p == item1) {
+ // item1 is one of item2's ancestors; item1 is not on top
+ return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
+ }
+ t2 = p;
+ --item2Depth;
+ }
+
+ // item1Ancestor is now at the same level as item2Ancestor, but not the same.
+ const QGraphicsItem *a1 = t1;
+ const QGraphicsItem *a2 = t2;
+ while (a1) {
+ const QGraphicsItem *p1 = a1;
+ const QGraphicsItem *p2 = a2;
+ a1 = a1->parentItem();
+ a2 = a2->parentItem();
+ if (a1 && a1 == a2)
+ return qt_closestLeaf(p1, p2);
+ }
+
+ // No common ancestor? Then just compare the items' toplevels directly.
+ return qt_closestLeaf(t1->topLevelItem(), t2->topLevelItem());
+}
+
+/*!
+ Returns true if \a item2 is on top of \a item1.
+
+ \internal
+*/
+bool QGraphicsSceneBspTreeIndexPrivate::closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
+{
+ return closestItemFirst_withoutCache(item2, item1);
+}
+
+/*!
+ Sort a list of \a itemList in a specific \a order and use the cache if requested.
+
+ \internal
+*/
+void QGraphicsSceneBspTreeIndexPrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
+ bool sortCacheEnabled, bool onlyTopLevelItems)
+{
+ if (order == Qt::SortOrder(-1))
+ return;
+
+ if (onlyTopLevelItems) {
+ if (order == Qt::AscendingOrder)
+ qSort(itemList->begin(), itemList->end(), qt_closestLeaf);
+ else if (order == Qt::DescendingOrder)
+ qSort(itemList->begin(), itemList->end(), qt_notclosestLeaf);
+ return;
+ }
+
+ if (sortCacheEnabled) {
+ if (order == Qt::AscendingOrder) {
+ qSort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
+ } else if (order == Qt::DescendingOrder) {
+ qSort(itemList->begin(), itemList->end(), closestItemLast_withCache);
+ }
+ } else {
+ if (order == Qt::AscendingOrder) {
+ qSort(itemList->begin(), itemList->end(), closestItemFirst_withoutCache);
+ } else if (order == Qt::DescendingOrder) {
+ qSort(itemList->begin(), itemList->end(), closestItemLast_withoutCache);
+ }
+ }
+}
+
+/*!
+ Constructs a BSP scene index for the given \a scene.
+*/
+QGraphicsSceneBspTreeIndex::QGraphicsSceneBspTreeIndex(QGraphicsScene *scene)
+ : QGraphicsSceneIndex(*new QGraphicsSceneBspTreeIndexPrivate(scene), scene)
+{
+
+}
+
+QGraphicsSceneBspTreeIndex::~QGraphicsSceneBspTreeIndex()
+{
+ Q_D(QGraphicsSceneBspTreeIndex);
+ for (int i = 0; i < d->indexedItems.size(); ++i) {
+ // Ensure item bits are reset properly.
+ if (QGraphicsItem *item = d->indexedItems.at(i)) {
+ Q_ASSERT(!item->d_ptr->itemDiscovered);
+ item->d_ptr->index = -1;
+ }
+ }
+}
+
+/*!
+ \reimp
+ Clear the all the BSP index.
+*/
+void QGraphicsSceneBspTreeIndex::clear()
+{
+ Q_D(QGraphicsSceneBspTreeIndex);
+ d->bsp.clear();
+ d->lastItemCount = 0;
+ d->freeItemIndexes.clear();
+ for (int i = 0; i < d->indexedItems.size(); ++i) {
+ // Ensure item bits are reset properly.
+ if (QGraphicsItem *item = d->indexedItems.at(i)) {
+ Q_ASSERT(!item->d_ptr->itemDiscovered);
+ item->d_ptr->index = -1;
+ }
+ }
+ d->indexedItems.clear();
+ d->unindexedItems.clear();
+ d->untransformableItems.clear();
+}
+
+/*!
+ Add the \a item into the BSP index.
+*/
+void QGraphicsSceneBspTreeIndex::addItem(QGraphicsItem *item)
+{
+ Q_D(QGraphicsSceneBspTreeIndex);
+ d->addItem(item);
+}
+
+/*!
+ Remove the \a item from the BSP index.
+*/
+void QGraphicsSceneBspTreeIndex::removeItem(QGraphicsItem *item)
+{
+ Q_D(QGraphicsSceneBspTreeIndex);
+ d->removeItem(item);
+}
+
+/*!
+ \reimp
+ Update the BSP when the \a item 's bounding rect has changed.
+*/
+void QGraphicsSceneBspTreeIndex::prepareBoundingRectChange(const QGraphicsItem *item)
+{
+ if (!item)
+ return;
+
+ if (item->d_ptr->index == -1 || item->d_ptr->itemIsUntransformable()
+ || (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
+ return; // Item is not in BSP tree; nothing to do.
+ }
+
+ Q_D(QGraphicsSceneBspTreeIndex);
+ QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
+ d->removeItem(thatItem, /*recursive=*/false, /*moveToUnindexedItems=*/true);
+ for (int i = 0; i < item->d_ptr->children.size(); ++i) // ### Do we really need this?
+ prepareBoundingRectChange(item->d_ptr->children.at(i));
+}
+
+/*!
+ Returns an estimation visible items that are either inside or
+ intersect with the specified \a rect and return a list sorted using \a order.
+
+ \a deviceTransform is the transformation apply to the view.
+
+*/
+QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::estimateItems(const QRectF &rect, Qt::SortOrder order) const
+{
+ Q_D(const QGraphicsSceneBspTreeIndex);
+ return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order);
+}
+
+QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::estimateTopLevelItems(const QRectF &rect, Qt::SortOrder order) const
+{
+ Q_D(const QGraphicsSceneBspTreeIndex);
+ return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order, /*onlyTopLevels=*/true);
+}
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::items(Qt::SortOrder order = Qt::AscendingOrder) const;
+
+ Return all items in the BSP index and sort them using \a order.
+*/
+QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::items(Qt::SortOrder order) const
+{
+ Q_D(const QGraphicsSceneBspTreeIndex);
+ const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->purgeRemovedItems();
+ QList<QGraphicsItem *> itemList;
+
+ // If freeItemIndexes is empty, we know there are no holes in indexedItems and
+ // unindexedItems.
+ if (d->freeItemIndexes.isEmpty()) {
+ if (d->unindexedItems.isEmpty()) {
+ itemList = d->indexedItems;
+ } else {
+ itemList = d->indexedItems + d->unindexedItems;
+ }
+ } else {
+ // Rebuild the list of items to avoid holes. ### We could also just
+ // compress the item lists at this point.
+ foreach (QGraphicsItem *item, d->indexedItems + d->unindexedItems) {
+ if (item)
+ itemList << item;
+ }
+ }
+ if (order != -1) {
+ //We sort descending order
+ d->sortItems(&itemList, order, d->sortCacheEnabled);
+ }
+ return itemList;
+}
+
+/*!
+ \property QGraphicsSceneBspTreeIndex::bspTreeDepth
+ \brief the depth of the BSP index tree
+ \since 4.6
+
+ This value determines the depth of BSP tree. The depth
+ directly affects performance and memory usage; the latter
+ growing exponentially with the depth of the tree. With an optimal tree
+ depth, the index can instantly determine the locality of items, even
+ for scenes with thousands or millions of items. This also greatly improves
+ rendering performance.
+
+ By default, the value is 0, in which case Qt will guess a reasonable
+ default depth based on the size, location and number of items in the
+ scene. If these parameters change frequently, however, you may experience
+ slowdowns as the index retunes the depth internally. You can avoid
+ potential slowdowns by fixating the tree depth through setting this
+ property.
+
+ The depth of the tree and the size of the scene rectangle decide the
+ granularity of the scene's partitioning. The size of each scene segment is
+ determined by the following algorithm:
+
+ The BSP tree has an optimal size when each segment contains between 0 and
+ 10 items.
+
+*/
+int QGraphicsSceneBspTreeIndex::bspTreeDepth()
+{
+ Q_D(const QGraphicsSceneBspTreeIndex);
+ return d->bspTreeDepth;
+}
+
+void QGraphicsSceneBspTreeIndex::setBspTreeDepth(int depth)
+{
+ Q_D(QGraphicsSceneBspTreeIndex);
+ if (d->bspTreeDepth == depth)
+ return;
+ d->bspTreeDepth = depth;
+ d->resetIndex();
+}
+
+/*!
+ \reimp
+
+ This method react to the \a rect change of the scene and
+ reset the BSP tree index.
+*/
+void QGraphicsSceneBspTreeIndex::updateSceneRect(const QRectF &rect)
+{
+ Q_D(QGraphicsSceneBspTreeIndex);
+ d->sceneRect = rect;
+ d->resetIndex();
+}
+
+/*!
+ \reimp
+
+ This method react to the \a change of the \a item and use the \a value to
+ update the BSP tree if necessary.
+
+*/
+void QGraphicsSceneBspTreeIndex::itemChange(const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change, const QVariant &value)
+{
+ Q_D(QGraphicsSceneBspTreeIndex);
+ switch (change) {
+ case QGraphicsItem::ItemFlagsChange: {
+ // Handle ItemIgnoresTransformations
+ bool ignoredTransform = item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations;
+ bool willIgnoreTransform = value.toUInt() & QGraphicsItem::ItemIgnoresTransformations;
+ bool clipsChildren = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
+ bool willClipChildren = value.toUInt() & QGraphicsItem::ItemClipsChildrenToShape;
+ if ((ignoredTransform != willIgnoreTransform) || (clipsChildren != willClipChildren)) {
+ QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
+ // Remove item and its descendants from the index and append
+ // them to the list of unindexed items. Then, when the index
+ // is updated, they will be put into the bsp-tree or the list
+ // of untransformable items.
+ d->removeItem(thatItem, /*recursive=*/true, /*moveToUnidexedItems=*/true);
+ }
+ break;
+ }
+ case QGraphicsItem::ItemZValueChange:
+ d->invalidateSortCache();
+ break;
+ case QGraphicsItem::ItemParentChange: {
+ d->invalidateSortCache();
+ // Handle ItemIgnoresTransformations
+ QGraphicsItem *newParent = qVariantValue<QGraphicsItem *>(value);
+ bool ignoredTransform = item->d_ptr->itemIsUntransformable();
+ bool willIgnoreTransform = (item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations)
+ || (newParent && newParent->d_ptr->itemIsUntransformable());
+ bool ancestorClippedChildren = item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren;
+ bool ancestorWillClipChildren = newParent
+ && ((newParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)
+ || (newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren));
+ if ((ignoredTransform != willIgnoreTransform) || (ancestorClippedChildren != ancestorWillClipChildren)) {
+ QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
+ // Remove item and its descendants from the index and append
+ // them to the list of unindexed items. Then, when the index
+ // is updated, they will be put into the bsp-tree or the list
+ // of untransformable items.
+ d->removeItem(thatItem, /*recursive=*/true, /*moveToUnidexedItems=*/true);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return QGraphicsSceneIndex::itemChange(item, change, value);
+}
+/*!
+ \reimp
+
+ Used to catch the timer event.
+
+ \internal
+*/
+bool QGraphicsSceneBspTreeIndex::event(QEvent *event)
+{
+ Q_D(QGraphicsSceneBspTreeIndex);
+ switch (event->type()) {
+ case QEvent::Timer:
+ if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
+ if (d->restartIndexTimer) {
+ d->restartIndexTimer = false;
+ } else {
+ // this call will kill the timer
+ d->_q_updateIndex();
+ }
+ }
+ // Fallthrough intended - support timers in subclasses.
+ default:
+ return QObject::event(event);
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qgraphicsscenebsptreeindex_p.cpp"
+
+#endif // QT_NO_GRAPHICSVIEW
+
diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h b/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h
new file mode 100644
index 0000000..2e02458
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex_p.h
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QGRAPHICSBSPTREEINDEX_H
+#define QGRAPHICSBSPTREEINDEX_H
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+#include "qgraphicssceneindex_p.h"
+#include "qgraphicsitem_p.h"
+#include "qgraphicsscene_bsp_p.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qlist.h>
+
+static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
+
+class QGraphicsScene;
+class QGraphicsSceneBspTreeIndexPrivate;
+
+class Q_AUTOTEST_EXPORT QGraphicsSceneBspTreeIndex : public QGraphicsSceneIndex
+{
+ Q_OBJECT
+ Q_PROPERTY(int bspTreeDepth READ bspTreeDepth WRITE setBspTreeDepth)
+public:
+ QGraphicsSceneBspTreeIndex(QGraphicsScene *scene = 0);
+ ~QGraphicsSceneBspTreeIndex();
+
+ QList<QGraphicsItem *> estimateItems(const QRectF &rect, Qt::SortOrder order) const;
+ QList<QGraphicsItem *> estimateTopLevelItems(const QRectF &rect, Qt::SortOrder order) const;
+ QList<QGraphicsItem *> items(Qt::SortOrder order = Qt::AscendingOrder) const;
+
+ int bspTreeDepth();
+ void setBspTreeDepth(int depth);
+
+protected Q_SLOTS:
+ void updateSceneRect(const QRectF &rect);
+
+protected:
+ bool event(QEvent *event);
+ void clear();
+
+ void addItem(QGraphicsItem *item);
+ void removeItem(QGraphicsItem *item);
+ void prepareBoundingRectChange(const QGraphicsItem *item);
+
+ void itemChange(const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change, const QVariant &value);
+
+private :
+ Q_DECLARE_PRIVATE(QGraphicsSceneBspTreeIndex)
+ Q_DISABLE_COPY(QGraphicsSceneBspTreeIndex)
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSortCache())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateIndex())
+
+ friend class QGraphicsScene;
+ friend class QGraphicsScenePrivate;
+};
+
+class QGraphicsSceneBspTreeIndexPrivate : public QGraphicsSceneIndexPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneBspTreeIndex)
+public:
+ QGraphicsSceneBspTreeIndexPrivate(QGraphicsScene *scene);
+
+ QGraphicsSceneBspTree bsp;
+ QRectF sceneRect;
+ int bspTreeDepth;
+ int indexTimerId;
+ bool restartIndexTimer;
+ bool regenerateIndex;
+ int lastItemCount;
+
+ QList<QGraphicsItem *> indexedItems;
+ QList<QGraphicsItem *> unindexedItems;
+ QList<QGraphicsItem *> untransformableItems;
+ QList<int> freeItemIndexes;
+
+ bool purgePending;
+ QSet<QGraphicsItem *> removedItems;
+ void purgeRemovedItems();
+
+ void _q_updateIndex();
+ void startIndexTimer(int interval = QGRAPHICSSCENE_INDEXTIMER_TIMEOUT);
+ void resetIndex();
+
+ void _q_updateSortCache();
+ bool sortCacheEnabled;
+ bool updatingSortCache;
+ void invalidateSortCache();
+ void addItem(QGraphicsItem *item, bool recursive = false);
+ void removeItem(QGraphicsItem *item, bool recursive = false, bool moveToUnindexedItems = false);
+ QList<QGraphicsItem *> estimateItems(const QRectF &, Qt::SortOrder, bool b = false);
+
+ static void climbTree(QGraphicsItem *item, int *stackingOrder);
+ static bool closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2);
+ static bool closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2);
+
+ static inline bool closestItemFirst_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
+ {
+ return item1->d_ptr->globalStackingOrder < item2->d_ptr->globalStackingOrder;
+ }
+ static inline bool closestItemLast_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
+ {
+ return item1->d_ptr->globalStackingOrder >= item2->d_ptr->globalStackingOrder;
+ }
+
+ static void sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
+ bool cached, bool onlyTopLevelItems = false);
+};
+
+static inline bool QRectF_intersects(const QRectF &s, const QRectF &r)
+{
+ qreal xp = s.left();
+ qreal yp = s.top();
+ qreal w = s.width();
+ qreal h = s.height();
+ qreal l1 = xp;
+ qreal r1 = xp;
+ if (w < 0)
+ l1 += w;
+ else
+ r1 += w;
+
+ qreal l2 = r.left();
+ qreal r2 = r.left();
+ if (w < 0)
+ l2 += r.width();
+ else
+ r2 += r.width();
+
+ if (l1 >= r2 || l2 >= r1)
+ return false;
+
+ qreal t1 = yp;
+ qreal b1 = yp;
+ if (h < 0)
+ t1 += h;
+ else
+ b1 += h;
+
+ qreal t2 = r.top();
+ qreal b2 = r.top();
+ if (r.height() < 0)
+ t2 += r.height();
+ else
+ b2 += r.height();
+
+ return !(t1 >= b2 || t2 >= b1);
+}
+
+#endif // QT_NO_GRAPHICSVIEW
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGRAPHICSBSPTREEINDEX_H
diff --git a/src/gui/graphicsview/qgraphicssceneindex.cpp b/src/gui/graphicsview/qgraphicssceneindex.cpp
new file mode 100644
index 0000000..01efde4
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicssceneindex.cpp
@@ -0,0 +1,659 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+ \class QGraphicsSceneIndex
+ \brief The QGraphicsSceneIndex class provides a base class to implement
+ a custom indexing algorithm for discovering items in QGraphicsScene.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+ \mainclass
+ \internal
+
+ The QGraphicsSceneIndex class provides a base class to implement
+ a custom indexing algorithm for discovering items in QGraphicsScene. You
+ need to subclass it and reimplement addItem, removeItem, estimateItems
+ and items in order to have an functional indexing.
+
+ \sa QGraphicsScene, QGraphicsView
+*/
+
+#include "qdebug.h"
+#include "qgraphicsscene.h"
+#include "qgraphicsitem_p.h"
+#include "qgraphicsscene_p.h"
+#include "qgraphicswidget.h"
+#include "qgraphicssceneindex_p.h"
+#include "qgraphicsscenebsptreeindex_p.h"
+
+#ifndef QT_NO_GRAPHICSVIEW
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsSceneIndexRectIntersector : public QGraphicsSceneIndexIntersector
+{
+public:
+ bool intersect(const QGraphicsItem *item, const QRectF &exposeRect, Qt::ItemSelectionMode mode,
+ const QTransform &deviceTransform) const
+ {
+ QRectF brect = item->boundingRect();
+ _q_adjustRect(&brect);
+
+ // ### Add test for this (without making things slower?)
+ Q_UNUSED(exposeRect);
+
+ bool keep = true;
+ const QGraphicsItemPrivate *itemd = QGraphicsItemPrivate::get(item);
+ if (itemd->itemIsUntransformable()) {
+ // Untransformable items; map the scene rect to item coordinates.
+ const QTransform transform = item->deviceTransform(deviceTransform);
+ QRectF itemRect = (deviceTransform * transform.inverted()).mapRect(sceneRect);
+ if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
+ keep = itemRect.contains(brect) && itemRect != brect;
+ else
+ keep = itemRect.intersects(brect);
+ if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
+ QPainterPath itemPath;
+ itemPath.addRect(itemRect);
+ keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, itemPath, mode);
+ }
+ } else {
+ Q_ASSERT(!itemd->dirtySceneTransform);
+ const QRectF itemSceneBoundingRect = itemd->sceneTransformTranslateOnly
+ ? brect.translated(itemd->sceneTransform.dx(),
+ itemd->sceneTransform.dy())
+ : itemd->sceneTransform.mapRect(brect);
+ if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
+ keep = sceneRect != brect && sceneRect.contains(itemSceneBoundingRect);
+ else
+ keep = sceneRect.intersects(itemSceneBoundingRect);
+ if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
+ QPainterPath rectPath;
+ rectPath.addRect(sceneRect);
+ if (itemd->sceneTransformTranslateOnly)
+ rectPath.translate(-itemd->sceneTransform.dx(), -itemd->sceneTransform.dy());
+ else
+ rectPath = itemd->sceneTransform.inverted().map(rectPath);
+ keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, rectPath, mode);
+ }
+ }
+ return keep;
+ }
+
+ QRectF sceneRect;
+};
+
+class QGraphicsSceneIndexPointIntersector : public QGraphicsSceneIndexIntersector
+{
+public:
+ bool intersect(const QGraphicsItem *item, const QRectF &exposeRect, Qt::ItemSelectionMode mode,
+ const QTransform &deviceTransform) const
+ {
+ QRectF brect = item->boundingRect();
+ _q_adjustRect(&brect);
+
+ // ### Add test for this (without making things slower?)
+ Q_UNUSED(exposeRect);
+
+ bool keep = false;
+ const QGraphicsItemPrivate *itemd = QGraphicsItemPrivate::get(item);
+ if (itemd->itemIsUntransformable()) {
+ // Untransformable items; map the scene point to item coordinates.
+ const QTransform transform = item->deviceTransform(deviceTransform);
+ QPointF itemPoint = (deviceTransform * transform.inverted()).map(scenePoint);
+ keep = brect.contains(itemPoint);
+ if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
+ QPainterPath pointPath;
+ pointPath.addRect(QRectF(itemPoint, QSizeF(1, 1)));
+ keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, pointPath, mode);
+ }
+ } else {
+ Q_ASSERT(!itemd->dirtySceneTransform);
+ QRectF sceneBoundingRect = itemd->sceneTransformTranslateOnly
+ ? brect.translated(itemd->sceneTransform.dx(),
+ itemd->sceneTransform.dy())
+ : itemd->sceneTransform.mapRect(brect);
+ keep = sceneBoundingRect.intersects(QRectF(scenePoint, QSizeF(1, 1)));
+ if (keep) {
+ QPointF p = itemd->sceneTransformTranslateOnly
+ ? QPointF(scenePoint.x() - itemd->sceneTransform.dx(),
+ scenePoint.y() - itemd->sceneTransform.dy())
+ : itemd->sceneTransform.inverted().map(scenePoint);
+ keep = item->contains(p);
+ }
+ }
+
+ return keep;
+ }
+
+ QPointF scenePoint;
+};
+
+class QGraphicsSceneIndexPathIntersector : public QGraphicsSceneIndexIntersector
+{
+public:
+ bool intersect(const QGraphicsItem *item, const QRectF &exposeRect, Qt::ItemSelectionMode mode,
+ const QTransform &deviceTransform) const
+ {
+ QRectF brect = item->boundingRect();
+ _q_adjustRect(&brect);
+
+ // ### Add test for this (without making things slower?)
+ Q_UNUSED(exposeRect);
+
+ bool keep = true;
+ const QGraphicsItemPrivate *itemd = QGraphicsItemPrivate::get(item);
+ if (itemd->itemIsUntransformable()) {
+ // Untransformable items; map the scene rect to item coordinates.
+ const QTransform transform = item->deviceTransform(deviceTransform);
+ QPainterPath itemPath = (deviceTransform * transform.inverted()).map(scenePath);
+ if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
+ keep = itemPath.contains(brect);
+ else
+ keep = itemPath.intersects(brect);
+ if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape))
+ keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, itemPath, mode);
+ } else {
+ Q_ASSERT(!itemd->dirtySceneTransform);
+ const QRectF itemSceneBoundingRect = itemd->sceneTransformTranslateOnly
+ ? brect.translated(itemd->sceneTransform.dx(),
+ itemd->sceneTransform.dy())
+ : itemd->sceneTransform.mapRect(brect);
+ if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
+ keep = scenePath.contains(itemSceneBoundingRect);
+ else
+ keep = scenePath.intersects(itemSceneBoundingRect);
+ if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
+ QPainterPath itemPath = itemd->sceneTransformTranslateOnly
+ ? scenePath.translated(-itemd->sceneTransform.dx(),
+ -itemd->sceneTransform.dy())
+ : itemd->sceneTransform.inverted().map(scenePath);
+ keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, itemPath, mode);
+ }
+ }
+ return keep;
+ }
+
+ QPainterPath scenePath;
+};
+
+/*!
+ Constructs a private scene index.
+*/
+QGraphicsSceneIndexPrivate::QGraphicsSceneIndexPrivate(QGraphicsScene *scene) : scene(scene)
+{
+ pointIntersector = new QGraphicsSceneIndexPointIntersector;
+ rectIntersector = new QGraphicsSceneIndexRectIntersector;
+ pathIntersector = new QGraphicsSceneIndexPathIntersector;
+}
+
+/*!
+ Destructor of private scene index.
+*/
+QGraphicsSceneIndexPrivate::~QGraphicsSceneIndexPrivate()
+{
+ delete pointIntersector;
+ delete rectIntersector;
+ delete pathIntersector;
+}
+
+/*!
+ \internal
+
+ Checks if item collides with the path and mode, but also checks that if it
+ doesn't collide, maybe its frame rect will.
+*/
+bool QGraphicsSceneIndexPrivate::itemCollidesWithPath(const QGraphicsItem *item,
+ const QPainterPath &path,
+ Qt::ItemSelectionMode mode)
+{
+ if (item->collidesWithPath(path, mode))
+ return true;
+ if (item->isWidget()) {
+ // Check if this is a window, and if its frame rect collides.
+ const QGraphicsWidget *widget = static_cast<const QGraphicsWidget *>(item);
+ if (widget->isWindow()) {
+ QRectF frameRect = widget->windowFrameRect();
+ QPainterPath framePath;
+ framePath.addRect(frameRect);
+ bool intersects = path.intersects(frameRect);
+ if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
+ return intersects || path.contains(frameRect.topLeft())
+ || framePath.contains(path.elementAt(0));
+ return !intersects && path.contains(frameRect.topLeft());
+ }
+ }
+ return false;
+}
+
+/*!
+ \internal
+*/
+void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRectF exposeRect,
+ QGraphicsSceneIndexIntersector *intersector,
+ QList<QGraphicsItem *> *items,
+ const QTransform &viewTransform,
+ Qt::ItemSelectionMode mode, Qt::SortOrder order,
+ qreal parentOpacity) const
+{
+ Q_ASSERT(item);
+ if (!item->d_ptr->visible)
+ return;
+
+ const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
+ const bool itemIsFullyTransparent = (opacity < 0.0001);
+ const bool itemHasChildren = !item->d_ptr->children.isEmpty();
+ if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
+ return;
+
+ // Update the item's scene transform if dirty.
+ const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
+ const bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform && !itemIsUntransformable;
+ if (wasDirtyParentSceneTransform) {
+ item->d_ptr->updateSceneTransformFromParent();
+ Q_ASSERT(!item->d_ptr->dirtySceneTransform);
+ }
+
+ const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
+ bool processItem = !itemIsFullyTransparent;
+ if (processItem) {
+ processItem = intersector->intersect(item, exposeRect, mode, viewTransform);
+ if (!processItem && (!itemHasChildren || itemClipsChildrenToShape)) {
+ if (wasDirtyParentSceneTransform)
+ item->d_ptr->invalidateChildrenSceneTransform();
+ return;
+ }
+ } // else we know for sure this item has children we must process.
+
+ int i = 0;
+ if (itemHasChildren) {
+ // Sort children.
+ item->d_ptr->ensureSortedChildren();
+
+ // Clip to shape.
+ if (itemClipsChildrenToShape && !itemIsUntransformable) {
+ QPainterPath mappedShape = item->d_ptr->sceneTransformTranslateOnly
+ ? item->shape().translated(item->d_ptr->sceneTransform.dx(),
+ item->d_ptr->sceneTransform.dy())
+ : item->d_ptr->sceneTransform.map(item->shape());
+ exposeRect &= mappedShape.controlPointRect();
+ }
+
+ // Process children behind
+ for (i = 0; i < item->d_ptr->children.size(); ++i) {
+ QGraphicsItem *child = item->d_ptr->children.at(i);
+ if (wasDirtyParentSceneTransform)
+ child->d_ptr->dirtySceneTransform = 1;
+ if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
+ break;
+ if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
+ continue;
+ recursive_items_helper(child, exposeRect, intersector, items, viewTransform,
+ mode, order, opacity);
+ }
+ }
+
+ // Process item
+ if (processItem)
+ items->append(item);
+
+ // Process children in front
+ if (itemHasChildren) {
+ for (; i < item->d_ptr->children.size(); ++i) {
+ QGraphicsItem *child = item->d_ptr->children.at(i);
+ if (wasDirtyParentSceneTransform)
+ child->d_ptr->dirtySceneTransform = 1;
+ if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
+ continue;
+ recursive_items_helper(child, exposeRect, intersector, items, viewTransform,
+ mode, order, opacity);
+ }
+ }
+}
+
+void QGraphicsSceneIndexPrivate::init()
+{
+ if (!scene)
+ return;
+
+ QObject::connect(scene, SIGNAL(sceneRectChanged(const QRectF&)),
+ q_func(), SLOT(updateSceneRect(const QRectF&)));
+}
+
+/*!
+ Constructs an abstract scene index for a given \a scene.
+*/
+QGraphicsSceneIndex::QGraphicsSceneIndex(QGraphicsScene *scene)
+: QObject(*new QGraphicsSceneIndexPrivate(scene), scene)
+{
+ d_func()->init();
+}
+
+/*!
+ \internal
+*/
+QGraphicsSceneIndex::QGraphicsSceneIndex(QGraphicsSceneIndexPrivate &dd, QGraphicsScene *scene)
+ : QObject(dd, scene)
+{
+ d_func()->init();
+}
+
+/*!
+ Destroys the scene index.
+*/
+QGraphicsSceneIndex::~QGraphicsSceneIndex()
+{
+
+}
+
+/*!
+ Returns the scene of this index.
+*/
+QGraphicsScene* QGraphicsSceneIndex::scene() const
+{
+ Q_D(const QGraphicsSceneIndex);
+ return d->scene;
+}
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPointF &pos,
+ Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform
+ &deviceTransform) const
+
+ Returns all visible items that, depending on \a mode, are at the specified
+ \a pos and return a list sorted using \a order.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with \a pos are returned.
+
+ \a deviceTransform is the transformation apply to the view.
+
+ This method use the estimation of the index (estimateItems) and refine the
+ list to get an exact result. If you want to implement your own refinement
+ algorithm you can reimplement this method.
+
+ \sa estimateItems()
+
+*/
+QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPointF &pos, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform) const
+{
+
+ Q_D(const QGraphicsSceneIndex);
+ QList<QGraphicsItem *> itemList;
+ d->pointIntersector->scenePoint = pos;
+ d->items_helper(QRectF(pos, QSizeF(1, 1)), d->pointIntersector, &itemList, deviceTransform, mode, order);
+ return itemList;
+}
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QRectF &rect,
+ Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform
+ &deviceTransform) const
+
+ \overload
+
+ Returns all visible items that, depending on \a mode, are either inside or
+ intersect with the specified \a rect and return a list sorted using \a order.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a rect are returned.
+
+ \a deviceTransform is the transformation apply to the view.
+
+ This method use the estimation of the index (estimateItems) and refine
+ the list to get an exact result. If you want to implement your own
+ refinement algorithm you can reimplement this method.
+
+ \sa estimateItems()
+
+*/
+QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QRectF &rect, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform) const
+{
+ Q_D(const QGraphicsSceneIndex);
+ QRectF exposeRect = rect;
+ _q_adjustRect(&exposeRect);
+ QList<QGraphicsItem *> itemList;
+ d->rectIntersector->sceneRect = rect;
+ d->items_helper(exposeRect, d->rectIntersector, &itemList, deviceTransform, mode, order);
+ return itemList;
+}
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPolygonF
+ &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const
+ QTransform &deviceTransform) const
+
+ \overload
+
+ Returns all visible items that, depending on \a mode, are either inside or
+ intersect with the specified \a polygon and return a list sorted using \a order.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a polygon are returned.
+
+ \a deviceTransform is the transformation apply to the view.
+
+ This method use the estimation of the index (estimateItems) and refine
+ the list to get an exact result. If you want to implement your own
+ refinement algorithm you can reimplement this method.
+
+ \sa estimateItems()
+
+*/
+QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform) const
+{
+ Q_D(const QGraphicsSceneIndex);
+ QList<QGraphicsItem *> itemList;
+ QRectF exposeRect = polygon.boundingRect();
+ _q_adjustRect(&exposeRect);
+ QPainterPath path;
+ path.addPolygon(polygon);
+ d->pathIntersector->scenePath = path;
+ d->items_helper(exposeRect, d->pathIntersector, &itemList, deviceTransform, mode, order);
+ return itemList;
+}
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPainterPath
+ &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform
+ &deviceTransform) const
+
+ \overload
+
+ Returns all visible items that, depending on \a mode, are either inside or
+ intersect with the specified \a path and return a list sorted using \a order.
+
+ The default value for \a mode is Qt::IntersectsItemShape; all items whose
+ exact shape intersects with or is contained by \a path are returned.
+
+ \a deviceTransform is the transformation apply to the view.
+
+ This method use the estimation of the index (estimateItems) and refine
+ the list to get an exact result. If you want to implement your own
+ refinement algorithm you can reimplement this method.
+
+ \sa estimateItems()
+
+*/
+QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform) const
+{
+ Q_D(const QGraphicsSceneIndex);
+ QList<QGraphicsItem *> itemList;
+ QRectF exposeRect = path.controlPointRect();
+ _q_adjustRect(&exposeRect);
+ d->pathIntersector->scenePath = path;
+ d->items_helper(exposeRect, d->pathIntersector, &itemList, deviceTransform, mode, order);
+ return itemList;
+}
+
+/*!
+ This virtual function return an estimation of items at position \a point.
+ This method return a list sorted using \a order.
+*/
+QList<QGraphicsItem *> QGraphicsSceneIndex::estimateItems(const QPointF &point, Qt::SortOrder order) const
+{
+ return estimateItems(QRectF(point, QSize(1, 1)), order);
+}
+
+QList<QGraphicsItem *> QGraphicsSceneIndex::estimateTopLevelItems(const QRectF &rect, Qt::SortOrder order) const
+{
+ Q_D(const QGraphicsSceneIndex);
+ Q_UNUSED(rect);
+ QGraphicsScenePrivate *scened = d->scene->d_func();
+ scened->ensureSortedTopLevelItems();
+ if (order == Qt::AscendingOrder) {
+ QList<QGraphicsItem *> sorted;
+ for (int i = scened->topLevelItems.size() - 1; i >= 0; --i)
+ sorted << scened->topLevelItems.at(i);
+ return sorted;
+ }
+ return scened->topLevelItems;
+}
+
+/*!
+ \fn virtual QList<QGraphicsItem *>
+ QGraphicsSceneIndex::estimateItems(const QRectF &rect, Qt::SortOrder
+ order, const QTransform &deviceTransform) const = 0
+
+ This pure virtual function return an estimation of items in the \a rect.
+ This method return a list sorted using \a order.
+
+ \a deviceTransform is the transformation apply to the view.
+*/
+
+/*!
+ \fn virtual QList<QGraphicsItem *>
+ QGraphicsSceneIndex::items(Qt::SortOrder order = Qt::AscendingOrder) const
+ = 0; This pure virtual function all items in the index and sort them using
+ \a order.
+*/
+
+
+/*!
+ Notifies the index that the scene's scene rect has changed. \a rect
+ is thew new scene rect.
+
+ \sa QGraphicsScene::sceneRect()
+*/
+void QGraphicsSceneIndex::updateSceneRect(const QRectF &rect)
+{
+ Q_UNUSED(rect);
+}
+
+/*!
+ This virtual function removes all items in the scene index.
+*/
+void QGraphicsSceneIndex::clear()
+{
+ const QList<QGraphicsItem *> allItems = items();
+ for (int i = 0 ; i < allItems.size(); ++i)
+ removeItem(allItems.at(i));
+}
+
+/*!
+ \fn virtual void QGraphicsSceneIndex::addItem(QGraphicsItem *item) = 0
+
+ This pure virtual function inserts an \a item to the scene index.
+
+ \sa removeItem(), deleteItem()
+*/
+
+/*!
+ \fn virtual void QGraphicsSceneIndex::removeItem(QGraphicsItem *item) = 0
+
+ This pure virtual function removes an \a item to the scene index.
+
+ \sa addItem(), deleteItem()
+*/
+
+/*!
+ This method is called when an \a item has been deleted.
+ The default implementation call removeItem. Be carefull,
+ if your implementation of removeItem use pure virtual method
+ of QGraphicsItem like boundingRect(), then you should reimplement
+ this method.
+
+ \sa addItem(), removeItem()
+*/
+void QGraphicsSceneIndex::deleteItem(QGraphicsItem *item)
+{
+ removeItem(item);
+}
+
+/*!
+ This virtual function is called by QGraphicsItem to notify the index
+ that some part of the \a item 's state changes. By reimplementing this
+ function, your can react to a change, and in some cases, (depending on \a
+ change,) adjustments in the index can be made.
+
+ \a change is the parameter of the item that is changing. \a value is the
+ value that changed; the type of the value depends on \a change.
+
+ The default implementation does nothing.
+
+ \sa QGraphicsItem::GraphicsItemChange
+*/
+void QGraphicsSceneIndex::itemChange(const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change, const QVariant &value)
+{
+ Q_UNUSED(item);
+ Q_UNUSED(change);
+ Q_UNUSED(value);
+}
+
+/*!
+ Notify the index for a geometry change of an \a item.
+
+ \sa QGraphicsItem::prepareGeometryChange()
+*/
+void QGraphicsSceneIndex::prepareBoundingRectChange(const QGraphicsItem *item)
+{
+ Q_UNUSED(item);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qgraphicssceneindex_p.cpp"
+
+#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicssceneindex_p.h b/src/gui/graphicsview/qgraphicssceneindex_p.h
new file mode 100644
index 0000000..8cf0294
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicssceneindex_p.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSCENEINDEX_H
+#define QGRAPHICSSCENEINDEX_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgraphicsscene_p.h"
+#include "qgraphicsscene.h"
+#include <private/qobject_p.h>
+
+#include <QtCore/qnamespace.h>
+#include <QtCore/qobject.h>
+#include <QtGui/qtransform.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+class QGraphicsSceneIndexIntersector;
+class QGraphicsSceneIndexPointIntersector;
+class QGraphicsSceneIndexRectIntersector;
+class QGraphicsSceneIndexPathIntersector;
+class QGraphicsSceneIndexPrivate;
+class QPointF;
+class QRectF;
+template<typename T> class QList;
+
+class Q_AUTOTEST_EXPORT QGraphicsSceneIndex : public QObject
+{
+ Q_OBJECT
+
+public:
+ QGraphicsSceneIndex(QGraphicsScene *scene = 0);
+ virtual ~QGraphicsSceneIndex();
+
+ QGraphicsScene *scene() const;
+
+ virtual QList<QGraphicsItem *> items(Qt::SortOrder order = Qt::AscendingOrder) const = 0;
+ virtual QList<QGraphicsItem *> items(const QPointF &pos, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform = QTransform()) const;
+ virtual QList<QGraphicsItem *> items(const QRectF &rect, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform = QTransform()) const;
+ virtual QList<QGraphicsItem *> items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform = QTransform()) const;
+ virtual QList<QGraphicsItem *> items(const QPainterPath &path, Qt::ItemSelectionMode mode,
+ Qt::SortOrder order, const QTransform &deviceTransform = QTransform()) const;
+ virtual QList<QGraphicsItem *> estimateItems(const QPointF &point, Qt::SortOrder order) const;
+ virtual QList<QGraphicsItem *> estimateItems(const QRectF &rect, Qt::SortOrder order) const = 0;
+ virtual QList<QGraphicsItem *> estimateTopLevelItems(const QRectF &, Qt::SortOrder order) const;
+
+protected Q_SLOTS:
+ virtual void updateSceneRect(const QRectF &rect);
+
+protected:
+ virtual void clear();
+ virtual void addItem(QGraphicsItem *item) = 0;
+ virtual void removeItem(QGraphicsItem *item) = 0;
+ virtual void deleteItem(QGraphicsItem *item);
+
+ virtual void itemChange(const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange, const QVariant &value);
+ virtual void prepareBoundingRectChange(const QGraphicsItem *item);
+
+ QGraphicsSceneIndex(QGraphicsSceneIndexPrivate &dd, QGraphicsScene *scene);
+
+ friend class QGraphicsScene;
+ friend class QGraphicsScenePrivate;
+ friend class QGraphicsItem;
+ friend class QGraphicsItemPrivate;
+ friend class QGraphicsSceneBspTreeIndex;
+private:
+ Q_DISABLE_COPY(QGraphicsSceneIndex)
+ Q_DECLARE_PRIVATE(QGraphicsSceneIndex)
+};
+
+class QGraphicsSceneIndexPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneIndex)
+public:
+ QGraphicsSceneIndexPrivate(QGraphicsScene *scene);
+ ~QGraphicsSceneIndexPrivate();
+
+ void init();
+ static bool itemCollidesWithPath(const QGraphicsItem *item, const QPainterPath &path, Qt::ItemSelectionMode mode);
+
+ void recursive_items_helper(QGraphicsItem *item, QRectF exposeRect,
+ QGraphicsSceneIndexIntersector *intersector, QList<QGraphicsItem *> *items,
+ const QTransform &viewTransform,
+ Qt::ItemSelectionMode mode, Qt::SortOrder order, qreal parentOpacity = 1.0) const;
+ inline void items_helper(const QRectF &rect, QGraphicsSceneIndexIntersector *intersector,
+ QList<QGraphicsItem *> *items, const QTransform &viewTransform,
+ Qt::ItemSelectionMode mode, Qt::SortOrder order) const;
+
+ QGraphicsScene *scene;
+ QGraphicsSceneIndexPointIntersector *pointIntersector;
+ QGraphicsSceneIndexRectIntersector *rectIntersector;
+ QGraphicsSceneIndexPathIntersector *pathIntersector;
+};
+
+inline void QGraphicsSceneIndexPrivate::items_helper(const QRectF &rect, QGraphicsSceneIndexIntersector *intersector,
+ QList<QGraphicsItem *> *items, const QTransform &viewTransform,
+ Qt::ItemSelectionMode mode, Qt::SortOrder order) const
+{
+ Q_Q(const QGraphicsSceneIndex);
+ const QList<QGraphicsItem *> tli = q->estimateTopLevelItems(rect, Qt::DescendingOrder);
+ for (int i = 0; i < tli.size(); ++i)
+ recursive_items_helper(tli.at(i), rect, intersector, items, viewTransform, mode, order);
+ if (order == Qt::AscendingOrder) {
+ const int n = items->size();
+ for (int i = 0; i < n / 2; ++i)
+ items->swap(i, n - i - 1);
+ }
+}
+
+class QGraphicsSceneIndexIntersector
+{
+public:
+ QGraphicsSceneIndexIntersector() { }
+ virtual ~QGraphicsSceneIndexIntersector() { }
+ virtual bool intersect(const QGraphicsItem *item, const QRectF &exposeRect, Qt::ItemSelectionMode mode,
+ const QTransform &deviceTransform) const = 0;
+};
+
+#endif // QT_NO_GRAPHICSVIEW
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGRAPHICSSCENEINDEX_H
diff --git a/src/gui/graphicsview/qgraphicsscenelinearindex.cpp b/src/gui/graphicsview/qgraphicsscenelinearindex.cpp
new file mode 100644
index 0000000..5e6ac30
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscenelinearindex.cpp
@@ -0,0 +1,62 @@
+/*!
+ \class QGraphicsSceneLinearIndex
+ \brief The QGraphicsSceneLinearIndex class provides an implementation of
+ a linear indexing algorithm for discovering items in QGraphicsScene.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+ \mainclass
+ \internal
+
+ QGraphicsSceneLinearIndex index is default linear implementation to discover items.
+ It basically store all items in a list and return them to the scene.
+
+ \sa QGraphicsScene, QGraphicsView, QGraphicsSceneIndex, QGraphicsSceneBspTreeIndex
+*/
+
+#include <private/qgraphicsscenelinearindex_p.h>
+
+/*!
+ \fn QGraphicsSceneLinearIndex::QGraphicsSceneLinearIndex(QGraphicsScene *scene = 0):
+
+ Construct a linear index for the given \a scene.
+*/
+
+/*!
+ \fn QList<QGraphicsItem *> QGraphicsSceneLinearIndex::items(Qt::SortOrder order = Qt::AscendingOrder) const;
+
+ Return all items in the index and sort them using \a order.
+*/
+
+
+/*!
+ \fn virtual QList<QGraphicsItem *> QGraphicsSceneLinearIndex::estimateItems(const QRectF &rect, Qt::SortOrder order) const;
+
+ Returns an estimation visible items that are either inside or
+ intersect with the specified \a rect and return a list sorted using \a order.
+*/
+
+/*!
+ \fn QRectF QGraphicsSceneLinearIndex::indexedRect() const;
+ \reimp
+ Return the rect indexed by the the index.
+*/
+
+/*!
+ \fn void QGraphicsSceneLinearIndex::clear();
+ \reimp
+ Clear the all the BSP index.
+*/
+
+/*!
+ \fn virtual void QGraphicsSceneLinearIndex::addItem(QGraphicsItem *item);
+
+ Add the \a item into the index.
+*/
+
+/*!
+ \fn virtual void QGraphicsSceneLinearIndex::removeItem(QGraphicsItem *item);
+
+ Add the \a item from the index.
+*/
+
diff --git a/src/gui/graphicsview/qgraphicsscenelinearindex_p.h b/src/gui/graphicsview/qgraphicsscenelinearindex_p.h
new file mode 100644
index 0000000..56dde3a
--- /dev/null
+++ b/src/gui/graphicsview/qgraphicsscenelinearindex_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSCENELINEARINDEX_H
+#define QGRAPHICSSCENELINEARINDEX_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+
+#include <QtCore/qrect.h>
+#include <QtCore/qlist.h>
+#include <QtGui/qgraphicsitem.h>
+#include <private/qgraphicssceneindex_p.h>
+
+class Q_AUTOTEST_EXPORT QGraphicsSceneLinearIndex : public QGraphicsSceneIndex
+{
+ Q_OBJECT
+
+public:
+ QGraphicsSceneLinearIndex(QGraphicsScene *scene = 0) : QGraphicsSceneIndex(scene)
+ { }
+
+ QList<QGraphicsItem *> items(Qt::SortOrder order = Qt::AscendingOrder) const
+ { Q_UNUSED(order); return m_items; }
+
+ virtual QList<QGraphicsItem *> estimateItems(const QRectF &rect, Qt::SortOrder order) const
+ {
+ Q_UNUSED(rect);
+ Q_UNUSED(order);
+ return m_items;
+ }
+
+protected :
+ virtual void clear()
+ { m_items.clear(); }
+
+ virtual void addItem(QGraphicsItem *item)
+ { m_items << item; }
+
+ virtual void removeItem(QGraphicsItem *item)
+ { m_items.removeOne(item); }
+
+private:
+ QList<QGraphicsItem*> m_items;
+};
+
+#endif // QT_NO_GRAPHICSVIEW
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGRAPHICSSCENELINEARINDEX_H
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 3b29552..bcfd68c 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -813,19 +813,9 @@ QRegion QGraphicsViewPrivate::mapToViewRegion(const QGraphicsItem *item, const Q
return item->boundingRegion(itv) & itv.mapRect(rect).toAlignedRect();
}
-// QRectF::intersects() returns false always if either the source or target
-// rectangle's width or height are 0. This works around that problem.
-static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
-{
- Q_ASSERT(item);
- QRectF boundingRect(item->boundingRect());
- if (!boundingRect.width())
- boundingRect.adjust(-0.00001, 0, 0.00001, 0);
- if (!boundingRect.height())
- boundingRect.adjust(0, -0.00001, 0, 0.00001);
- return boundingRect;
-}
-
+/*!
+ \internal
+*/
void QGraphicsViewPrivate::processPendingUpdates()
{
if (!scene)
@@ -850,13 +840,29 @@ void QGraphicsViewPrivate::processPendingUpdates()
dirtyRegion = QRegion();
}
+static inline bool intersectsViewport(const QRect &r, int width, int height)
+{ return !(r.left() > width) && !(r.right() < 0) && !(r.top() >= height) && !(r.bottom() < 0); }
+
+static inline bool containsViewport(const QRect &r, int width, int height)
+{ return r.left() <= 0 && r.top() <= 0 && r.right() >= width - 1 && r.bottom() >= height - 1; }
+
+static inline void QRect_unite(QRect *rect, const QRect &other)
+{
+ if (rect->isEmpty()) {
+ *rect = other;
+ } else {
+ rect->setCoords(qMin(rect->left(), other.left()), qMin(rect->top(), other.top()),
+ qMax(rect->right(), other.right()), qMax(rect->bottom(), other.bottom()));
+ }
+}
+
bool QGraphicsViewPrivate::updateRegion(const QRegion &r)
{
if (fullUpdatePending || viewportUpdateMode == QGraphicsView::NoViewportUpdate || r.isEmpty())
return false;
const QRect boundingRect = r.boundingRect();
- if (!boundingRect.intersects(viewport->rect()))
+ if (!intersectsViewport(boundingRect, viewport->width(), viewport->height()))
return false; // Update region outside viewport.
switch (viewportUpdateMode) {
@@ -865,8 +871,8 @@ bool QGraphicsViewPrivate::updateRegion(const QRegion &r)
viewport->update();
break;
case QGraphicsView::BoundingRectViewportUpdate:
- dirtyBoundingRect |= boundingRect;
- if (dirtyBoundingRect.contains(viewport->rect())) {
+ QRect_unite(&dirtyBoundingRect, boundingRect);
+ if (containsViewport(dirtyBoundingRect, viewport->width(), viewport->height())) {
fullUpdatePending = true;
viewport->update();
}
@@ -893,7 +899,7 @@ bool QGraphicsViewPrivate::updateRegion(const QRegion &r)
bool QGraphicsViewPrivate::updateRect(const QRect &r)
{
if (fullUpdatePending || viewportUpdateMode == QGraphicsView::NoViewportUpdate
- || !r.intersects(viewport->rect())) {
+ || !intersectsViewport(r, viewport->width(), viewport->height())) {
return false;
}
@@ -903,8 +909,8 @@ bool QGraphicsViewPrivate::updateRect(const QRect &r)
viewport->update();
break;
case QGraphicsView::BoundingRectViewportUpdate:
- dirtyBoundingRect |= r;
- if (dirtyBoundingRect.contains(viewport->rect())) {
+ QRect_unite(&dirtyBoundingRect, r);
+ if (containsViewport(dirtyBoundingRect, viewport->width(), viewport->height())) {
fullUpdatePending = true;
viewport->update();
}
@@ -955,47 +961,32 @@ extern QPainterPath qt_regionToPath(const QRegion &region);
is at risk of painting 1 pixel outside the bounding rect. Therefore we
must search for items with an adjustment of (-1, -1, 1, 1).
*/
-QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedRegion, bool *allItems) const
+QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedRegion, bool *allItems,
+ const QTransform &viewTransform) const
{
Q_Q(const QGraphicsView);
// Step 1) If all items are contained within the expose region, then
- // return a list of all visible items.
+ // return a list of all visible items. ### the scene's growing bounding
+ // rect does not take into account untransformable items.
const QRectF exposedRegionSceneBounds = q->mapToScene(exposedRegion.boundingRect().adjusted(-1, -1, 1, 1))
.boundingRect();
- if (exposedRegionSceneBounds.contains(scene->d_func()->growingItemsBoundingRect)) {
+ if (exposedRegionSceneBounds.contains(scene->sceneRect())) {
Q_ASSERT(allItems);
*allItems = true;
- // All items are guaranteed within the exposed region, don't bother using the index.
- QList<QGraphicsItem *> itemList(scene->items());
- int i = 0;
- while (i < itemList.size()) {
- const QGraphicsItem *item = itemList.at(i);
- // But we only want to include items that are visible
- // The following check is basically the same as item->d_ptr->isInvisible(), except
- // that we don't check whether the item clips children to shape or propagates its
- // opacity (we loop through all items, so those checks are wrong in this context).
- if (!item->isVisible() || item->d_ptr->isClippedAway() || item->d_ptr->isFullyTransparent())
- itemList.removeAt(i);
- else
- ++i;
- }
-
- // Sort the items.
- QGraphicsScenePrivate::sortItems(&itemList, Qt::DescendingOrder, scene->d_func()->sortCacheEnabled);
- return itemList;
+ // All items are guaranteed within the exposed region.
+ return scene->items(Qt::DescendingOrder);
}
// Step 2) If the expose region is a simple rect and the view is only
// translated or scaled, search for items using
// QGraphicsScene::items(QRectF).
- bool simpleRectLookup = (scene->d_func()->largestUntransformableItem.isNull()
- && exposedRegion.numRects() == 1 && matrix.type() <= QTransform::TxScale);
+ bool simpleRectLookup = exposedRegion.numRects() == 1 && matrix.type() <= QTransform::TxScale;
if (simpleRectLookup) {
- return scene->d_func()->items_helper(exposedRegionSceneBounds,
- Qt::IntersectsItemBoundingRect,
- Qt::DescendingOrder);
+ return scene->items(exposedRegionSceneBounds,
+ Qt::IntersectsItemBoundingRect,
+ Qt::DescendingOrder, viewTransform);
}
// If the region is complex or the view has a complex transform, adjust
@@ -1005,16 +996,9 @@ QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedReg
foreach (const QRect &r, exposedRegion.rects())
adjustedRegion += r.adjusted(-1, -1, 1, 1);
- const QPainterPath exposedPath(qt_regionToPath(adjustedRegion));
- if (scene->d_func()->largestUntransformableItem.isNull()) {
- const QPainterPath exposedScenePath(q->mapToScene(exposedPath));
- return scene->d_func()->items_helper(exposedScenePath,
- Qt::IntersectsItemBoundingRect,
- Qt::DescendingOrder);
- }
-
- // NB! Path must be in viewport coordinates.
- return itemsInArea(exposedPath, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder);
+ const QPainterPath exposedScenePath(q->mapToScene(qt_regionToPath(adjustedRegion)));
+ return scene->items(exposedScenePath, Qt::IntersectsItemBoundingRect,
+ Qt::DescendingOrder, viewTransform);
}
/*!
@@ -1915,7 +1899,12 @@ void QGraphicsView::fitInView(const QRectF &rect, Qt::AspectRatioMode aspectRati
void QGraphicsView::fitInView(const QGraphicsItem *item, Qt::AspectRatioMode aspectRatioMode)
{
QPainterPath path = item->isClipped() ? item->clipPath() : item->shape();
- fitInView(item->sceneTransform().map(path).boundingRect(), aspectRatioMode);
+ if (item->d_ptr->hasTranslateOnlySceneTransform()) {
+ path.translate(item->d_ptr->sceneTransform.dx(), item->d_ptr->sceneTransform.dy());
+ fitInView(path.boundingRect(), aspectRatioMode);
+ } else {
+ fitInView(item->d_ptr->sceneTransform.map(path).boundingRect(), aspectRatioMode);
+ }
}
/*!
@@ -1941,6 +1930,8 @@ void QGraphicsView::fitInView(const QGraphicsItem *item, Qt::AspectRatioMode asp
void QGraphicsView::render(QPainter *painter, const QRectF &target, const QRect &source,
Qt::AspectRatioMode aspectRatioMode)
{
+ // ### Switch to using the recursive rendering algorithm instead.
+
Q_D(QGraphicsView);
if (!d->scene || !(painter && painter->isActive()))
return;
@@ -2037,69 +2028,6 @@ QList<QGraphicsItem *> QGraphicsView::items() const
}
/*!
- Returns all items in the area \a path, which is in viewport coordinates,
- also taking untransformable items into consideration. This function is
- considerably slower than just checking the scene directly. There is
- certainly room for improvement.
-*/
-QList<QGraphicsItem *> QGraphicsViewPrivate::itemsInArea(const QPainterPath &path,
- Qt::ItemSelectionMode mode,
- Qt::SortOrder order) const
-{
- Q_Q(const QGraphicsView);
-
- // Determine the size of the largest untransformable subtree of children
- // mapped to scene coordinates.
- QRectF untr = scene->d_func()->largestUntransformableItem;
- QRectF ltri = matrix.inverted().mapRect(untr);
- ltri.adjust(-untr.width(), -untr.height(), untr.width(), untr.height());
-
- QRectF rect = path.controlPointRect();
-
- // Find all possible items in the relevant area.
- // ### Improve this algorithm; it might be searching a too large area.
- QRectF adjustedRect = q->mapToScene(rect.adjusted(-1, -1, 1, 1).toRect()).boundingRect();
- adjustedRect.adjust(-ltri.width(), -ltri.height(), ltri.width(), ltri.height());
-
- // First build a (potentially large) list of all items in the vicinity
- // that might be untransformable.
- QList<QGraphicsItem *> allCandidates = scene->d_func()->estimateItemsInRect(adjustedRect);
-
- // Then find the minimal list of items that are inside \a path, and
- // convert it to a set.
- QList<QGraphicsItem *> regularCandidates = scene->items(q->mapToScene(path), mode);
- QSet<QGraphicsItem *> candSet = QSet<QGraphicsItem *>::fromList(regularCandidates);
-
- QTransform viewMatrix = q->viewportTransform();
-
- QList<QGraphicsItem *> result;
-
- // Run through all candidates and keep all items that are in candSet, or
- // are untransformable and collide with \a path. ### We can improve this
- // algorithm.
- QList<QGraphicsItem *>::Iterator it = allCandidates.begin();
- while (it != allCandidates.end()) {
- QGraphicsItem *item = *it;
- if (item->d_ptr->itemIsUntransformable()) {
- // Check if this untransformable item collides with the
- // original selection rect.
- QTransform itemTransform = item->deviceTransform(viewMatrix);
- if (QGraphicsScenePrivate::itemCollidesWithPath(item, itemTransform.inverted().map(path), mode))
- result << item;
- } else {
- if (candSet.contains(item))
- result << item;
- }
- ++it;
- }
-
- // ### Insertion sort would be faster.
- if (order != Qt::SortOrder(-1))
- QGraphicsScenePrivate::sortItems(&result, order, scene->d_func()->sortCacheEnabled);
- return result;
-}
-
-/*!
Returns a list of all the items at the position \a pos in the view. The
items are listed in descending Z order (i.e., the first item in the list
is the top-most item, and the last item is the bottom-most item). \a pos
@@ -2118,17 +2046,22 @@ QList<QGraphicsItem *> QGraphicsView::items(const QPoint &pos) const
Q_D(const QGraphicsView);
if (!d->scene)
return QList<QGraphicsItem *>();
- if (d->scene->d_func()->largestUntransformableItem.isNull()) {
- if ((d->identityMatrix || d->matrix.type() <= QTransform::TxScale)) {
- QTransform xinv = viewportTransform().inverted();
- return d->scene->items(xinv.mapRect(QRectF(pos.x(), pos.y(), 1, 1)));
- }
- return d->scene->items(mapToScene(pos.x(), pos.y(), 1, 1));
+ // ### Unify these two, and use the items(QPointF) version in
+ // QGraphicsScene instead. The scene items function could use the viewport
+ // transform to map the point to a rect/polygon.
+ if ((d->identityMatrix || d->matrix.type() <= QTransform::TxScale)) {
+ // Use the rect version
+ QTransform xinv = viewportTransform().inverted();
+ return d->scene->items(xinv.mapRect(QRectF(pos.x(), pos.y(), 1, 1)),
+ Qt::IntersectsItemShape,
+ Qt::AscendingOrder,
+ viewportTransform());
}
-
- QPainterPath path;
- path.addRect(QRectF(pos.x(), pos.y(), 1, 1));
- return d->itemsInArea(path);
+ // Use the polygon version
+ return d->scene->items(mapToScene(pos.x(), pos.y(), 1, 1),
+ Qt::IntersectsItemShape,
+ Qt::AscendingOrder,
+ viewportTransform());
}
/*!
@@ -2155,12 +2088,7 @@ QList<QGraphicsItem *> QGraphicsView::items(const QRect &rect, Qt::ItemSelection
Q_D(const QGraphicsView);
if (!d->scene)
return QList<QGraphicsItem *>();
- if (d->scene->d_func()->largestUntransformableItem.isNull())
- return d->scene->items(mapToScene(rect), mode);
-
- QPainterPath path;
- path.addRect(rect);
- return d->itemsInArea(path);
+ return d->scene->items(mapToScene(rect), mode, Qt::AscendingOrder, viewportTransform());
}
/*!
@@ -2188,13 +2116,7 @@ QList<QGraphicsItem *> QGraphicsView::items(const QPolygon &polygon, Qt::ItemSel
Q_D(const QGraphicsView);
if (!d->scene)
return QList<QGraphicsItem *>();
- if (d->scene->d_func()->largestUntransformableItem.isNull())
- return d->scene->items(mapToScene(polygon), mode);
-
- QPainterPath path;
- path.addPolygon(polygon);
- path.closeSubpath();
- return d->itemsInArea(path);
+ return d->scene->items(mapToScene(polygon), mode, Qt::AscendingOrder, viewportTransform());
}
/*!
@@ -2214,9 +2136,7 @@ QList<QGraphicsItem *> QGraphicsView::items(const QPainterPath &path, Qt::ItemSe
Q_D(const QGraphicsView);
if (!d->scene)
return QList<QGraphicsItem *>();
- if (d->scene->d_func()->largestUntransformableItem.isNull())
- return d->scene->items(mapToScene(path), mode);
- return d->itemsInArea(path);
+ return d->scene->items(mapToScene(path), mode, Qt::AscendingOrder, viewportTransform());
}
/*!
@@ -3169,7 +3089,8 @@ void QGraphicsView::mouseMoveEvent(QMouseEvent *event)
selectionArea.addPolygon(mapToScene(d->rubberBandRect));
selectionArea.closeSubpath();
if (d->scene)
- d->scene->setSelectionArea(selectionArea, d->rubberBandSelectionMode);
+ d->scene->setSelectionArea(selectionArea, d->rubberBandSelectionMode,
+ viewportTransform());
return;
}
} else
@@ -3382,8 +3303,7 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
} else {
// Find all exposed items
bool allItems = false;
- QList<QGraphicsItem *> itemList = d->findItems(d->exposedRegion, &allItems);
-
+ QList<QGraphicsItem *> itemList = d->findItems(d->exposedRegion, &allItems, viewTransform);
if (!itemList.isEmpty()) {
// Generate the style options.
const int numItems = itemList.size();
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index 09d842d..0fa8b34 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -59,11 +59,12 @@
#include <QtGui/qevent.h>
#include "qgraphicssceneevent.h"
+#include <QtGui/qstyleoption.h>
#include <private/qabstractscrollarea_p.h>
QT_BEGIN_NAMESPACE
-class QGraphicsViewPrivate : public QAbstractScrollAreaPrivate
+class Q_AUTOTEST_EXPORT QGraphicsViewPrivate : public QAbstractScrollAreaPrivate
{
Q_DECLARE_PUBLIC(QGraphicsView)
public:
@@ -84,10 +85,6 @@ public:
qint64 horizontalScroll() const;
qint64 verticalScroll() const;
- QList<QGraphicsItem *> itemsInArea(const QPainterPath &path,
- Qt::ItemSelectionMode mode = Qt::IntersectsItemShape,
- Qt::SortOrder = Qt::AscendingOrder) const;
-
QPointF mousePressItemPoint;
QPointF mousePressScenePoint;
QPoint mousePressViewPoint;
@@ -176,7 +173,8 @@ public:
bool updateSceneSlotReimplementedChecked;
QRegion exposedRegion;
- QList<QGraphicsItem *> findItems(const QRegion &exposedRegion, bool *allItems) const;
+ QList<QGraphicsItem *> findItems(const QRegion &exposedRegion, bool *allItems,
+ const QTransform &viewTransform) const;
QPointF mapToScene(const QPointF &point) const;
QRectF mapToScene(const QRectF &rect) const;
diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp
index dd84304..a4a69c3 100644
--- a/src/gui/itemviews/qabstractitemview.cpp
+++ b/src/gui/itemviews/qabstractitemview.cpp
@@ -3881,30 +3881,48 @@ bool QAbstractItemViewPrivate::openEditor(const QModelIndex &index, QEvent *even
return true;
}
-QPixmap QAbstractItemViewPrivate::renderToPixmap(const QModelIndexList &indexes, QRect *r) const
+/*
+ \internal
+
+ returns the pair QRect/QModelIndex that should be painted on the viewports's rect
+ */
+
+QItemViewPaintPairs QAbstractItemViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
{
+ Q_ASSERT(r);
Q_Q(const QAbstractItemView);
- QRect rect = q->visualRect(indexes.at(0));
- QList<QRect> rects;
+ QRect &rect = *r;
+ const QRect viewportRect = viewport->rect();
+ QItemViewPaintPairs ret;
for (int i = 0; i < indexes.count(); ++i) {
- rects.append(q->visualRect(indexes.at(i)));
- rect |= rects.at(i);
+ const QModelIndex &index = indexes.at(i);
+ const QRect current = q->visualRect(index);
+ if (current.intersects(viewportRect)) {
+ ret += qMakePair(current, index);
+ rect |= current;
+ }
}
- rect = rect.intersected(viewport->rect());
- if (rect.width() <= 0 || rect.height() <= 0)
+ rect &= viewportRect;
+ return ret;
+}
+
+QPixmap QAbstractItemViewPrivate::renderToPixmap(const QModelIndexList &indexes, QRect *r) const
+{
+ Q_ASSERT(r);
+ QItemViewPaintPairs paintPairs = draggablePaintPairs(indexes, r);
+ if (paintPairs.isEmpty())
return QPixmap();
- QImage image(rect.size(), QImage::Format_ARGB32_Premultiplied);
- image.fill(0);
- QPainter painter(&image);
+ QPixmap pixmap(r->size());
+ pixmap.fill(Qt::transparent);
+ QPainter painter(&pixmap);
QStyleOptionViewItemV4 option = viewOptionsV4();
option.state |= QStyle::State_Selected;
- for (int j = 0; j < indexes.count(); ++j) {
- option.rect = QRect(rects.at(j).topLeft() - rect.topLeft(), rects.at(j).size());
- delegateForIndex(indexes.at(j))->paint(&painter, option, indexes.at(j));
+ for (int j = 0; j < paintPairs.count(); ++j) {
+ option.rect = paintPairs.at(j).first.translated(r->topLeft());
+ const QModelIndex &current = paintPairs.at(j).second;
+ delegateForIndex(current)->paint(&painter, option, current);
}
- painter.end();
- if (r) *r = rect;
- return QPixmap::fromImage(image);
+ return pixmap;
}
void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h
index 2950bcd..557e98b 100644
--- a/src/gui/itemviews/qabstractitemview_p.h
+++ b/src/gui/itemviews/qabstractitemview_p.h
@@ -61,11 +61,10 @@
#include "QtGui/qmime.h"
#include "QtGui/qpainter.h"
#include "QtCore/qpair.h"
-#include "QtCore/qtimer.h"
-#include "QtCore/qtimeline.h"
#include "QtGui/qregion.h"
#include "QtCore/qdebug.h"
#include "QtGui/qpainter.h"
+#include "QtCore/qbasictimer.h"
#ifndef QT_NO_ITEMVIEWS
@@ -87,6 +86,9 @@ struct QEditorInfo
};
+typedef QPair<QRect, QModelIndex> QItemViewPaintPair;
+typedef QList<QItemViewPaintPair> QItemViewPaintPairs;
+
class QEmptyModel : public QAbstractItemModel
{
public:
@@ -177,7 +179,9 @@ public:
q_func()->style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, painter, q_func());
}
}
+
#endif
+ virtual QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const;
inline void releaseEditor(QWidget *editor) const {
if (editor) {
@@ -222,7 +226,7 @@ public:
void clearOrRemove();
void checkPersistentEditorFocus();
- QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r = 0) const;
+ QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r) const;
inline QPoint offset() const {
const Q_Q(QAbstractItemView);
@@ -376,7 +380,6 @@ public:
QBasicTimer updateTimer;
QBasicTimer delayedEditing;
QBasicTimer delayedAutoScroll; //used when an item is clicked
- QTimeLine timeline;
QAbstractItemView::ScrollMode verticalScrollMode;
QAbstractItemView::ScrollMode horizontalScrollMode;
diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp
index e4cb0f0..87825d9 100644
--- a/src/gui/itemviews/qitemselectionmodel.cpp
+++ b/src/gui/itemviews/qitemselectionmodel.cpp
@@ -270,24 +270,35 @@ QItemSelectionRange QItemSelectionRange::intersect(const QItemSelectionRange &ot
*/
-/*!
- Returns the list of model index items stored in the selection.
-*/
+/*
+ \internal
-QModelIndexList QItemSelectionRange::indexes() const
+ utility function for getting the indexes from a range
+ it avoid concatenating list and works on one
+ */
+
+static void indexesFromRange(const QItemSelectionRange &range, QModelIndexList &result)
{
- QModelIndex index;
- QModelIndexList result;
- if (isValid() && model()) {
- for (int column = left(); column <= right(); ++column) {
- for (int row = top(); row <= bottom(); ++row) {
- index = model()->index(row, column, parent());
- Qt::ItemFlags flags = model()->flags(index);
+ if (range.isValid() && range.model()) {
+ for (int column = range.left(); column <= range.right(); ++column) {
+ for (int row = range.top(); row <= range.bottom(); ++row) {
+ QModelIndex index = range.model()->index(row, column, range.parent());
+ Qt::ItemFlags flags = range.model()->flags(index);
if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
result.append(index);
}
}
}
+}
+
+/*!
+ Returns the list of model index items stored in the selection.
+*/
+
+QModelIndexList QItemSelectionRange::indexes() const
+{
+ QModelIndexList result;
+ indexesFromRange(*this, result);
return result;
}
@@ -404,7 +415,7 @@ QModelIndexList QItemSelection::indexes() const
QModelIndexList result;
QList<QItemSelectionRange>::const_iterator it = begin();
for (; it != end(); ++it)
- result += (*it).indexes();
+ indexesFromRange(*it, result);
return result;
}
diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp
index 4652b91..9a94b31 100644
--- a/src/gui/itemviews/qlistview.cpp
+++ b/src/gui/itemviews/qlistview.cpp
@@ -709,6 +709,32 @@ void QListViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
selectionModel->select(selection, command);
}
+/*!
+ \reimp
+
+ We have a QListView way of knowing what elements are on the viewport
+ through the intersectingSet function
+*/
+QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
+{
+ Q_ASSERT(r);
+ Q_Q(const QListView);
+ QRect &rect = *r;
+ const QRect viewportRect = viewport->rect();
+ QItemViewPaintPairs ret;
+ intersectingSet(viewportRect);
+ const QSet<QModelIndex> visibleIndexes = intersectingSet(viewportRect).toList().toSet();
+ for (int i = 0; i < indexes.count(); ++i) {
+ const QModelIndex &index = indexes.at(i);
+ if (visibleIndexes.contains(index)) {
+ const QRect current = q->visualRect(index);
+ ret += qMakePair(current, index);
+ rect |= current;
+ }
+ }
+ rect &= viewportRect;
+ return ret;
+}
/*!
\internal
@@ -925,9 +951,9 @@ void QListView::dragMoveEvent(QDragMoveEvent *e)
QModelIndex index;
if (d->movement == Snap) {
QRect rect(d->dynamicListView->snapToGrid(e->pos() + d->offset()), d->gridSize());
- d->intersectingSet(rect);
- index = d->intersectVector.count() > 0
- ? d->intersectVector.last() : QModelIndex();
+ const QVector<QModelIndex> intersectVector = d->intersectingSet(rect);
+ index = intersectVector.count() > 0
+ ? intersectVector.last() : QModelIndex();
} else {
index = indexAt(e->pos());
}
@@ -1100,10 +1126,8 @@ void QListView::paintEvent(QPaintEvent *e)
return;
QStyleOptionViewItemV4 option = d->viewOptionsV4();
QPainter painter(d->viewport);
- QRect area = e->rect();
- d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false);
- const QVector<QModelIndex> toBeRendered = d->intersectVector;
+ const QVector<QModelIndex> toBeRendered = d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false);
const QModelIndex current = currentIndex();
const QModelIndex hover = d->hover;
@@ -1225,9 +1249,9 @@ QModelIndex QListView::indexAt(const QPoint &p) const
{
Q_D(const QListView);
QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
- d->intersectingSet(rect);
- QModelIndex index = d->intersectVector.count() > 0
- ? d->intersectVector.last() : QModelIndex();
+ const QVector<QModelIndex> intersectVector = d->intersectingSet(rect);
+ QModelIndex index = intersectVector.count() > 0
+ ? intersectVector.last() : QModelIndex();
if (index.isValid() && visualRect(index).contains(p))
return index;
return QModelIndex();
@@ -1325,38 +1349,38 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie
if (d->gridSize().isValid()) rect.setSize(d->gridSize());
QSize contents = d->contentsSize();
- d->intersectVector.clear();
+ QVector<QModelIndex> intersectVector;
switch (cursorAction) {
case MoveLeft:
- while (d->intersectVector.isEmpty()) {
+ while (intersectVector.isEmpty()) {
rect.translate(-rect.width(), 0);
if (rect.right() <= 0)
return current;
if (rect.left() < 0)
rect.setLeft(0);
- d->intersectingSet(rect);
- d->removeCurrentAndDisabled(&d->intersectVector, current);
+ intersectVector = d->intersectingSet(rect);
+ d->removeCurrentAndDisabled(&intersectVector, current);
}
- return d->closestIndex(initialRect, d->intersectVector);
+ return d->closestIndex(initialRect, intersectVector);
case MoveRight:
- while (d->intersectVector.isEmpty()) {
+ while (intersectVector.isEmpty()) {
rect.translate(rect.width(), 0);
if (rect.left() >= contents.width())
return current;
if (rect.right() > contents.width())
rect.setRight(contents.width());
- d->intersectingSet(rect);
- d->removeCurrentAndDisabled(&d->intersectVector, current);
+ intersectVector = d->intersectingSet(rect);
+ d->removeCurrentAndDisabled(&intersectVector, current);
}
- return d->closestIndex(initialRect, d->intersectVector);
+ return d->closestIndex(initialRect, intersectVector);
case MovePageUp:
rect.moveTop(rect.top() - d->viewport->height());
if (rect.top() < rect.height())
rect.moveTop(rect.height());
case MovePrevious:
case MoveUp:
- while (d->intersectVector.isEmpty()) {
+ while (intersectVector.isEmpty()) {
rect.translate(0, -rect.height());
if (rect.bottom() <= 0) {
#ifdef QT_KEYPAD_NAVIGATION
@@ -1372,17 +1396,17 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie
}
if (rect.top() < 0)
rect.setTop(0);
- d->intersectingSet(rect);
- d->removeCurrentAndDisabled(&d->intersectVector, current);
+ intersectVector = d->intersectingSet(rect);
+ d->removeCurrentAndDisabled(&intersectVector, current);
}
- return d->closestIndex(initialRect, d->intersectVector);
+ return d->closestIndex(initialRect, intersectVector);
case MovePageDown:
rect.moveTop(rect.top() + d->viewport->height());
if (rect.bottom() > contents.height() - rect.height())
rect.moveBottom(contents.height() - rect.height());
case MoveNext:
case MoveDown:
- while (d->intersectVector.isEmpty()) {
+ while (intersectVector.isEmpty()) {
rect.translate(0, rect.height());
if (rect.top() >= contents.height()) {
#ifdef QT_KEYPAD_NAVIGATION
@@ -1399,10 +1423,10 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie
}
if (rect.bottom() > contents.height())
rect.setBottom(contents.height());
- d->intersectingSet(rect);
- d->removeCurrentAndDisabled(&d->intersectVector, current);
+ intersectVector = d->intersectingSet(rect);
+ d->removeCurrentAndDisabled(&intersectVector, current);
}
- return d->closestIndex(initialRect, d->intersectVector);
+ return d->closestIndex(initialRect, intersectVector);
case MoveHome:
return d->model->index(0, d->column, d->root);
case MoveEnd:
@@ -1477,10 +1501,10 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl
QItemSelection selection;
if (rect.width() == 1 && rect.height() == 1) {
- d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
+ const QVector<QModelIndex> intersectVector = d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
QModelIndex tl;
- if (!d->intersectVector.isEmpty())
- tl = d->intersectVector.last(); // special case for mouse press; only select the top item
+ if (!intersectVector.isEmpty())
+ tl = intersectVector.last(); // special case for mouse press; only select the top item
if (tl.isValid() && d->isIndexEnabled(tl))
selection.select(tl, tl);
} else {
@@ -1490,14 +1514,14 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl
QModelIndex tl, br;
// get the first item
const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1);
- d->intersectingSet(topLeft);
- if (!d->intersectVector.isEmpty())
- tl = d->intersectVector.last();
+ QVector<QModelIndex> intersectVector = d->intersectingSet(topLeft);
+ if (!intersectVector.isEmpty())
+ tl = intersectVector.last();
// get the last item
const QRect bottomRight(rect.right() + horizontalOffset(), rect.bottom() + verticalOffset(), 1, 1);
- d->intersectingSet(bottomRight);
- if (!d->intersectVector.isEmpty())
- br = d->intersectVector.last();
+ intersectVector = d->intersectingSet(bottomRight);
+ if (!intersectVector.isEmpty())
+ br = intersectVector.last();
// get the ranges
if (tl.isValid() && br.isValid()
@@ -1633,14 +1657,16 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con
QModelIndexList QListView::selectedIndexes() const
{
Q_D(const QListView);
- QModelIndexList viewSelected;
- QModelIndexList modelSelected;
- if (d->selectionModel)
- modelSelected = d->selectionModel->selectedIndexes();
- for (int i = 0; i < modelSelected.count(); ++i) {
- QModelIndex index = modelSelected.at(i);
+ if (!d->selectionModel)
+ return QModelIndexList();
+
+ QModelIndexList viewSelected = d->selectionModel->selectedIndexes();
+ for (int i = 0; i < viewSelected.count(); ++i) {
+ const QModelIndex &index = viewSelected.at(i);
if (!isIndexHidden(index) && index.parent() == d->root && index.column() == d->column)
- viewSelected.append(index);
+ ++i;
+ else
+ viewSelected.removeAt(i);
}
return viewSelected;
}
@@ -2116,8 +2142,8 @@ QItemSelection QListViewPrivate::selection(const QRect &rect) const
{
QItemSelection selection;
QModelIndex tl, br;
- intersectingSet(rect);
- QVector<QModelIndex>::iterator it = intersectVector.begin();
+ const QVector<QModelIndex> intersectVector = intersectingSet(rect);
+ QVector<QModelIndex>::const_iterator it = intersectVector.begin();
for (; it != intersectVector.end(); ++it) {
if (!tl.isValid() && !br.isValid()) {
tl = br = *it;
@@ -2408,9 +2434,9 @@ void QStaticListViewBase::doStaticLayout(const QListViewLayoutInfo &info)
Finds the set of items intersecting with \a area.
In this function, itemsize is counted from topleft to the start of the next item.
*/
-void QStaticListViewBase::intersectingStaticSet(const QRect &area) const
+QVector<QModelIndex> QStaticListViewBase::intersectingStaticSet(const QRect &area) const
{
- clearIntersections();
+ QVector<QModelIndex> ret;
int segStartPosition;
int segEndPosition;
int flowStartPosition;
@@ -2427,7 +2453,7 @@ void QStaticListViewBase::intersectingStaticSet(const QRect &area) const
flowEndPosition = area.bottom();
}
if (segmentPositions.count() < 2 || flowPositions.isEmpty())
- return;
+ return ret;
// the last segment position is actually the edge of the last segment
const int segLast = segmentPositions.count() - 2;
int seg = qBinarySearch<int>(segmentPositions, segStartPosition, 0, segLast + 1);
@@ -2442,13 +2468,14 @@ void QStaticListViewBase::intersectingStaticSet(const QRect &area) const
continue;
QModelIndex index = modelIndex(row);
if (index.isValid())
- appendToIntersections(index);
+ ret += index;
#if 0 // for debugging
else
qWarning("intersectingStaticSet: row %d was invalid", row);
#endif
}
}
+ return ret;
}
int QStaticListViewBase::itemIndex(const QListViewItem &item) const
@@ -2769,12 +2796,15 @@ void QDynamicListViewBase::doDynamicLayout(const QListViewLayoutInfo &info)
viewport()->update();
}
-void QDynamicListViewBase::intersectingDynamicSet(const QRect &area) const
+QVector<QModelIndex> QDynamicListViewBase::intersectingDynamicSet(const QRect &area) const
{
- clearIntersections();
- QListViewPrivate *that = const_cast<QListViewPrivate*>(dd);
+ QDynamicListViewBase *that = const_cast<QDynamicListViewBase*>(this);
QBspTree::Data data(static_cast<void*>(that));
- that->dynamicListView->tree.climbTree(area, &QDynamicListViewBase::addLeaf, data);
+ QVector<QModelIndex> res;
+ that->interSectingVector = &res;
+ that->tree.climbTree(area, &QDynamicListViewBase::addLeaf, data);
+ that->interSectingVector = 0;
+ return res;
}
void QDynamicListViewBase::createItems(int to)
@@ -2851,20 +2881,20 @@ int QDynamicListViewBase::itemIndex(const QListViewItem &item) const
}
void QDynamicListViewBase::addLeaf(QVector<int> &leaf, const QRect &area,
- uint visited, QBspTree::Data data)
+ uint visited, QBspTree::Data data)
{
QListViewItem *vi;
- QListViewPrivate *_this = static_cast<QListViewPrivate *>(data.ptr);
+ QDynamicListViewBase *_this = static_cast<QDynamicListViewBase *>(data.ptr);
for (int i = 0; i < leaf.count(); ++i) {
int idx = leaf.at(i);
- if (idx < 0 || idx >= _this->dynamicListView->items.count())
+ if (idx < 0 || idx >= _this->items.count())
continue;
- vi = &_this->dynamicListView->items[idx];
+ vi = &_this->items[idx];
Q_ASSERT(vi);
if (vi->isValid() && vi->rect().intersects(area) && vi->visited != visited) {
- QModelIndex index = _this->listViewItemToIndex(*vi);
+ QModelIndex index = _this->dd->listViewItemToIndex(*vi);
Q_ASSERT(index.isValid());
- _this->intersectVector.append(index);
+ _this->interSectingVector->append(index);
vi->visited = visited;
}
}
diff --git a/src/gui/itemviews/qlistview_p.h b/src/gui/itemviews/qlistview_p.h
index a7a7000..1727ba4 100644
--- a/src/gui/itemviews/qlistview_p.h
+++ b/src/gui/itemviews/qlistview_p.h
@@ -153,9 +153,6 @@ public:
inline bool isHidden(int row) const;
inline int hiddenCount() const;
- inline void clearIntersections() const;
- inline void appendToIntersections(const QModelIndex &idx) const;
-
inline bool isRightToLeft() const;
QListViewPrivate *dd;
@@ -186,7 +183,7 @@ public:
QPoint initStaticLayout(const QListViewLayoutInfo &info);
void doStaticLayout(const QListViewLayoutInfo &info);
- void intersectingStaticSet(const QRect &area) const;
+ QVector<QModelIndex> intersectingStaticSet(const QRect &area) const;
int itemIndex(const QListViewItem &item) const;
@@ -216,7 +213,7 @@ class QDynamicListViewBase : public QCommonListViewBase
friend class QListViewPrivate;
public:
QDynamicListViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d),
- batchStartRow(0), batchSavedDeltaSeg(0) {}
+ batchStartRow(0), batchSavedDeltaSeg(0), interSectingVector(0) {}
QBspTree tree;
QVector<QListViewItem> items;
@@ -230,6 +227,7 @@ public:
// used when laying out in batches
int batchStartRow;
int batchSavedDeltaSeg;
+ QVector<QModelIndex> *interSectingVector; //used from within intersectingDynamicSet
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max);
@@ -237,7 +235,7 @@ public:
void initBspTree(const QSize &contents);
QPoint initDynamicLayout(const QListViewLayoutInfo &info);
void doDynamicLayout(const QListViewLayoutInfo &info);
- void intersectingDynamicSet(const QRect &area) const;
+ QVector<QModelIndex> intersectingDynamicSet(const QRect &area) const;
static void addLeaf(QVector<int> &leaf, const QRect &area,
uint visited, QBspTree::Data data);
@@ -277,11 +275,11 @@ public:
bool doItemsLayout(int num);
- inline void intersectingSet(const QRect &area, bool doLayout = true) const {
+ inline QVector<QModelIndex> intersectingSet(const QRect &area, bool doLayout = true) const {
if (doLayout) executePostedLayout();
QRect a = (q_func()->isRightToLeft() ? flipX(area.normalized()) : area.normalized());
- if (viewMode == QListView::ListMode) staticListView->intersectingStaticSet(a);
- else dynamicListView->intersectingDynamicSet(a);
+ return (viewMode == QListView::ListMode) ? staticListView->intersectingStaticSet(a)
+ : dynamicListView->intersectingDynamicSet(a);
}
// ### FIXME:
@@ -351,6 +349,8 @@ public:
void scrollElasticBandBy(int dx, int dy);
+ QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const;
+
// ### FIXME: we only need one at a time
QDynamicListViewBase *dynamicListView;
QStaticListViewBase *staticListView;
@@ -383,9 +383,6 @@ public:
QRect layoutBounds;
- // used for intersecting set
- mutable QVector<QModelIndex> intersectVector;
-
// timers
QBasicTimer batchLayoutTimer;
@@ -438,9 +435,6 @@ inline QAbstractItemDelegate *QCommonListViewBase::delegate(const QModelIndex &i
inline bool QCommonListViewBase::isHidden(int row) const { return dd->isHidden(row); }
inline int QCommonListViewBase::hiddenCount() const { return dd->hiddenRows.count(); }
-inline void QCommonListViewBase::clearIntersections() const { dd->intersectVector.clear(); }
-inline void QCommonListViewBase::appendToIntersections(const QModelIndex &idx) const { dd->intersectVector.append(idx); }
-
inline bool QCommonListViewBase::isRightToLeft() const { return qq->isRightToLeft(); }
QT_END_NAMESPACE
diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp
index c676237..2009499 100644
--- a/src/gui/itemviews/qtableview.cpp
+++ b/src/gui/itemviews/qtableview.cpp
@@ -1528,6 +1528,8 @@ void QTableView::updateGeometries()
++columnsInViewport;
}
}
+ columnsInViewport = qMax(columnsInViewport, 1); //there must be always at least 1 column
+
if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
const int visibleColumns = columnCount - d->horizontalHeader->hiddenSectionCount();
horizontalScrollBar()->setRange(0, visibleColumns - columnsInViewport);
@@ -1554,6 +1556,8 @@ void QTableView::updateGeometries()
++rowsInViewport;
}
}
+ rowsInViewport = qMax(rowsInViewport, 1); //there must be always at least 1 row
+
if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
const int visibleRows = rowCount - d->verticalHeader->hiddenSectionCount();
verticalScrollBar()->setRange(0, visibleRows - rowsInViewport);
@@ -2036,7 +2040,7 @@ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint)
if (positionAtRight || hint == PositionAtCenter || positionAtLeft) {
int hiddenSections = 0;
if (d->horizontalHeader->sectionsHidden()) {
- for (int s = horizontalIndex; s >= 0; --s) {
+ for (int s = horizontalIndex - 1; s >= 0; --s) {
int column = d->horizontalHeader->logicalIndex(s);
if (d->horizontalHeader->isSectionHidden(column))
++hiddenSections;
@@ -2091,7 +2095,7 @@ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint)
if (hint == PositionAtBottom || hint == PositionAtCenter || hint == PositionAtTop) {
int hiddenSections = 0;
if (d->verticalHeader->sectionsHidden()) {
- for (int s = verticalIndex; s >= 0; --s) {
+ for (int s = verticalIndex - 1; s >= 0; --s) {
int row = d->verticalHeader->logicalIndex(s);
if (d->verticalHeader->isSectionHidden(row))
++hiddenSections;
diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp
index 7c319dc..f13ff0c 100644
--- a/src/gui/itemviews/qtreeview.cpp
+++ b/src/gui/itemviews/qtreeview.cpp
@@ -262,10 +262,6 @@ void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel)
Q_D(QTreeView);
Q_ASSERT(selectionModel);
if (d->selectionModel) {
- if (d->allColumnsShowFocus) {
- QObject::disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_currentChanged(QModelIndex,QModelIndex)));
- }
// support row editing
disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
d->model, SLOT(submit()));
@@ -275,10 +271,6 @@ void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel)
QAbstractItemView::setSelectionModel(selectionModel);
if (d->selectionModel) {
- if (d->allColumnsShowFocus) {
- QObject::connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_currentChanged(QModelIndex,QModelIndex)));
- }
// support row editing
connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
d->model, SLOT(submit()));
@@ -901,15 +893,6 @@ void QTreeView::setAllColumnsShowFocus(bool enable)
Q_D(QTreeView);
if (d->allColumnsShowFocus == enable)
return;
- if (d->selectionModel) {
- if (enable) {
- QObject::connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_currentChanged(QModelIndex,QModelIndex)));
- } else {
- QObject::disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_currentChanged(QModelIndex,QModelIndex)));
- }
- }
d->allColumnsShowFocus = enable;
d->viewport->update();
}
@@ -1267,10 +1250,13 @@ void QTreeView::paintEvent(QPaintEvent *event)
Q_D(QTreeView);
d->executePostedLayout();
QPainter painter(viewport());
+#ifndef QT_NO_ANIMATION
if (d->isAnimating()) {
- drawTree(&painter, event->region() - d->animationRect());
+ drawTree(&painter, event->region() - d->animatedOperation.rect());
d->drawAnimatedOperation(&painter);
- } else {
+ } else
+#endif //QT_NO_ANIMATION
+ {
drawTree(&painter, event->region());
#ifndef QT_NO_DRAGANDDROP
d->paintDropIndicator(&painter);
@@ -1306,13 +1292,13 @@ bool QTreeViewPrivate::expandOrCollapseItemAtPos(const QPoint &pos)
{
Q_Q(QTreeView);
// we want to handle mousePress in EditingState (persistent editors)
- if ((q->state() != QAbstractItemView::NoState
- && q->state() != QAbstractItemView::EditingState)
+ if ((state != QAbstractItemView::NoState
+ && state != QAbstractItemView::EditingState)
|| !viewport->rect().contains(pos))
return true;
int i = itemDecorationAt(pos);
- if ((i != -1) && q->itemsExpandable() && hasVisibleChildren(viewItems.at(i).index)) {
+ if ((i != -1) && itemsExpandable && hasVisibleChildren(viewItems.at(i).index)) {
if (viewItems.at(i).expanded)
collapse(i, true);
else
@@ -2851,10 +2837,9 @@ void QTreeViewPrivate::initialize()
header->setStretchLastSection(true);
header->setDefaultAlignment(Qt::AlignLeft|Qt::AlignVCenter);
q->setHeader(header);
-
- // animation
- QObject::connect(&timeline, SIGNAL(frameChanged(int)), q, SLOT(_q_animate()));
- QObject::connect(&timeline, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation()), Qt::QueuedConnection);
+#ifndef QT_NO_ANIMATION
+ QObject::connect(&animatedOperation, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation()));
+#endif //QT_NO_ANIMATION
}
void QTreeViewPrivate::expand(int item, bool emitSignal)
@@ -2864,10 +2849,11 @@ void QTreeViewPrivate::expand(int item, bool emitSignal)
if (item == -1 || viewItems.at(item).expanded)
return;
+#ifndef QT_NO_ANIMATION
if (emitSignal && animationsEnabled)
- prepareAnimatedOperation(item, AnimatedOperation::Expand);
-
- QAbstractItemView::State oldState = q->state();
+ prepareAnimatedOperation(item, QVariantAnimation::Forward);
+#endif //QT_NO_ANIMATION
+ QAbstractItemView::State oldState = state;
q->setState(QAbstractItemView::ExpandingState);
const QModelIndex index = viewItems.at(item).index;
storeExpanded(index);
@@ -2877,8 +2863,10 @@ void QTreeViewPrivate::expand(int item, bool emitSignal)
if (emitSignal) {
emit q->expanded(index);
+#ifndef QT_NO_ANIMATION
if (animationsEnabled)
beginAnimatedOperation();
+#endif //QT_NO_ANIMATION
}
if (model->canFetchMore(index))
model->fetchMore(index);
@@ -2902,10 +2890,12 @@ void QTreeViewPrivate::collapse(int item, bool emitSignal)
if (it == expandedIndexes.end() || viewItems.at(item).expanded == false)
return; // nothing to do
+#ifndef QT_NO_ANIMATION
if (emitSignal && animationsEnabled)
- prepareAnimatedOperation(item, AnimatedOperation::Collapse);
+ prepareAnimatedOperation(item, QVariantAnimation::Backward);
+#endif //QT_NO_ANIMATION
- QAbstractItemView::State oldState = q->state();
+ QAbstractItemView::State oldState = state;
q->setState(QAbstractItemView::CollapsingState);
expandedIndexes.erase(it);
viewItems[item].expanded = false;
@@ -2922,29 +2912,33 @@ void QTreeViewPrivate::collapse(int item, bool emitSignal)
if (emitSignal) {
emit q->collapsed(modelIndex);
+#ifndef QT_NO_ANIMATION
if (animationsEnabled)
beginAnimatedOperation();
+#endif //QT_NO_ANIMATION
}
}
-void QTreeViewPrivate::prepareAnimatedOperation(int item, AnimatedOperation::Type type)
+#ifndef QT_NO_ANIMATION
+void QTreeViewPrivate::prepareAnimatedOperation(int item, QVariantAnimation::Direction direction)
{
animatedOperation.item = item;
- animatedOperation.type = type;
+ animatedOperation.viewport = viewport;
+ animatedOperation.setDirection(direction);
int top = coordinateForItem(item) + itemHeight(item);
QRect rect = viewport->rect();
rect.setTop(top);
- if (type == AnimatedOperation::Collapse) {
+ if (direction == QVariantAnimation::Backward) {
const int limit = rect.height() * 2;
int h = 0;
int c = item + viewItems.at(item).total + 1;
for (int i = item + 1; i < c && h < limit; ++i)
h += itemHeight(i);
rect.setHeight(h);
- animatedOperation.duration = h;
+ animatedOperation.setEndValue(top + h);
}
- animatedOperation.top = top;
+ animatedOperation.setStartValue(top);
animatedOperation.before = renderTreeToPixmapForAnimation(rect);
}
@@ -2953,50 +2947,29 @@ void QTreeViewPrivate::beginAnimatedOperation()
Q_Q(QTreeView);
QRect rect = viewport->rect();
- rect.setTop(animatedOperation.top);
- if (animatedOperation.type == AnimatedOperation::Expand) {
+ rect.setTop(animatedOperation.top());
+ if (animatedOperation.direction() == QVariantAnimation::Forward) {
const int limit = rect.height() * 2;
int h = 0;
int c = animatedOperation.item + viewItems.at(animatedOperation.item).total + 1;
for (int i = animatedOperation.item + 1; i < c && h < limit; ++i)
h += itemHeight(i);
rect.setHeight(h);
- animatedOperation.duration = h;
+ animatedOperation.setEndValue(animatedOperation.top() + h);
}
animatedOperation.after = renderTreeToPixmapForAnimation(rect);
q->setState(QAbstractItemView::AnimatingState);
-
- timeline.stop();
- timeline.setDuration(250);
- timeline.setFrameRange(animatedOperation.top, animatedOperation.top + animatedOperation.duration);
- timeline.start();
-}
-
-void QTreeViewPrivate::_q_endAnimatedOperation()
-{
- Q_Q(QTreeView);
- animatedOperation.before = QPixmap();
- animatedOperation.after = QPixmap();
- q->setState(QAbstractItemView::NoState);
- q->updateGeometries();
- viewport->update();
-}
-
-void QTreeViewPrivate::_q_animate()
-{
- QRect rect = viewport->rect();
- rect.moveTop(animatedOperation.top);
- viewport->repaint(rect);
+ animatedOperation.start(); //let's start the animation
}
void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const
{
- int start = timeline.startFrame();
- int end = timeline.endFrame();
- bool collapsing = animatedOperation.type == AnimatedOperation::Collapse;
- int current = collapsing ? end - timeline.currentFrame() + start : timeline.currentFrame();
+ const int start = animatedOperation.startValue().toInt(),
+ end = animatedOperation.endValue().toInt(),
+ current = animatedOperation.currentValue().toInt();
+ bool collapsing = animatedOperation.direction() == QVariantAnimation::Backward;
const QPixmap top = collapsing ? animatedOperation.before : animatedOperation.after;
painter->drawPixmap(0, start, top, 0, end - current - 1, top.width(), top.height());
const QPixmap bottom = collapsing ? animatedOperation.after : animatedOperation.before;
@@ -3039,26 +3012,14 @@ QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) cons
return pixmap;
}
-void QTreeViewPrivate::_q_currentChanged(const QModelIndex &current, const QModelIndex &previous)
+void QTreeViewPrivate::_q_endAnimatedOperation()
{
Q_Q(QTreeView);
- if (previous.isValid()) {
- QRect previousRect = q->visualRect(previous);
- if (allColumnsShowFocus) {
- previousRect.setX(0);
- previousRect.setWidth(viewport->width());
- }
- viewport->update(previousRect);
- }
- if (current.isValid()) {
- QRect currentRect = q->visualRect(current);
- if (allColumnsShowFocus) {
- currentRect.setX(0);
- currentRect.setWidth(viewport->width());
- }
- viewport->update(currentRect);
- }
+ q->setState(QAbstractItemView::NoState);
+ q->updateGeometries();
+ viewport->update();
}
+#endif //QT_NO_ANIMATION
void QTreeViewPrivate::_q_modelAboutToBeReset()
{
@@ -3787,6 +3748,21 @@ void QTreeView::currentChanged(const QModelIndex &current, const QModelIndex &pr
}
#endif
QAbstractItemView::currentChanged(current, previous);
+
+ if (allColumnsShowFocus()) {
+ if (previous.isValid()) {
+ QRect previousRect = visualRect(previous);
+ previousRect.setX(0);
+ previousRect.setWidth(viewport()->width());
+ viewport()->update(previousRect);
+ }
+ if (current.isValid()) {
+ QRect currentRect = visualRect(current);
+ currentRect.setX(0);
+ currentRect.setWidth(viewport()->width());
+ viewport()->update(currentRect);
+ }
+ }
}
/*!
diff --git a/src/gui/itemviews/qtreeview.h b/src/gui/itemviews/qtreeview.h
index 0347645..4411781 100644
--- a/src/gui/itemviews/qtreeview.h
+++ b/src/gui/itemviews/qtreeview.h
@@ -223,12 +223,11 @@ private:
Q_DECLARE_PRIVATE(QTreeView)
Q_DISABLE_COPY(QTreeView)
+#ifndef QT_NO_ANIMATION
Q_PRIVATE_SLOT(d_func(), void _q_endAnimatedOperation())
- Q_PRIVATE_SLOT(d_func(), void _q_animate())
- Q_PRIVATE_SLOT(d_func(), void _q_currentChanged(const QModelIndex&, const QModelIndex &))
+#endif //QT_NO_ANIMATION
Q_PRIVATE_SLOT(d_func(), void _q_modelAboutToBeReset())
Q_PRIVATE_SLOT(d_func(), void _q_sortIndicatorChanged(int column, Qt::SortOrder order))
- Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed())
};
#endif // QT_NO_TREEVIEW
diff --git a/src/gui/itemviews/qtreeview_p.h b/src/gui/itemviews/qtreeview_p.h
index 6a1dfe5..6fb2e41 100644
--- a/src/gui/itemviews/qtreeview_p.h
+++ b/src/gui/itemviews/qtreeview_p.h
@@ -54,6 +54,7 @@
//
#include "private/qabstractitemview_p.h"
+#include <QtCore/qvariantanimation.h>
#ifndef QT_NO_TREEVIEW
@@ -81,42 +82,39 @@ public:
uniformRowHeights(false), rootDecoration(true),
itemsExpandable(true), sortingEnabled(false),
expandsOnDoubleClick(true),
- allColumnsShowFocus(false),
+ allColumnsShowFocus(false), current(0),
animationsEnabled(false), columnResizeTimerID(0),
autoExpandDelay(-1), hoverBranch(-1), geometryRecursionBlock(false) {}
~QTreeViewPrivate() {}
void initialize();
- struct AnimatedOperation
+#ifndef QT_NO_ANIMATION
+ struct AnimatedOperation : public QVariantAnimation
{
- enum Type { Expand, Collapse };
int item;
- int top;
- int duration;
- Type type;
QPixmap before;
QPixmap after;
- };
-
- void expand(int item, bool emitSignal);
- void collapse(int item, bool emitSignal);
-
- void prepareAnimatedOperation(int item, AnimatedOperation::Type type);
+ QWidget *viewport;
+ AnimatedOperation() : item(0) { setEasingCurve(QEasingCurve::InOutQuad); }
+ int top() const { return startValue().toInt(); }
+ QRect rect() const { QRect rect = viewport->rect(); rect.moveTop(top()); return rect; }
+ void updateCurrentValue(const QVariant &) { viewport->update(rect()); }
+ void updateState(State, State state) { if (state == Stopped) before = after = QPixmap(); }
+ } animatedOperation;
+ void prepareAnimatedOperation(int item, QVariantAnimation::Direction d);
void beginAnimatedOperation();
- void _q_endAnimatedOperation();
void drawAnimatedOperation(QPainter *painter) const;
QPixmap renderTreeToPixmapForAnimation(const QRect &rect) const;
+ void _q_endAnimatedOperation();
+#endif //QT_NO_ANIMATION
- inline QRect animationRect() const
- { return QRect(0, animatedOperation.top, viewport->width(),
- viewport->height() - animatedOperation.top); }
+ void expand(int item, bool emitSignal);
+ void collapse(int item, bool emitSignal);
- void _q_currentChanged(const QModelIndex&, const QModelIndex&);
void _q_columnsAboutToBeRemoved(const QModelIndex &, int, int);
void _q_columnsRemoved(const QModelIndex &, int, int);
void _q_modelAboutToBeReset();
- void _q_animate();
void _q_sortIndicatorChanged(int column, Qt::SortOrder order);
void _q_modelDestroyed();
@@ -177,8 +175,6 @@ public:
// used when expanding and collapsing items
QSet<QPersistentModelIndex> expandedIndexes;
- QStack<bool> expandParent;
- AnimatedOperation animatedOperation;
bool animationsEnabled;
inline bool storeExpanded(const QPersistentModelIndex &idx) {
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 839e465..b168188 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -126,7 +126,7 @@ int QApplicationPrivate::app_compile_version = 0x040000; //we don't know exactly
QApplication::Type qt_appType=QApplication::Tty;
QApplicationPrivate *QApplicationPrivate::self = 0;
-QInputContext *QApplicationPrivate::inputContext;
+QInputContext *QApplicationPrivate::inputContext = 0;
bool QApplicationPrivate::quitOnLastWindowClosed = true;
@@ -3716,6 +3716,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
Qt::MouseFocusReason);
}
+ // ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms
+ // like Mac OS X (probably others too), can optimize their views by not
+ // dispatching mouse move events. We have attributes to control hover,
+ // and mouse tracking, but as long as we are deciding to implement this
+ // feature without choice of opting-in or out, you ALWAYS have to have
+ // tracking enabled. Therefore, the other properties give a false sense of
+ // performance enhancement.
if (e->type() == QEvent::MouseMove && mouse->buttons() == 0) {
d->toolTipWidget = w;
d->toolTipPos = relpos;
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 0884976..beccfb0 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -1316,8 +1316,13 @@ void QApplication::setOverrideCursor(const QCursor &cursor)
{
qApp->d_func()->cursor_list.prepend(cursor);
+#ifdef QT_MAC_USE_COCOA
+ QMacCocoaAutoReleasePool pool;
+ [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push];
+#else
if (qApp && qApp->activeWindow())
qt_mac_set_cursor(&qApp->d_func()->cursor_list.first(), QCursor::pos());
+#endif
}
void QApplication::restoreOverrideCursor()
@@ -1326,12 +1331,17 @@ void QApplication::restoreOverrideCursor()
return;
qApp->d_func()->cursor_list.removeFirst();
+#ifdef QT_MAC_USE_COCOA
+ QMacCocoaAutoReleasePool pool;
+ [NSCursor pop];
+#else
if (qApp && qApp->activeWindow()) {
const QCursor def(Qt::ArrowCursor);
qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first(), QCursor::pos());
}
-}
#endif
+}
+#endif // QT_NO_CURSOR
QWidget *QApplication::topLevelAt(const QPoint &p)
{
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index db77b07..90eaba0 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -158,17 +158,19 @@ inline QPointF QTabletDeviceData::scaleCoord(int coordX, int coordY,
int outOriginY, int outExtentY) const
{
QPointF ret;
+
if (sign(outExtentX) == sign(maxX))
- ret.setX(((coordX - minX) * qAbs(outExtentX) / qAbs(qreal(maxX))) + outOriginX);
+ ret.setX(((coordX - minX) * qAbs(outExtentX) / qAbs(qreal(maxX - minX))) + outOriginX);
else
- ret.setX(((qAbs(maxX) - (coordX - minX)) * qAbs(outExtentX) / qAbs(qreal(maxX)))
+ ret.setX(((qAbs(maxX) - (coordX - minX)) * qAbs(outExtentX) / qAbs(qreal(maxX - minX)))
+ outOriginX);
if (sign(outExtentY) == sign(maxY))
- ret.setY(((coordY - minY) * qAbs(outExtentY) / qAbs(qreal(maxY))) + outOriginY);
+ ret.setY(((coordY - minY) * qAbs(outExtentY) / qAbs(qreal(maxY - minY))) + outOriginY);
else
- ret.setY(((qAbs(maxY) - (coordY - minY)) * qAbs(outExtentY) / qAbs(qreal(maxY)))
+ ret.setY(((qAbs(maxY) - (coordY - minY)) * qAbs(outExtentY) / qAbs(qreal(maxY - minY)))
+ outOriginY);
+
return ret;
}
#endif
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index e0eda82..e0c62b7 100644
--- a/src/gui/kernel/qapplication_win.cpp
+++ b/src/gui/kernel/qapplication_win.cpp
@@ -2956,7 +2956,9 @@ bool QETWidget::translateMouseEvent(const MSG &msg)
if (alienWidget && alienWidget->internalWinId())
alienWidget = 0;
- if (type == QEvent::MouseMove || type == QEvent::NonClientAreaMouseMove) {
+ if (type == QEvent::MouseMove || type == QEvent::NonClientAreaMouseMove
+ || type == QEvent::TabletMove) {
+
if (!(state & Qt::MouseButtonMask))
qt_button_down = 0;
#ifndef QT_NO_CURSOR
@@ -3087,6 +3089,8 @@ bool QETWidget::translateMouseEvent(const MSG &msg)
popupButtonFocus = popupChild;
break;
case QEvent::MouseButtonRelease:
+ case QEvent::TabletRelease:
+
releaseAfter = true;
break;
default:
@@ -3324,17 +3328,19 @@ static void tabletInit(UINT wActiveCsr, HCTX hTab)
tdd.minTanPressure = int(np.axMin);
tdd.maxTanPressure = int(np.axMax);
- ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_X, &np);
- tdd.minX = int(np.axMin);
- tdd.maxX = int(np.axMax);
+ LOGCONTEXT lcMine;
+
+ /* get default region */
+ ptrWTInfo(WTI_DEFCONTEXT, 0, &lcMine);
+
+ tdd.minX = 0;
+ tdd.maxX = int(lcMine.lcInExtX) - int(lcMine.lcInOrgX);
- ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_Y, &np);
- tdd.minY = int(np.axMin);
- tdd.maxY = int(np.axMax);
+ tdd.minY = 0;
+ tdd.maxY = int(lcMine.lcInExtY) - int(lcMine.lcInOrgY);
- ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_Z, &np);
- tdd.minZ = int(np.axMin);
- tdd.maxZ = int(np.axMax);
+ tdd.minZ = 0;
+ tdd.maxZ = int(lcMine.lcInExtZ) - int(lcMine.lcInOrgZ);
int csr_type,
csr_physid;
@@ -3444,13 +3450,34 @@ bool QETWidget::translateTabletEvent(const MSG &msg, PACKET *localPacketBuf,
}
QPoint globalPos(qRound(hiResGlobal.x()), qRound(hiResGlobal.y()));
+ if (t == QEvent::TabletPress)
+ {
+ qt_button_down = QApplication::widgetAt(globalPos);
+ }
+
// make sure the tablet event get's sent to the proper widget...
- QWidget *w = QApplication::widgetAt(globalPos);
+ QWidget *w = 0;
+
if (qt_button_down)
w = qt_button_down; // Pass it to the thing that's grabbed it.
+ else
+ w = QApplication::widgetAt(globalPos);
if (!w)
w = this;
+
+ if (t == QEvent::TabletRelease)
+ {
+ if (qt_win_ignoreNextMouseReleaseEvent) {
+ qt_win_ignoreNextMouseReleaseEvent = false;
+ if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) {
+ releaseAutoCapture();
+ qt_button_down = 0;
+ }
+ }
+
+ }
+
QPoint localPos = w->mapFromGlobal(globalPos);
#ifndef QT_NO_TABLETEVENT
if (currentTabletPointer.currentDevice == QTabletEvent::Airbrush) {
diff --git a/src/gui/kernel/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm
index bdc7ecb..1e0bbdf 100644
--- a/src/gui/kernel/qcocoapanel_mac.mm
+++ b/src/gui/kernel/qcocoapanel_mac.mm
@@ -85,6 +85,12 @@ QT_USE_NAMESPACE
last resort (i.e., this is code that can potentially be removed).
*/
+- (void)toggleToolbarShown:(id)sender
+{
+ macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]);
+ [super toggleToolbarShown:sender];
+}
+
- (void)keyDown:(NSEvent *)theEvent
{
bool keyOK = qt_dispatchKeyEvent(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]);
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index 64cdae6..52685ca 100644
--- a/src/gui/kernel/qcocoaview_mac.mm
+++ b/src/gui/kernel/qcocoaview_mac.mm
@@ -290,11 +290,18 @@ extern "C" {
{
if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
return NSDragOperationNone;
+ NSPoint windowPoint = [sender draggingLocation];
+ if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ // pass the drag enter event to the view underneath.
+ NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
+ if (candidateView && candidateView != self)
+ return [candidateView draggingEntered:sender];
+ }
+ dragEnterSequence = [sender draggingSequenceNumber];
[self addDropData:sender];
QMimeData *mimeData = dropData;
if (QDragManager::self()->source())
mimeData = QDragManager::self()->dragPrivate()->data;
- NSPoint windowPoint = [sender draggingLocation];
NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
QPoint posDrag(localPoint.x, localPoint.y);
@@ -318,6 +325,9 @@ extern "C" {
[self removeDropData];
return NSDragOperationNone;
} else {
+ // save the mouse position, used by draggingExited handler.
+ DnDParams *dndParams = [QCocoaView currentMouseEvent];
+ dndParams->activeDragEnterPos = windowPoint;
// send a drag move event immediately after a drag enter event (as per documentation).
QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
qDMEvent.setDropAction(qDEEvent.dropAction());
@@ -338,11 +348,22 @@ extern "C" {
- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
{
- // drag enter event was rejected, so ignore the move event.
+ NSPoint windowPoint = [sender draggingLocation];
+ if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ // pass the drag move event to the view underneath.
+ NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
+ if (candidateView && candidateView != self)
+ return [candidateView draggingUpdated:sender];
+ }
+ // in cases like QFocusFrame, the view under the mouse might
+ // not have received the drag enter. Generate a synthetic
+ // drag enter event for that view.
+ if (dragEnterSequence != [sender draggingSequenceNumber])
+ [self draggingEntered:sender];
+ // drag enter event was rejected, so ignore the move event.
if (dropData == 0)
return NSDragOperationNone;
// return last value, if we are still in the answerRect.
- NSPoint windowPoint = [sender draggingLocation];
NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
NSDragOperation nsActions = [sender draggingSourceOperationMask];
@@ -381,21 +402,34 @@ extern "C" {
- (void)draggingExited:(id < NSDraggingInfo >)sender
{
- Q_UNUSED(sender)
- // drag enter event was rejected, so ignore the move event.
+ dragEnterSequence = -1;
+ if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ // try sending the leave event to the last view which accepted drag enter.
+ DnDParams *dndParams = [QCocoaView currentMouseEvent];
+ NSView *candidateView = [[[self window] contentView] hitTest:dndParams->activeDragEnterPos];
+ if (candidateView && candidateView != self)
+ return [candidateView draggingExited:sender];
+ }
+ // drag enter event was rejected, so ignore the move event.
if (dropData) {
QDragLeaveEvent de;
QApplication::sendEvent(qwidget, &de);
[self removeDropData];
}
-
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
+ NSPoint windowPoint = [sender draggingLocation];
+ dragEnterSequence = -1;
+ if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
+ // pass the drop event to the view underneath.
+ NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
+ if (candidateView && candidateView != self)
+ return [candidateView performDragOperation:sender];
+ }
[self addDropData:sender];
- NSPoint windowPoint = [sender draggingLocation];
NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
QPoint posDrop(localPoint.x, localPoint.y);
@@ -574,11 +608,15 @@ extern "C" {
[self removeTrackingArea:t];
}
}
+
+ // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should
+ // only be turned on if mouseTracking, hover is on or a tool tip is set.
+ // Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to
+ // turn it on in ALL case. That means EVERY QCocoaView gets to pay the cost of
+ // mouse moves delivered to it (Apple recommends keeping it OFF because there
+ // is a performance hit). So it goes.
NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
- | NSTrackingInVisibleRect;
- if (qwidget->hasMouseTracking() || !qwidgetprivate->toolTip.isEmpty()
- || qwidget->testAttribute(Qt::WA_Hover))
- trackingOptions |= NSTrackingMouseMoved;
+ | NSTrackingInVisibleRect | NSTrackingMouseMoved;
NSTrackingArea *ta = [[NSTrackingArea alloc] initWithRect:NSMakeRect(0, 0,
qwidget->width(),
qwidget->height())
@@ -643,62 +681,6 @@ extern "C" {
qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
}
-- (NSView *)viewUnderTransparentForMouseView:(NSView *)mouseView widget:(QWidget *)widgetToGetMouse
- withWindowPoint:(NSPoint)windowPoint
-{
- NSMutableArray *viewsToLookAt = [NSMutableArray arrayWithCapacity:5];
- [viewsToLookAt addObject:mouseView];
- QWidget *parentWidget = widgetToGetMouse->parentWidget();
- while (parentWidget) {
- [viewsToLookAt addObject:qt_mac_nativeview_for(parentWidget)];
- parentWidget = parentWidget->parentWidget();
- }
-
- // Now walk through the subviews of each view and determine which subview should
- // get the event. We look through all the subviews at a given level with
- // the assumption that the last item to be found the candidate has a higher z-order.
- // Unfortunately, fast enumeration doesn't go backwards in 10.5, so assume go fast
- // forward is quicker than the slow normal way backwards.
- NSView *candidateView = nil;
- for (NSView *lookView in viewsToLookAt) {
- NSPoint tmpPoint = [lookView convertPoint:windowPoint fromView:nil];
- for (NSView *view in [lookView subviews]) {
- if (view == mouseView || [view isHidden])
- continue;
- NSRect frameRect = [view frame];
- if (NSMouseInRect(tmpPoint, [view frame], [view isFlipped]))
- candidateView = view;
- }
- if (candidateView)
- break;
- }
-
-
- if (candidateView != nil) {
- // Now that we've got a candidate, we have to dig into it's tree and see where it is.
- NSView *lowerView = nil;
- NSView *viewForDescent = candidateView;
- while (viewForDescent) {
- NSPoint tmpPoint = [viewForDescent convertPoint:windowPoint fromView:nil];
- // Apply same rule as above wrt z-order.
- for (NSView *view in [viewForDescent subviews]) {
- if (![view isHidden] && NSMouseInRect(tmpPoint, [view frame], [view isFlipped]))
- lowerView = view;
- }
- if (!lowerView) // Low as we can be at this point.
- candidateView = viewForDescent;
-
- // Try to go deeper, will also exit out of the loop, if we found the point.
- viewForDescent = lowerView;
- lowerView = nil;
- }
- }
- // I am transparent, so I can't be a candidate.
- if (candidateView == mouseView)
- candidateView = nil;
- return candidateView;
-}
-
- (void)mouseDown:(NSEvent *)theEvent
{
qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::LeftButton);
diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h
index 6583139..4762b17 100644
--- a/src/gui/kernel/qcocoaview_mac_p.h
+++ b/src/gui/kernel/qcocoaview_mac_p.h
@@ -68,6 +68,7 @@ struct DnDParams
NSEvent *theEvent;
NSPoint localPoint;
NSDragOperation performedAction;
+ NSPoint activeDragEnterPos;
};
QT_END_NAMESPACE
@@ -86,6 +87,7 @@ Q_GUI_EXPORT
bool sendKeyEvents;
QString *composingText;
QStringList *currentCustomTypes;
+ NSInteger dragEnterSequence;
}
- (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;
- (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;
@@ -104,8 +106,6 @@ Q_GUI_EXPORT
- (QWidget *)qt_qwidget;
- (BOOL)qt_leftButtonIsRightButton;
- (void)qt_setLeftButtonIsRightButton:(BOOL)isSwapped;
-- (NSView *)viewUnderTransparentForMouseView:(NSView *)mouseView widget:(QWidget *)widgetToGetMouse
- withWindowPoint:(NSPoint)windowPoint;
+ (DnDParams*)currentMouseEvent;
@end
diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm
index 7084416..eb08982 100644
--- a/src/gui/kernel/qcocoawindow_mac.mm
+++ b/src/gui/kernel/qcocoawindow_mac.mm
@@ -104,6 +104,12 @@ QT_USE_NAMESPACE
last resort (i.e., this is code that can potentially be removed).
*/
+- (void)toggleToolbarShown:(id)sender
+{
+ macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]);
+ [super toggleToolbarShown:sender];
+}
+
- (void)keyDown:(NSEvent *)theEvent
{
bool keyOK = qt_dispatchKeyEvent(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]);
diff --git a/src/gui/kernel/qmultitouch_mac.mm b/src/gui/kernel/qmultitouch_mac.mm
index 3fe85a9..3d2eae6 100644
--- a/src/gui/kernel/qmultitouch_mac.mm
+++ b/src/gui/kernel/qmultitouch_mac.mm
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
#ifdef QT_MAC_USE_COCOA
-QHash<int, QCocoaTouch*> QCocoaTouch::_currentTouches;
+QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
QPointF QCocoaTouch::_screenReferencePos;
QPointF QCocoaTouch::_trackpadReferencePos;
int QCocoaTouch::_idAssignmentCount = 0;
@@ -62,7 +62,7 @@ QCocoaTouch::QCocoaTouch(NSTouch *nstouch)
_touchPoint.setId(_idAssignmentCount++);
_touchPoint.setPressure(1.0);
- _identity = int([nstouch identity]);
+ _identity = qint64([nstouch identity]);
_currentTouches.insert(_identity, this);
updateTouchData(nstouch, NSTouchPhaseBegan);
}
@@ -100,7 +100,7 @@ void QCocoaTouch::updateTouchData(NSTouch *nstouch, NSTouchPhase phase)
QCocoaTouch *QCocoaTouch::findQCocoaTouch(NSTouch *nstouch)
{
- int identity = int([nstouch identity]);
+ qint64 identity = qint64([nstouch identity]);
if (_currentTouches.contains(identity))
return _currentTouches.value(identity);
return 0;
diff --git a/src/gui/kernel/qmultitouch_mac_p.h b/src/gui/kernel/qmultitouch_mac_p.h
index 3fa8f6c..618e9ca 100644
--- a/src/gui/kernel/qmultitouch_mac_p.h
+++ b/src/gui/kernel/qmultitouch_mac_p.h
@@ -74,7 +74,7 @@ class QCocoaTouch
static void setMouseInDraggingState(bool inDraggingState);
private:
- static QHash<int, QCocoaTouch*> _currentTouches;
+ static QHash<qint64, QCocoaTouch*> _currentTouches;
static QPointF _screenReferencePos;
static QPointF _trackpadReferencePos;
static int _idAssignmentCount;
@@ -82,7 +82,7 @@ class QCocoaTouch
static bool _updateInternalStateOnly;
QTouchEvent::TouchPoint _touchPoint;
- int _identity;
+ qint64 _identity;
QCocoaTouch(NSTouch *nstouch);
~QCocoaTouch();
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm
index 13b0e50..a98a7f8 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac.mm
+++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm
@@ -177,11 +177,10 @@ void macWindowToolbarShow(const QWidget *widget, bool show )
{
OSWindowRef wnd = qt_mac_window_for(widget);
#if QT_MAC_USE_COCOA
- NSToolbar *toolbar = [wnd toolbar];
- if (toolbar) {
+ if (NSToolbar *toolbar = [wnd toolbar]) {
QMacCocoaAutoReleasePool pool;
if (show != [toolbar isVisible]) {
- [wnd toggleToolbarShown:wnd];
+ [toolbar setVisible:show];
} else {
// The toolbar may be in sync, but we are not, update our framestrut.
qt_widget_private(const_cast<QWidget *>(widget))->updateFrameStrut();
@@ -197,22 +196,21 @@ void macWindowToolbarSet( void * /*OSWindowRef*/ window, void *toolbarRef )
{
OSWindowRef wnd = static_cast<OSWindowRef>(window);
#if QT_MAC_USE_COCOA
- [wnd setToolbar:static_cast<NSToolbar *>(toolbarRef)];
+ [wnd setToolbar:static_cast<NSToolbar *>(toolbarRef)];
#else
SetWindowToolbar(wnd, static_cast<HIToolbarRef>(toolbarRef));
#endif
}
-bool macWindowToolbarVisible( void * /*OSWindowRef*/ window )
+bool macWindowToolbarIsVisible( void * /*OSWindowRef*/ window )
{
OSWindowRef wnd = static_cast<OSWindowRef>(window);
#if QT_MAC_USE_COCOA
- NSToolbar *toolbar = [wnd toolbar];
- if (toolbar)
+ if (NSToolbar *toolbar = [wnd toolbar])
return [toolbar isVisible];
return false;
#else
- return IsWindowToolbarVisible(wnd);
+ return IsWindowToolbarVisible(wnd);
#endif
}
@@ -220,12 +218,12 @@ void macWindowSetHasShadow( void * /*OSWindowRef*/ window, bool hasShadow )
{
OSWindowRef wnd = static_cast<OSWindowRef>(window);
#if QT_MAC_USE_COCOA
- [wnd setHasShadow:BOOL(hasShadow)];
+ [wnd setHasShadow:BOOL(hasShadow)];
#else
- if (hasShadow)
- ChangeWindowAttributes(wnd, 0, kWindowNoShadowAttribute);
- else
- ChangeWindowAttributes(wnd, kWindowNoShadowAttribute, 0);
+ if (hasShadow)
+ ChangeWindowAttributes(wnd, 0, kWindowNoShadowAttribute);
+ else
+ ChangeWindowAttributes(wnd, kWindowNoShadowAttribute, 0);
#endif
}
@@ -233,9 +231,9 @@ void macWindowFlush(void * /*OSWindowRef*/ window)
{
OSWindowRef wnd = static_cast<OSWindowRef>(window);
#if QT_MAC_USE_COCOA
- [wnd flushWindowIfNeeded];
+ [wnd flushWindowIfNeeded];
#else
- HIWindowFlush(wnd);
+ HIWindowFlush(wnd);
#endif
}
@@ -352,6 +350,12 @@ Qt::MouseButton qt_mac_get_button(EventMouseButton button)
return Qt::NoButton;
}
+void macSendToolbarChangeEvent(QWidget *widget)
+{
+ QToolBarChangeEvent ev(!(GetCurrentKeyModifiers() & cmdKey));
+ qt_sendSpontaneousEvent(widget, &ev);
+}
+
Q_GLOBAL_STATIC(QMacTabletHash, tablet_hash)
QMacTabletHash *qt_mac_tablet_hash()
{
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
index 3881ccd..5f6204f 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h
+++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
@@ -118,9 +118,10 @@ void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds = 0);
bool macWindowIsTextured(void * /*OSWindowRef*/ window);
void macWindowToolbarShow(const QWidget *widget, bool show );
void macWindowToolbarSet( void * /*OSWindowRef*/ window, void* toolbarRef );
-bool macWindowToolbarVisible( void * /*OSWindowRef*/ window );
+bool macWindowToolbarIsVisible( void * /*OSWindowRef*/ window );
void macWindowSetHasShadow( void * /*OSWindowRef*/ window, bool hasShadow );
void macWindowFlush(void * /*OSWindowRef*/ window);
+void macSendToolbarChangeEvent(QWidget *widget);
struct HIContentBorderMetrics;
void qt_mac_updateContentBorderMetricts(void * /*OSWindowRef */window, const ::HIContentBorderMetrics &metrics);
void * /*NSImage */qt_mac_create_nsimage(const QPixmap &pm);
diff --git a/src/gui/kernel/qt_mac.cpp b/src/gui/kernel/qt_mac.cpp
index 27df5d1..0c3b707 100644
--- a/src/gui/kernel/qt_mac.cpp
+++ b/src/gui/kernel/qt_mac.cpp
@@ -134,7 +134,7 @@ QColor qcolorForThemeTextColor(ThemeTextColor themeColor)
#ifdef Q_OS_MAC32
RGBColor c;
GetThemeTextColor(themeColor, 32, true, &c);
- QColor color = QColor(c.red / 265, c.green / 256, c.blue / 256);
+ QColor color = QColor(c.red / 256, c.green / 256, c.blue / 256);
return color;
#else
// There is no equivalent to GetThemeTextColor in 64-bit and it was rather bad that
@@ -156,13 +156,13 @@ QColor qcolorForThemeTextColor(ThemeTextColor themeColor)
case kThemeTextColorAlertInactive:
case kThemeTextColorDialogInactive:
case kThemeTextColorPlacardInactive:
- return QColor(67, 69, 69, 255);
+ return QColor(69, 69, 69, 255);
case kThemeTextColorPopupButtonInactive:
case kThemeTextColorPopupLabelInactive:
case kThemeTextColorPushButtonInactive:
case kThemeTextColorTabFrontInactive:
case kThemeTextColorBevelButtonInactive:
- return QColor(123, 127, 127, 255);
+ return QColor(127, 127, 127, 255);
default: {
QNativeImage nativeImage(16,16, QNativeImage::systemFormat());
CGRect cgrect = CGRectMake(0, 0, 16, 16);
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index d1ab45a..c21ebda 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -4541,6 +4541,11 @@ void QWidget::unsetLayoutDirection()
By default, this property contains a cursor with the Qt::ArrowCursor
shape.
+ Some underlying window implementations will reset the cursor if it
+ leaves a widget even if the mouse is grabbed. If you want to have
+ a cursor set for all widgets, even when outside the window, consider
+ QApplication::setOverrideCursor().
+
\sa QApplication::setOverrideCursor()
*/
@@ -9894,11 +9899,8 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
break;
case Qt::WA_InputMethodEnabled: {
QInputContext *ic = d->ic;
- if (!ic) {
- // implicitly create input context only if we have a focus
- if (hasFocus())
- ic = d->inputContext();
- }
+ if (!ic && (!on || hasFocus()))
+ ic = d->inputContext();
if (ic) {
if (on && hasFocus() && ic->focusWidget() != this && isEnabled()) {
ic->setFocusWidget(this);
diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm
index ad16485..5e2dfb6 100644
--- a/src/gui/kernel/qwidget_mac.mm
+++ b/src/gui/kernel/qwidget_mac.mm
@@ -843,8 +843,7 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event,
extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
qt_button_down = 0;
} else if(ekind == kEventWindowToolbarSwitchMode) {
- QToolBarChangeEvent ev(!(GetCurrentKeyModifiers() & cmdKey));
- QApplication::sendSpontaneousEvent(widget, &ev);
+ macSendToolbarChangeEvent(widget);
HIToolbarRef toolbar;
if (GetWindowToolbar(wid, &toolbar) == noErr) {
if (toolbar) {
@@ -1521,12 +1520,16 @@ void QWidgetPrivate::toggleDrawers(bool visible)
*****************************************************************************/
bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
{
+ // I'm not sure what "up" is
if(!w || !w->isWindow())
return false;
QTLWExtra *topData = w->d_func()->topData();
QWExtra *extraData = w->d_func()->extraData();
- topData->resizer += up;
+ // topData->resizer is only 4 bits, so subtracting -1 from zero causes bad stuff
+ // to happen, prevent that here (you really want the thing hidden).
+ if (up >= 0 || topData->resizer != 0)
+ topData->resizer += up;
OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->winId()));
{
#ifndef QT_MAC_USE_COCOA
@@ -1539,7 +1542,6 @@ bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
bool remove_grip = (topData->resizer || (w->windowFlags() & Qt::FramelessWindowHint)
|| (extraData->maxw && extraData->maxh &&
extraData->maxw == extraData->minw && extraData->maxh == extraData->minh));
-
#ifndef QT_MAC_USE_COCOA
WindowAttributes attr;
GetWindowAttributes(windowRef, &attr);
diff --git a/src/gui/math3d/qgenericmatrix.h b/src/gui/math3d/qgenericmatrix.h
index 1131f9b..7bdf70a 100644
--- a/src/gui/math3d/qgenericmatrix.h
+++ b/src/gui/math3d/qgenericmatrix.h
@@ -119,7 +119,9 @@ Q_INLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>::QGenericMatrix()
template <int N, int M, typename T, typename InnerT>
Q_INLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>::QGenericMatrix(const QGenericMatrix<N, M, T, InnerT>& other)
{
- qMemCopy(m, other.m, sizeof(m));
+ for (int col = 0; col < N; ++col)
+ for (int row = 0; row < M; ++row)
+ m[col][row] = other.m[col][row];
}
template <int N, int M, typename T, typename InnerT>
diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp
index b998353..88f58c8 100644
--- a/src/gui/math3d/qmatrix4x4.cpp
+++ b/src/gui/math3d/qmatrix4x4.cpp
@@ -53,10 +53,6 @@ QT_BEGIN_NAMESPACE
\brief The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
\since 4.6
- The matrix elements are stored internally using the most efficient
- numeric representation for the underlying hardware: floating-point
- or fixed-point.
-
\sa QVector3D, QGenericMatrix
*/
@@ -308,8 +304,7 @@ QMatrix4x4::QMatrix4x4(const QTransform& transform)
// The 4x4 matrix inverse algorithm is based on that described at:
// http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24
// Some optimization has been done to avoid making copies of 3x3
-// sub-matrices, to do calculations in fixed-point where required,
-// and to unroll the loops.
+// sub-matrices and to unroll the loops.
// Calculate the determinant of a 3x3 sub-matrix.
// | A B C |
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index 9988e2b..d9d4160 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -55,10 +55,6 @@ QT_BEGIN_NAMESPACE
Quaternions are used to represent rotations in 3D space, and
consist of a 3D rotation axis specified by the x, y, and z
coordinates, and a scalar representing the rotation angle.
-
- The components of a quaternion are stored internally using the most
- efficient representation for the GL rendering engine, which will be
- either floating-point or fixed-point.
*/
/*!
diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp
index 9b5d123..b492aa8 100644
--- a/src/gui/math3d/qvector2d.cpp
+++ b/src/gui/math3d/qvector2d.cpp
@@ -57,9 +57,7 @@ QT_BEGIN_NAMESPACE
The QVector2D class can also be used to represent vertices in 2D space.
We therefore do not need to provide a separate vertex class.
- The coordinates are stored internally using the most efficient
- representation for the GL rendering engine, which will be either
- floating-point or fixed-point.
+ \sa QVector3D, QVector4D, QQuaternion
*/
/*!
diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp
index 977152a..95550cd 100644
--- a/src/gui/math3d/qvector3d.cpp
+++ b/src/gui/math3d/qvector3d.cpp
@@ -61,9 +61,7 @@ QT_BEGIN_NAMESPACE
The QVector3D class can also be used to represent vertices in 3D space.
We therefore do not need to provide a separate vertex class.
- The coordinates are stored internally using the most efficient
- representation for the GL rendering engine, which will be either
- floating-point or fixed-point.
+ \sa QVector2D, QVector4D, QQuaternion
*/
/*!
diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp
index a28d2a1..1f7d921 100644
--- a/src/gui/math3d/qvector4d.cpp
+++ b/src/gui/math3d/qvector4d.cpp
@@ -57,10 +57,6 @@ QT_BEGIN_NAMESPACE
The QVector4D class can also be used to represent vertices in 4D space.
We therefore do not need to provide a separate vertex class.
- The coordinates are stored internally using the most efficient
- representation for the GL rendering engine, which will be either
- floating-point or fixed-point.
-
\sa QQuaternion, QVector2D, QVector3D
*/
diff --git a/src/gui/text/qsyntaxhighlighter.cpp b/src/gui/text/qsyntaxhighlighter.cpp
index db1a38e..f69562d 100644
--- a/src/gui/text/qsyntaxhighlighter.cpp
+++ b/src/gui/text/qsyntaxhighlighter.cpp
@@ -65,6 +65,18 @@ public:
void _q_reformatBlocks(int from, int charsRemoved, int charsAdded);
void reformatBlock(QTextBlock block);
+
+ inline void rehighlight(QTextCursor &cursor, QTextCursor::MoveOperation operation) {
+ QObject::disconnect(doc, SIGNAL(contentsChange(int,int,int)),
+ q_func(), SLOT(_q_reformatBlocks(int,int,int)));
+ cursor.beginEditBlock();
+ int from = cursor.position();
+ cursor.movePosition(operation);
+ _q_reformatBlocks(from, 0, cursor.position() - from);
+ cursor.endEditBlock();
+ QObject::connect(doc, SIGNAL(contentsChange(int,int,int)),
+ q_func(), SLOT(_q_reformatBlocks(int,int,int)));
+ }
inline void _q_delayedRehighlight() {
if (!rehighlightPending)
@@ -356,6 +368,8 @@ QTextDocument *QSyntaxHighlighter::document() const
\since 4.2
Redoes the highlighting of the whole document.
+
+ \sa rehighlightBlock()
*/
void QSyntaxHighlighter::rehighlight()
{
@@ -363,15 +377,25 @@ void QSyntaxHighlighter::rehighlight()
if (!d->doc)
return;
- disconnect(d->doc, SIGNAL(contentsChange(int,int,int)),
- this, SLOT(_q_reformatBlocks(int,int,int)));
QTextCursor cursor(d->doc);
- cursor.beginEditBlock();
- cursor.movePosition(QTextCursor::End);
- d->_q_reformatBlocks(0, 0, cursor.position());
- cursor.endEditBlock();
- connect(d->doc, SIGNAL(contentsChange(int,int,int)),
- this, SLOT(_q_reformatBlocks(int,int,int)));
+ d->rehighlight(cursor, QTextCursor::End);
+}
+
+/*!
+ \since 4.6
+
+ Redoes the highlighting of the given QTextBlock \a block.
+
+ \sa rehighlight()
+*/
+void QSyntaxHighlighter::rehighlightBlock(const QTextBlock &block)
+{
+ Q_D(QSyntaxHighlighter);
+ if (!d->doc)
+ return;
+
+ QTextCursor cursor(block);
+ d->rehighlight(cursor, QTextCursor::EndOfBlock);
}
/*!
diff --git a/src/gui/text/qsyntaxhighlighter.h b/src/gui/text/qsyntaxhighlighter.h
index 4e5271b..ee249b8 100644
--- a/src/gui/text/qsyntaxhighlighter.h
+++ b/src/gui/text/qsyntaxhighlighter.h
@@ -78,6 +78,7 @@ public:
public Q_SLOTS:
void rehighlight();
+ void rehighlightBlock(const QTextBlock &block);
protected:
virtual void highlightBlock(const QString &text) = 0;
diff --git a/src/gui/widgets/qabstractscrollarea_p.h b/src/gui/widgets/qabstractscrollarea_p.h
index 7e0f444..aef8ac5 100644
--- a/src/gui/widgets/qabstractscrollarea_p.h
+++ b/src/gui/widgets/qabstractscrollarea_p.h
@@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE
class QScrollBar;
class QAbstractScrollAreaScrollBarContainer;
-class QAbstractScrollAreaPrivate: public QFramePrivate
+class Q_AUTOTEST_EXPORT QAbstractScrollAreaPrivate: public QFramePrivate
{
Q_DECLARE_PUBLIC(QAbstractScrollArea)
diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp
index da18d13..433406c 100644
--- a/src/gui/widgets/qabstractspinbox.cpp
+++ b/src/gui/widgets/qabstractspinbox.cpp
@@ -1577,7 +1577,7 @@ void QAbstractSpinBox::initStyleOption(QStyleOptionSpinBox *option) const
option->initFrom(this);
option->activeSubControls = QStyle::SC_None;
option->buttonSymbols = d->buttonSymbols;
- option->subControls = QStyle::SC_SpinBoxFrame;
+ option->subControls = QStyle::SC_SpinBoxFrame | QStyle::SC_SpinBoxEditField;
if (d->buttonSymbols != QAbstractSpinBox::NoButtons) {
option->subControls |= QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown;
if (d->buttonState & Up) {
diff --git a/src/gui/widgets/qdockarealayout.cpp b/src/gui/widgets/qdockarealayout.cpp
index b905ccd..ee29b55 100644
--- a/src/gui/widgets/qdockarealayout.cpp
+++ b/src/gui/widgets/qdockarealayout.cpp
@@ -1707,7 +1707,7 @@ QDockAreaLayoutItem &QDockAreaLayoutInfo::item(const QList<int> &path)
Q_ASSERT(!path.isEmpty());
const int index = path.first();
if (path.count() > 1) {
- const QDockAreaLayoutItem &item = item_list.at(index);
+ const QDockAreaLayoutItem &item = item_list[index];
Q_ASSERT(item.subinfo != 0);
return item.subinfo->item(path.mid(1));
}
diff --git a/src/gui/widgets/qeffects.cpp b/src/gui/widgets/qeffects.cpp
index d6d0a16..f3b1b76 100644
--- a/src/gui/widgets/qeffects.cpp
+++ b/src/gui/widgets/qeffects.cpp
@@ -128,7 +128,8 @@ QAlphaWidget::~QAlphaWidget()
{
#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
// Restore user-defined opacity value
- widget->setWindowOpacity(windowOpacity);
+ if (widget)
+ widget->setWindowOpacity(windowOpacity);
#endif
}
diff --git a/src/gui/widgets/qgroupbox.cpp b/src/gui/widgets/qgroupbox.cpp
index 2380e78..5758b6a 100644
--- a/src/gui/widgets/qgroupbox.cpp
+++ b/src/gui/widgets/qgroupbox.cpp
@@ -478,11 +478,7 @@ void QGroupBox::focusInEvent(QFocusEvent *fe)
if (focusPolicy() == Qt::NoFocus) {
d->_q_fixFocus(fe->reason());
} else {
- QStyleOptionGroupBox box;
- initStyleOption(&box);
- QRect rect = style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxCheckBox, this)
- | style()->subControlRect(QStyle::CC_GroupBox, &box, QStyle::SC_GroupBoxLabel, this);
- update(rect);
+ QWidget::focusInEvent(fe);
}
}
diff --git a/src/gui/widgets/qmainwindow.cpp b/src/gui/widgets/qmainwindow.cpp
index 0c841eb..c51bed9 100644
--- a/src/gui/widgets/qmainwindow.cpp
+++ b/src/gui/widgets/qmainwindow.cpp
@@ -1369,20 +1369,25 @@ bool QMainWindow::event(QEvent *event)
#ifdef Q_WS_MAC
case QEvent::Show:
if (unifiedTitleAndToolBarOnMac())
- macWindowToolbarShow(this, true);
+ d->layout->syncUnifiedToolbarVisibility();
+ d->layout->blockVisiblityCheck = false;
break;
-# ifdef QT_MAC_USE_COCOA
case QEvent::WindowStateChange:
{
+ if (isHidden()) {
+ // We are coming out of a minimize, leave things as is.
+ d->layout->blockVisiblityCheck = true;
+ }
+# ifdef QT_MAC_USE_COCOA
// We need to update the HIToolbar status when we go out of or into fullscreen.
QWindowStateChangeEvent *wce = static_cast<QWindowStateChangeEvent *>(event);
if ((windowState() & Qt::WindowFullScreen) || (wce->oldState() & Qt::WindowFullScreen)) {
d->layout->updateHIToolBarStatus();
}
+# endif // Cocoa
}
break;
-# endif // Cocoa
-#endif
+#endif // Q_WS_MAC
#if !defined(QT_NO_DOCKWIDGET) && !defined(QT_NO_CURSOR)
case QEvent::CursorChange:
if (d->cursorAdjusted) {
diff --git a/src/gui/widgets/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp
index aba9120..3936a67 100644
--- a/src/gui/widgets/qmainwindowlayout.cpp
+++ b/src/gui/widgets/qmainwindowlayout.cpp
@@ -939,15 +939,70 @@ void QMainWindowLayout::getStyleOptionInfo(QStyleOptionToolBar *option, QToolBar
void QMainWindowLayout::toggleToolBarsVisible()
{
- layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
- if (!layoutState.mainWindow->isMaximized()){
- QPoint topLeft = parentWidget()->geometry().topLeft();
- QRect r = parentWidget()->geometry();
- r = layoutState.toolBarAreaLayout.rectHint(r);
- r.moveTo(topLeft);
- parentWidget()->setGeometry(r);
- } else{
- update();
+ bool updateNonUnifiedParts = true;
+#ifdef Q_WS_MAC
+ if (layoutState.mainWindow->unifiedTitleAndToolBarOnMac()) {
+ // If we hit this case, someone has pressed the "toolbar button" which will
+ // toggle the unified toolbar visiblity, because that's what the user wants.
+ // We might be in a situation where someone has hidden all the toolbars
+ // beforehand (maybe in construction), but now they've hit this button and
+ // and are expecting the items to show. What do we do?
+ // 1) Check the visibility of all the toolbars, if one is visible, do nothing, this
+ // preserves what people would expect (these toolbars were visible when I clicked last time).
+ // 2) If NONE are visible, then show them all. Again, this preserves the user expectation
+ // of, "I want to see the toolbars." The user may get more toolbars than expected, but this
+ // is better seeing nothing.
+ // Don't worry about any of this if we are going invisible. This does mean we may get
+ // into issues when switching into and out of fullscreen mode, but this is probably minor.
+ // If we ever need to do hiding, that would have to be taken care of after the unified toolbar
+ // has finished hiding.
+ // People can of course handle the QEvent::ToolBarChange event themselves and do
+ // WHATEVER they want if they don't like what we are doing (though the unified toolbar
+ // will fire regardless).
+
+ // Check if we REALLY need to update the geometry below. If we only have items in the
+ // unified toolbar, all the docks will be empty, so there's very little point
+ // in doing the geometry as Apple will do it (we also avoid flicker in Cocoa as well).
+ // FWIW, layoutState.toolBarAreaLayout.visible and the state of the unified toolbar
+ // visibility can get out of sync. I really don't think it's a big issue. It is kept
+ // to a minimum because we only change the visibility if we absolutely must.
+ // update the "non unified parts."
+ updateNonUnifiedParts = !layoutState.toolBarAreaLayout.isEmpty();
+
+ // We get this function before the unified toolbar does its thing.
+ // So, the value will be opposite of what we expect.
+ bool goingVisible = !macWindowToolbarIsVisible(qt_mac_window_for(layoutState.mainWindow));
+ if (goingVisible) {
+ const int ToolBarCount = qtoolbarsInUnifiedToolbarList.size();
+ bool needAllVisible = true;
+ for (int i = 0; i < ToolBarCount; ++i) {
+ if (!qtoolbarsInUnifiedToolbarList.at(i)->isHidden()) {
+ needAllVisible = false;
+ break;
+ }
+ }
+ if (needAllVisible) {
+ QBoolBlocker blocker(blockVisiblityCheck); // Disable the visibilty check because
+ // the toggle has already happened.
+ for (int i = 0; i < ToolBarCount; ++i)
+ qtoolbarsInUnifiedToolbarList.at(i)->setVisible(true);
+ }
+ }
+ if (!updateNonUnifiedParts)
+ layoutState.toolBarAreaLayout.visible = goingVisible;
+ }
+#endif
+ if (updateNonUnifiedParts) {
+ layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible;
+ if (!layoutState.mainWindow->isMaximized()) {
+ QPoint topLeft = parentWidget()->geometry().topLeft();
+ QRect r = parentWidget()->geometry();
+ r = layoutState.toolBarAreaLayout.rectHint(r);
+ r.moveTo(topLeft);
+ parentWidget()->setGeometry(r);
+ } else {
+ update();
+ }
}
}
@@ -1574,9 +1629,6 @@ void QMainWindowLayout::animationFinished(QWidget *widget)
#ifndef QT_NO_DOCKWIDGET
#ifndef QT_NO_TABBAR
- //it is important to set the current tab before applying the layout
- //so that applyState will not try to counter the result of the animation
- //by putting the item in negative space
if (qobject_cast<QDockWidget*>(widget) != 0) {
// info() might return null if the widget is destroyed while
// animating but before the animationFinished signal is received.
@@ -1586,8 +1638,6 @@ void QMainWindowLayout::animationFinished(QWidget *widget)
#endif
#endif
- applyState(layoutState, false);
-
savedState.clear();
currentGapPos.clear();
pluggingWidget = 0;
@@ -1641,6 +1691,9 @@ QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow)
#ifndef QT_NO_RUBBERBAND
, gapIndicator(new QRubberBand(QRubberBand::Rectangle, mainwindow))
#endif //QT_NO_RUBBERBAND
+#ifdef Q_WS_MAC
+ , blockVisiblityCheck(false)
+#endif
{
#ifndef QT_NO_DOCKWIDGET
#ifndef QT_NO_TABBAR
diff --git a/src/gui/widgets/qmainwindowlayout_mac.mm b/src/gui/widgets/qmainwindowlayout_mac.mm
index 6632be7..61719c2 100644
--- a/src/gui/widgets/qmainwindowlayout_mac.mm
+++ b/src/gui/widgets/qmainwindowlayout_mac.mm
@@ -338,18 +338,16 @@ void QMainWindowLayout::updateHIToolBarStatus()
0, kWindowUnifiedTitleAndToolbarAttribute);
}
#endif
- macWindowToolbarShow(layoutState.mainWindow, useMacToolbar);
layoutState.mainWindow->setUpdatesEnabled(false); // reduces a little bit of flicker, not all though
if (!useMacToolbar) {
- OSWindowRef windowRef = qt_mac_window_for(parentWidget());
- macWindowToolbarShow(parentWidget(), false);
+ macWindowToolbarShow(layoutState.mainWindow, false);
// Move everything out of the HIToolbar into the main toolbar.
while (!qtoolbarsInUnifiedToolbarList.isEmpty()) {
// Should shrink the list by one every time.
layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, qtoolbarsInUnifiedToolbarList.first());
}
- macWindowToolbarSet(windowRef, NULL);
+ macWindowToolbarSet(qt_mac_window_for(layoutState.mainWindow), 0);
} else {
QList<QToolBar *> toolbars = layoutState.mainWindow->findChildren<QToolBar *>();
for (int i = 0; i < toolbars.size(); ++i) {
@@ -359,6 +357,7 @@ void QMainWindowLayout::updateHIToolBarStatus()
layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
}
}
+ syncUnifiedToolbarVisibility();
}
layoutState.mainWindow->setUpdatesEnabled(true);
}
@@ -439,7 +438,7 @@ void QMainWindowLayout::insertIntoMacToolbar(QToolBar *before, QToolBar *toolbar
#else
NSString *toolbarID = kQToolBarNSToolbarIdentifier;
toolbarID = [toolbarID stringByAppendingFormat:@"%p", toolbar];
- cocoaItemIDToToolbarHash.insert(QCFString::toQString(CFStringRef(toolbarID)), toolbar);
+ cocoaItemIDToToolbarHash.insert(qt_mac_NSStringToQString(toolbarID), toolbar);
[macToolbar insertItemWithItemIdentifier:toolbarID atIndex:beforeIndex];
#endif
}
@@ -487,6 +486,7 @@ void QMainWindowLayout::cleanUpMacToolbarItems()
void QMainWindowLayout::fixSizeInUnifiedToolbar(QToolBar *tb) const
{
+#ifdef QT_MAC_USE_COCOA
QHash<void *, QToolBar *>::const_iterator it = unifiedToolbarHash.constBegin();
NSToolbarItem *item = nil;
while (it != unifiedToolbarHash.constEnd()) {
@@ -507,5 +507,26 @@ void QMainWindowLayout::fixSizeInUnifiedToolbar(QToolBar *tb) const
nssize.height = size.height() - 2;
[item setMinSize:nssize];
}
+#else
+ Q_UNUSED(tb);
+#endif
}
+
+void QMainWindowLayout::syncUnifiedToolbarVisibility()
+{
+ if (blockVisiblityCheck)
+ return;
+
+ Q_ASSERT(layoutState.mainWindow->unifiedTitleAndToolBarOnMac());
+ bool show = false;
+ const int ToolBarCount = qtoolbarsInUnifiedToolbarList.count();
+ for (int i = 0; i < ToolBarCount; ++i) {
+ if (qtoolbarsInUnifiedToolbarList.at(i)->isVisible()) {
+ show = true;
+ break;
+ }
+ }
+ macWindowToolbarShow(layoutState.mainWindow, show);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/widgets/qmainwindowlayout_p.h b/src/gui/widgets/qmainwindowlayout_p.h
index 45f62cd..524fdbf 100644
--- a/src/gui/widgets/qmainwindowlayout_p.h
+++ b/src/gui/widgets/qmainwindowlayout_p.h
@@ -335,6 +335,8 @@ public:
void cleanUpMacToolbarItems();
void fixSizeInUnifiedToolbar(QToolBar *tb) const;
bool useHIToolBar;
+ void syncUnifiedToolbarVisibility();
+ bool blockVisiblityCheck;
#endif
};
QT_END_NAMESPACE
diff --git a/src/gui/widgets/qprogressbar.cpp b/src/gui/widgets/qprogressbar.cpp
index ac3338b..d168028 100644
--- a/src/gui/widgets/qprogressbar.cpp
+++ b/src/gui/widgets/qprogressbar.cpp
@@ -204,7 +204,7 @@ bool QProgressBarPrivate::repaintRequired() const
\o A progress bar shown in the Plastique widget style.
\endtable
- \sa QTimeLine, QProgressDialog, {fowler}{GUI Design Handbook: Progress Indicator}
+ \sa QProgressDialog, {fowler}{GUI Design Handbook: Progress Indicator}
*/
/*!
diff --git a/src/gui/widgets/qspinbox.cpp b/src/gui/widgets/qspinbox.cpp
index e069a21..3933272 100644
--- a/src/gui/widgets/qspinbox.cpp
+++ b/src/gui/widgets/qspinbox.cpp
@@ -50,6 +50,7 @@
#include <qdebug.h>
#include <math.h>
+#include <float.h>
QT_BEGIN_NAMESPACE
@@ -823,8 +824,8 @@ void QDoubleSpinBox::setRange(double minimum, double maximum)
Sets how many decimals the spinbox will use for displaying and
interpreting doubles.
- \warning The results might not be reliable with very high values
- for \a decimals.
+ \warning The maximum value for \a decimals is DBL_MAX_10_EXP +
+ DBL_DIG (ie. 323) because of the limitations of the double type.
Note: The maximum, minimum and value might change as a result of
changing this property.
@@ -840,7 +841,7 @@ int QDoubleSpinBox::decimals() const
void QDoubleSpinBox::setDecimals(int decimals)
{
Q_D(QDoubleSpinBox);
- d->decimals = qMax(0, decimals);
+ d->decimals = qBound(0, decimals, DBL_MAX_10_EXP + DBL_DIG);
setRange(minimum(), maximum()); // make sure values are rounded
setValue(value());
diff --git a/src/gui/widgets/qtabbar.cpp b/src/gui/widgets/qtabbar.cpp
index 11cb6a1..690e624 100644
--- a/src/gui/widgets/qtabbar.cpp
+++ b/src/gui/widgets/qtabbar.cpp
@@ -663,7 +663,7 @@ void QTabBarPrivate::refresh()
if (pressedIndex != -1
&& movable
&& QApplication::mouseButtons() == Qt::NoButton) {
- _q_moveTabFinished(pressedIndex);
+ moveTabFinished(pressedIndex);
if (!validIndex(pressedIndex))
pressedIndex = -1;
}
@@ -1662,26 +1662,17 @@ void QTabBarPrivate::slide(int from, int to)
q->setUpdatesEnabled(true);
int postLocation = vertical ? q->tabRect(to).y() : q->tabRect(to).x();
int length = postLocation - preLocation;
- tabList[to].makeTimeLine(q);
- tabList[to].dragOffset += -1 * length;
- tabList[to].timeLine->setFrameRange(tabList[to].dragOffset, 0);
- animations[tabList[to].timeLine] = to;
- tabList[to].timeLine->setDuration(ANIMATION_DURATION);
- if (tabList[to].timeLine->state() != QTimeLine::Running)
- tabList[to].timeLine->start();
+ tabList[to].dragOffset -= length;
+ tabList[to].startAnimation(this, ANIMATION_DURATION);
}
-void QTabBarPrivate::_q_moveTab(int offset)
+void QTabBarPrivate::moveTab(int index, int offset)
{
- Q_Q(QTabBar);
- if (QTimeLine *timeLine = qobject_cast<QTimeLine *>(q->sender())) {
- int index = animations[timeLine];
- if (!validIndex(index))
- return;
- tabList[index].dragOffset = offset;
- layoutTab(index); // Make buttons follow tab
- q->update();
- }
+ if (!validIndex(index))
+ return;
+ tabList[index].dragOffset = offset;
+ layoutTab(index); // Make buttons follow tab
+ q_func()->update();
}
/*!\reimp
@@ -1695,7 +1686,7 @@ void QTabBar::mousePressEvent(QMouseEvent *event)
}
// Be safe!
if (d->pressedIndex != -1 && d->movable)
- d->_q_moveTabFinished(d->pressedIndex);
+ d->moveTabFinished(d->pressedIndex);
d->pressedIndex = d->indexAtPos(event->pos());
if (d->validIndex(d->pressedIndex)) {
@@ -1721,7 +1712,7 @@ void QTabBar::mouseMoveEvent(QMouseEvent *event)
// Be safe!
if (d->pressedIndex != -1
&& event->buttons() == Qt::NoButton)
- d->_q_moveTabFinished(d->pressedIndex);
+ d->moveTabFinished(d->pressedIndex);
// Start drag
if (!d->dragInProgress && d->pressedIndex != -1) {
@@ -1789,16 +1780,6 @@ void QTabBar::mouseMoveEvent(QMouseEvent *event)
optTabBase.documentMode = d->documentMode;
}
-void QTabBarPrivate::_q_moveTabFinished()
-{
- Q_Q(QTabBar);
- if (QTimeLine *timeLine = qobject_cast<QTimeLine *>(q->sender())) {
- int index = animations[timeLine];
- animations.remove(timeLine);
- _q_moveTabFinished(index);
- }
-}
-
void QTabBarPrivate::setupMovableTab()
{
Q_Q(QTabBar);
@@ -1838,11 +1819,19 @@ void QTabBarPrivate::setupMovableTab()
movingTab->setVisible(true);
}
-void QTabBarPrivate::_q_moveTabFinished(int index)
+void QTabBarPrivate::moveTabFinished(int index)
{
Q_Q(QTabBar);
bool cleanup = (pressedIndex == index) || (pressedIndex == -1) || !validIndex(index);
- if (animations.isEmpty() && cleanup) {
+ bool allAnimationsFinished = true;
+#ifndef QT_NO_ANIMATION
+ for(int i = 0; allAnimationsFinished && i < tabList.count(); ++i) {
+ const Tab &t = tabList.at(i);
+ if (t.animation && t.animation->state() == QAbstractAnimation::Running)
+ allAnimationsFinished = false;
+ }
+#endif //QT_NO_ANIMATION
+ if (allAnimationsFinished && cleanup) {
movingTab->setVisible(false); // We might not get a mouse release
for (int i = 0; i < tabList.count(); ++i) {
tabList[i].dragOffset = 0;
@@ -1877,17 +1866,8 @@ void QTabBar::mouseReleaseEvent(QMouseEvent *event)
? tabRect(d->pressedIndex).height()
: tabRect(d->pressedIndex).width();
int duration = qMin(ANIMATION_DURATION,
- ((length < 0 ? (-1 * length) : length) * ANIMATION_DURATION) / width);
- if (duration > 0) {
- d->tabList[d->pressedIndex].makeTimeLine(this);
- d->tabList[d->pressedIndex].timeLine->setFrameRange(length, 0);
- d->animations[d->tabList[d->pressedIndex].timeLine] = d->pressedIndex;
- d->tabList[d->pressedIndex].timeLine->setDuration(duration);
- if (d->tabList[d->pressedIndex].timeLine->state() != QTimeLine::Running)
- d->tabList[d->pressedIndex].timeLine->start();
- } else {
- d->_q_moveTabFinished(d->pressedIndex);
- }
+ (qAbs(length) * ANIMATION_DURATION) / width);
+ d->tabList[d->pressedIndex].startAnimation(d, duration);
d->dragInProgress = false;
d->movingTab->setVisible(false);
d->dragStartPosition = QPoint();
diff --git a/src/gui/widgets/qtabbar.h b/src/gui/widgets/qtabbar.h
index 7514486..402f54b 100644
--- a/src/gui/widgets/qtabbar.h
+++ b/src/gui/widgets/qtabbar.h
@@ -215,8 +215,6 @@ private:
Q_DECLARE_PRIVATE(QTabBar)
Q_PRIVATE_SLOT(d_func(), void _q_scrollTabs())
Q_PRIVATE_SLOT(d_func(), void _q_closeTab())
- Q_PRIVATE_SLOT(d_func(), void _q_moveTab(int))
- Q_PRIVATE_SLOT(d_func(), void _q_moveTabFinished())
};
#endif // QT_NO_TABBAR
diff --git a/src/gui/widgets/qtabbar_p.h b/src/gui/widgets/qtabbar_p.h
index dbae055..b9b9fba 100644
--- a/src/gui/widgets/qtabbar_p.h
+++ b/src/gui/widgets/qtabbar_p.h
@@ -58,9 +58,8 @@
#include <qicon.h>
#include <qtoolbutton.h>
-#include <qtimeline.h>
-#include <qhash.h>
#include <qdebug.h>
+#include <qvariantanimation.h>
#ifndef QT_NO_TABBAR
@@ -75,9 +74,10 @@ class QTabBarPrivate : public QWidgetPrivate
Q_DECLARE_PUBLIC(QTabBar)
public:
QTabBarPrivate()
- :currentIndex(-1), pressedIndex(-1),
- shape(QTabBar::RoundedNorth),
- layoutDirty(false), drawBase(true), scrollOffset(0), expanding(true), closeButtonOnTabs(false), selectionBehaviorOnRemove(QTabBar::SelectRightTab), paintWithOffsets(true), movable(false), dragInProgress(false), documentMode(false), movingTab(0) {}
+ :currentIndex(-1), pressedIndex(-1), shape(QTabBar::RoundedNorth), layoutDirty(false),
+ drawBase(true), scrollOffset(0), expanding(true), closeButtonOnTabs(false),
+ selectionBehaviorOnRemove(QTabBar::SelectRightTab), paintWithOffsets(true), movable(false),
+ dragInProgress(false), documentMode(false), movingTab(0) {}
int currentIndex;
int pressedIndex;
@@ -88,16 +88,13 @@ public:
struct Tab {
inline Tab(const QIcon &ico, const QString &txt)
- : enabled(true)
- , shortcutId(0)
- , text(txt)
- , icon(ico)
- , leftWidget(0)
- , rightWidget(0)
- , lastTab(-1)
- , timeLine(0)
- , dragOffset(0)
+ : enabled(true) , shortcutId(0), text(txt), icon(ico),
+ leftWidget(0), rightWidget(0), lastTab(-1), dragOffset(0)
+#ifndef QT_NO_ANIMATION
+ , animation(0)
+#endif //QT_NO_ANIMATION
{}
+ bool operator==(const Tab &other) const { return &other == this; }
bool enabled;
int shortcutId;
QString text;
@@ -117,21 +114,39 @@ public:
QWidget *leftWidget;
QWidget *rightWidget;
int lastTab;
-
- QTimeLine *timeLine;
int dragOffset;
- void makeTimeLine(QWidget *q) {
- if (timeLine)
- return;
- timeLine = new QTimeLine(ANIMATION_DURATION, q);
- q->connect(timeLine, SIGNAL(frameChanged(int)), q, SLOT(_q_moveTab(int)));
- q->connect(timeLine, SIGNAL(finished()), q, SLOT(_q_moveTabFinished()));
+#ifndef QT_NO_ANIMATION
+ ~Tab() { delete animation; }
+ struct TabBarAnimation : public QVariantAnimation {
+ TabBarAnimation(Tab *t, QTabBarPrivate *_priv) : tab(t), priv(_priv)
+ { setEasingCurve(QEasingCurve::InOutQuad); }
+
+ void updateCurrentValue(const QVariant &current)
+ { priv->moveTab(priv->tabList.indexOf(*tab), current.toInt()); }
+
+ void updateState(State, State newState)
+ { if (newState == Stopped) priv->moveTabFinished(priv->tabList.indexOf(*tab)); }
+ private:
+ //these are needed for the callbacks
+ Tab *tab;
+ QTabBarPrivate *priv;
+ } *animation;
+
+ void startAnimation(QTabBarPrivate *priv, int duration) {
+ if (!animation)
+ animation = new TabBarAnimation(this, priv);
+ animation->setStartValue(dragOffset);
+ animation->setEndValue(0);
+ animation->setDuration(duration);
+ animation->start();
}
-
+#else
+ void startAnimation(QTabBarPrivate *priv, int duration)
+ { Q_UNUSED(duration); priv->moveTabFinished(priv->tabList.indexOf(*this)); }
+#endif //QT_NO_ANIMATION
};
QList<Tab> tabList;
- QHash<QTimeLine*, int> animations;
int calculateNewPosition(int from, int to, int index) const;
void slide(int from, int to);
@@ -152,9 +167,8 @@ public:
void _q_scrollTabs();
void _q_closeTab();
- void _q_moveTab(int);
- void _q_moveTabFinished();
- void _q_moveTabFinished(int offset);
+ void moveTab(int index, int offset);
+ void moveTabFinished(int index);
QRect hoverRect;
void refresh();
diff --git a/src/gui/widgets/qtoolbar.cpp b/src/gui/widgets/qtoolbar.cpp
index b249915..b65f1ba 100644
--- a/src/gui/widgets/qtoolbar.cpp
+++ b/src/gui/widgets/qtoolbar.cpp
@@ -1074,6 +1074,15 @@ static bool waitForPopup(QToolBar *tb, QWidget *popup)
return false;
}
+#if defined(Q_WS_MAC)
+static bool toolbarInUnifiedToolBar(QToolBar *toolbar)
+{
+ const QMainWindow *mainWindow = qobject_cast<const QMainWindow *>(toolbar->parentWidget());
+ return mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()
+ && mainWindow->toolBarArea(toolbar) == Qt::TopToolBarArea;
+}
+#endif
+
/*! \reimp */
bool QToolBar::event(QEvent *event)
{
@@ -1096,7 +1105,15 @@ bool QToolBar::event(QEvent *event)
// fallthrough intended
case QEvent::Show:
d->toggleViewAction->setChecked(event->type() == QEvent::Show);
-#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
+#if defined(Q_WS_MAC)
+ if (toolbarInUnifiedToolBar(this)) {
+ // I can static_cast because I did the qobject_cast in the if above, therefore
+ // we must have a QMainWindowLayout here.
+ QMainWindowLayout *mwLayout = static_cast<QMainWindowLayout *>(parentWidget()->layout());
+ mwLayout->fixSizeInUnifiedToolbar(this);
+ mwLayout->syncUnifiedToolbarVisibility();
+ }
+# if !defined(QT_MAC_USE_COCOA)
// Fall through
case QEvent::LayoutRequest: {
// There's currently no way to invalidate the size and let
@@ -1111,10 +1128,9 @@ bool QToolBar::event(QEvent *event)
}
if (needUpdate) {
- OSWindowRef windowRef = qt_mac_window_for(this);
- if (mainWindow->unifiedTitleAndToolBarOnMac()
- && mainWindow->toolBarArea(this) == Qt::TopToolBarArea
- && macWindowToolbarVisible(windowRef)) {
+ OSWindowRef windowRef = qt_mac_window_for(mainWindow);
+ if (toolbarInUnifiedToolBar(this)
+ && macWindowToolbarIsVisible(windowRef)) {
DisableScreenUpdates();
macWindowToolbarShow(this, false);
macWindowToolbarShow(this, true);
@@ -1126,7 +1142,8 @@ bool QToolBar::event(QEvent *event)
return earlyResult;
}
}
-#endif
+# endif // !QT_MAC_USE_COCOA
+#endif // Q_WS_MAC
break;
case QEvent::ParentChange:
d->layout->checkUsePopupMenu();
diff --git a/src/gui/widgets/qwidgetanimator.cpp b/src/gui/widgets/qwidgetanimator.cpp
index 26cf905..1a93b51 100644
--- a/src/gui/widgets/qwidgetanimator.cpp
+++ b/src/gui/widgets/qwidgetanimator.cpp
@@ -100,7 +100,6 @@ void QWidgetAnimator::animate(QWidget *widget, const QRect &_final_geometry, boo
m_animation_map[widget] = anim;
connect(anim, SIGNAL(finished()), SLOT(animationFinished()));
anim->start(QPropertyAnimation::DeleteWhenStopped);
- Q_ASSERT(animate || widget->geometry() == final_geometry);
#else
//we do it in one shot
widget->setGeometry(final_geometry);
diff --git a/src/gui/widgets/qwidgetanimator_p.h b/src/gui/widgets/qwidgetanimator_p.h
index 64697a9..5a3e39d 100644
--- a/src/gui/widgets/qwidgetanimator_p.h
+++ b/src/gui/widgets/qwidgetanimator_p.h
@@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE
class QWidget;
class QMainWindowLayout;
class QPropertyAnimation;
+class QRect;
class QWidgetAnimator : public QObject
{
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 483589b..7a616aa 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -201,6 +201,7 @@ bool QHttpNetworkReply::isFinished() const
QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
: QHttpNetworkHeaderPrivate(newUrl), state(NothingDoneState), statusCode(100),
majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0),
+ chunkedTransferEncoding(0),
currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false),
autoDecompress(false), responseData(0), requestIsPrepared(false)
{
@@ -506,6 +507,9 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
state = ReadingDataState;
fragment.clear(); // next fragment
bodyLength = contentLength(); // cache the length
+
+ // cache isChunked() since it is called often
+ chunkedTransferEncoding = headerField("transfer-encoding").toLower().contains("chunked");
}
return bytes;
}
@@ -546,7 +550,7 @@ void QHttpNetworkReplyPrivate::parseHeader(const QByteArray &header)
bool QHttpNetworkReplyPrivate::isChunked()
{
- return headerField("transfer-encoding").toLower().contains("chunked");
+ return chunkedTransferEncoding;
}
bool QHttpNetworkReplyPrivate::connectionCloseEnabled()
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index b86cfaa..5eb70ce 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -198,6 +198,7 @@ public:
qint64 contentRead;
qint64 totalProgress;
QByteArray fragment; // used for header, status, chunk header etc, not for reply data
+ bool chunkedTransferEncoding;
qint64 currentChunkSize;
qint64 currentChunkRead;
QPointer<QHttpNetworkConnection> connection;
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index de39970..28319bb 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -461,8 +461,8 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data)
void QNetworkReplyImplPrivate::finished()
{
Q_Q(QNetworkReplyImpl);
- Q_ASSERT_X(state != Finished, "QNetworkReplyImpl",
- "Backend called finished/finishedWithError more than once");
+ if (state == Finished || state == Aborted)
+ return;
state = Finished;
pendingNotifications.clear();
diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp
index 1d968c2..608db65 100644
--- a/src/network/kernel/qnetworkproxy.cpp
+++ b/src/network/kernel/qnetworkproxy.cpp
@@ -366,7 +366,7 @@ static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::Pro
int(QNetworkProxy::HostNameLookupCapability)),
};
- if (int(type) < 0 && int(type) > int(QNetworkProxy::FtpCachingProxy))
+ if (int(type) < 0 || int(type) > int(QNetworkProxy::FtpCachingProxy))
type = QNetworkProxy::DefaultProxy;
return QNetworkProxy::Capabilities(defaults[int(type)]);
}
diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp
index 1a971f0..794b2b7 100644
--- a/src/network/socket/qlocalsocket_win.cpp
+++ b/src/network/socket/qlocalsocket_win.cpp
@@ -168,7 +168,7 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
// we have a valid handle
d->serverName = name;
- if (setSocketDescriptor((quintptr)localSocket), openMode) {
+ if (setSocketDescriptor((quintptr)localSocket, ConnectedState, openMode)) {
d->handle = localSocket;
emit connected();
}
@@ -299,8 +299,6 @@ void QLocalSocket::abort()
DWORD QLocalSocketPrivate::bytesAvailable()
{
Q_Q(QLocalSocket);
- if (q->state() != QLocalSocket::ConnectedState)
- return 0;
DWORD bytes;
if (PeekNamedPipe(handle, NULL, 0, NULL, &bytes, NULL)) {
return bytes;
@@ -410,7 +408,7 @@ bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
d->handle = (int*)socketDescriptor;
d->state = socketState;
emit stateChanged(d->state);
- if (d->state == ConnectedState) {
+ if (d->state == ConnectedState && openMode.testFlag(QIODevice::ReadOnly)) {
d->startAsyncRead();
d->checkReadyRead();
}
@@ -471,6 +469,10 @@ bool QLocalSocket::waitForDisconnected(int msecs)
Q_D(QLocalSocket);
if (state() == UnconnectedState)
return false;
+ if (!openMode().testFlag(QIODevice::ReadOnly)) {
+ qWarning("QLocalSocket::waitForDisconnected isn't supported for write only pipes.");
+ return false;
+ }
QIncrementalSleepTimer timer(msecs);
forever {
d->bytesAvailable(); // to check if PeekNamedPipe fails
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
index 096bf40..4928b67 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
@@ -81,7 +81,7 @@ template <> inline const bool* ptr<bool>(const bool &) { return 0; }
template <typename device, typename T1, typename T2, typename T3>
static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
int scale, bool matrixRotShear, bool simplePen,
- bool dfbHandledClip,
+ bool dfbHandledClip, bool unsupportedCompositionMode,
const char *nameOne, const T1 &one,
const char *nameTwo, const T2 &two,
const char *nameThree, const T3 &three)
@@ -98,7 +98,8 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device *
dbg << "scale" << scale
<< "matrixRotShear" << matrixRotShear
<< "simplePen" << simplePen
- << "dfbHandledClip" << dfbHandledClip;
+ << "dfbHandledClip" << dfbHandledClip
+ << "unsupportedCompositionMode" << unsupportedCompositionMode;
const T1 *t1 = ptr(one);
const T2 *t2 = ptr(two);
@@ -124,6 +125,7 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device *
__FUNCTION__, state()->painter->device(), \
d_func()->scale, d_func()->matrixRotShear, \
d_func()->simplePen, d_func()->dfbCanHandleClip(), \
+ d_func()->unsupportedCompositionMode, \
#one, one, #two, two, #three, three); \
if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \
return;
@@ -138,6 +140,7 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device *
__FUNCTION__, state()->painter->device(), \
d_func()->scale, d_func()->matrixRotShear, \
d_func()->simplePen, d_func()->dfbCanHandleClip(), \
+ d_func()->unsupportedCompositionMode, \
#one, one, #two, two, #three, three);
#else
#define RASTERFALLBACK(op, one, two, three)
@@ -238,7 +241,7 @@ public:
void fillRects(const QRectF *rects, int count);
void drawRects(const QRectF *rects, int count);
- void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap);
+ void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos);
void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src);
inline void updateClip();
@@ -281,6 +284,7 @@ private:
bool unsupportedCompositionMode;
QDirectFBPaintEngine *q;
+ QRect currentClip;
friend class QDirectFBPaintEngine;
};
@@ -340,6 +344,7 @@ bool QDirectFBPaintEngine::end()
#if (Q_DIRECTFB_VERSION >= 0x010000)
d->surface->ReleaseSource(d->surface);
#endif
+ d->currentClip = QRect();
d->surface->SetClip(d->surface, NULL);
d->surface = 0;
return QRasterPaintEngine::end();
@@ -610,30 +615,26 @@ void QDirectFBPaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm)
void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r,
const QPixmap &pixmap,
- const QPointF &sp)
+ const QPointF &offset)
{
Q_D(QDirectFBPaintEngine);
d->updateClip();
if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) {
- RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), sp);
+ RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
d->lock();
- QRasterPaintEngine::drawTiledPixmap(r, pixmap, sp);
- } else if (d->unsupportedCompositionMode || !d->dfbCanHandleClip(r) || d->matrixRotShear || !sp.isNull()
+ QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset);
+ } else if (d->unsupportedCompositionMode || !d->dfbCanHandleClip(r) || d->matrixRotShear
|| d->scale == QDirectFBPaintEnginePrivate::NegativeScale) {
- RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), sp);
+ RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ);
d->lock();
QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType);
data->fromImage(*img, Qt::AutoColor);
const QPixmap pix(data);
- QRasterPaintEngine::drawTiledPixmap(r, pix, sp);
+ QRasterPaintEngine::drawTiledPixmap(r, pix, offset);
} else {
d->unlock();
- QPixmapData *data = pixmap.pixmapData();
- Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
- QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
- dfbData->unlockDirectFB();
- d->drawTiledPixmap(r, pixmap);
+ d->drawTiledPixmap(r, pixmap, offset);
}
}
@@ -730,14 +731,17 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
d->surface->FillRectangle(d->surface, r.x(), r.y(),
r.width(), r.height());
return; }
- case Qt::TexturePattern:
- if (state()->brushOrigin == QPointF() && brush.transform().isIdentity()) {
- //could handle certain types of brush.transform() E.g. scale
- d->unlock();
- d->drawTiledPixmap(rect, brush.texture());
- return;
- }
- break;
+ case Qt::TexturePattern: {
+ if (d->scale == QDirectFBPaintEnginePrivate::NegativeScale)
+ break;
+
+ const QPixmap texture = brush.texture();
+ if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass)
+ break;
+
+ d->unlock();
+ d->drawTiledPixmap(rect, texture, rect.topLeft() - state()->brushOrigin);
+ return; }
default:
break;
}
@@ -1059,6 +1063,8 @@ void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s,
{
const QRect sr = src.toRect();
const QRect dr = transform.mapRect(dest).toRect();
+ if (dr.isEmpty())
+ return;
const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() };
DFBResult result;
@@ -1072,55 +1078,105 @@ void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s,
DirectFBError("QDirectFBPaintEngine::drawPixmap()", result);
}
-void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest,
- const QPixmap &pixmap)
+static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset)
{
+ qreal pos = rect_pos - offset;
+ while (pos > rect_pos)
+ pos -= pixmapSize;
+ while (pos + pixmapSize < rect_pos)
+ pos += pixmapSize;
+ return pos;
+}
+
+void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &off)
+{
+ Q_ASSERT(!dirtyClip);
+ const QRect destinationRect = transform.mapRect(dest).toRect().normalized();
+ QRect newClip = destinationRect;
+ if (!currentClip.isEmpty())
+ newClip &= currentClip;
+
+ if (newClip.isNull())
+ return;
+
+ const DFBRegion clip = {
+ newClip.x(),
+ newClip.y(),
+ newClip.x() + newClip.width() - 1,
+ newClip.y() + newClip.height() - 1
+ };
+ surface->SetClip(surface, &clip);
+
+ QPointF offset = off;
+ Q_ASSERT(transform.type() <= QTransform::TxScale);
prepareForBlit(pixmap.hasAlphaChannel());
QPixmapData *data = pixmap.pixmapData();
Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
- IDirectFBSurface *s = dfbData->directFBSurface();
- const QRect dr = transform.mapRect(dest).toRect();
- DFBResult result = DFB_OK;
-
- if (scale == NoScale && dr == QRect(0, 0, fbWidth, fbHeight)) {
- result = surface->TileBlit(surface, s, 0, 0, 0);
- } else if (scale == NoScale) {
- const int dx = pixmap.width();
- const int dy = pixmap.height();
- const DFBRectangle rect = { 0, 0, dx, dy };
- QVarLengthArray<DFBRectangle> rects;
- QVarLengthArray<DFBPoint> points;
-
- for (int y = dr.y(); y <= dr.bottom(); y += dy) {
- for (int x = dr.x(); x <= dr.right(); x += dx) {
- rects.append(rect);
- const DFBPoint point = { x, y };
- points.append(point);
+ dfbData->unlockDirectFB();
+ const QSize pixmapSize = dfbData->size();
+ IDirectFBSurface *sourceSurface = dfbData->directFBSurface();
+ if (transform.isScaling()) {
+ Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0);
+ offset.rx() *= transform.m11();
+ offset.ry() *= transform.m22();
+
+ const QSizeF mappedSize(pixmapSize.width() * transform.m11(), pixmapSize.height() * transform.m22());
+ qreal y = ::fixCoord(destinationRect.y(), mappedSize.height(), offset.y());
+ const qreal startX = ::fixCoord(destinationRect.x(), mappedSize.width(), offset.x());
+ while (y < destinationRect.bottom()) {
+ qreal x = startX;
+ while (x < destinationRect.right()) {
+ const DFBRectangle destination = { qRound(x), qRound(y), mappedSize.width(), mappedSize.height() };
+ surface->StretchBlit(surface, sourceSurface, 0, &destination);
+ x += mappedSize.width();
}
+ y += mappedSize.height();
}
- result = surface->BatchBlit(surface, s, rects.constData(),
- points.constData(), points.size());
} else {
- const QRect sr = transform.mapRect(QRect(0, 0, pixmap.width(), pixmap.height()));
- const int dx = sr.width();
- const int dy = sr.height();
- const DFBRectangle sRect = { 0, 0, dx, dy };
-
- for (int y = dr.y(); y <= dr.bottom(); y += dy) {
- for (int x = dr.x(); x <= dr.right(); x += dx) {
- const DFBRectangle dRect = { x, y, dx, dy };
- result = surface->StretchBlit(surface, s, &sRect, &dRect);
- if (result != DFB_OK) {
- y = dr.bottom() + 1;
- break;
- }
+ qreal y = ::fixCoord(destinationRect.y(), pixmapSize.height(), offset.y());
+ const qreal startX = ::fixCoord(destinationRect.x(), pixmapSize.width(), offset.x());
+ int horizontal = qMax(1, destinationRect.width() / pixmapSize.width()) + 1;
+ if (startX != destinationRect.x())
+ ++horizontal;
+ int vertical = qMax(1, destinationRect.height() / pixmapSize.height()) + 1;
+ if (y != destinationRect.y())
+ ++vertical;
+
+ const int maxCount = (vertical * horizontal);
+ QVarLengthArray<DFBRectangle, 16> sourceRects(maxCount);
+ QVarLengthArray<DFBPoint, 16> points(maxCount);
+
+ int i = 0;
+ while (y < destinationRect.bottom()) {
+ Q_ASSERT(i < maxCount);
+ qreal x = startX;
+ while (x < destinationRect.right()) {
+ points[i].x = qRound(x);
+ points[i].y = qRound(y);
+ sourceRects[i].x = 0;
+ sourceRects[i].y = 0;
+ sourceRects[i].w = int(pixmapSize.width());
+ sourceRects[i].h = int(pixmapSize.height());
+ x += pixmapSize.width();
+ ++i;
}
+ y += pixmapSize.height();
}
+ surface->BatchBlit(surface, sourceSurface, sourceRects.constData(), points.constData(), i);
}
- if (result != DFB_OK)
- DirectFBError("QDirectFBPaintEngine::drawTiledPixmap()", result);
+ if (currentClip.isEmpty()) {
+ surface->SetClip(surface, 0);
+ } else {
+ const DFBRegion clip = {
+ currentClip.x(),
+ currentClip.y(),
+ currentClip.x() + currentClip.width(),
+ currentClip.y() + currentClip.height()
+ };
+ surface->SetClip(surface, &clip);
+ }
}
void QDirectFBPaintEnginePrivate::updateClip()
@@ -1128,6 +1184,7 @@ void QDirectFBPaintEnginePrivate::updateClip()
if (!dirtyClip)
return;
+ currentClip = QRect();
const QClipData *clipData = clip();
if (!clipData || !clipData->enabled) {
surface->SetClip(surface, NULL);
@@ -1140,6 +1197,8 @@ void QDirectFBPaintEnginePrivate::updateClip()
clipData->clipRect.y() + clipData->clipRect.height()
};
surface->SetClip(surface, &r);
+ currentClip = clipData->clipRect.normalized();
+ // ### is this guaranteed to always be normalized?
dfbHandledClip = true;
} else if (clipData->hasRegionClip && ignoreSystemClip && clipData->clipRegion == systemClip) {
dfbHandledClip = true;
diff --git a/src/plugins/kbddrivers/sl5000/main.cpp b/src/plugins/kbddrivers/sl5000/main.cpp
index 4d61266..cc68747 100644
--- a/src/plugins/kbddrivers/sl5000/main.cpp
+++ b/src/plugins/kbddrivers/sl5000/main.cpp
@@ -66,10 +66,9 @@ QStringList QSL5000KbdDriver::keys() const
QWSKeyboardHandler* QSL5000KbdDriver::create(const QString &driver,
const QString &device)
{
- Q_UNUSED(device);
if (driver.compare(QLatin1String("SL5000"), Qt::CaseInsensitive))
return 0;
- return new QWSSL5000KeyboardHandler(driver);
+ return new QWSSL5000KeyboardHandler(device);
}
Q_EXPORT_PLUGIN2(qwssl5000kbddriver, QSL5000KbdDriver)
diff --git a/src/plugins/kbddrivers/vr41xx/main.cpp b/src/plugins/kbddrivers/vr41xx/main.cpp
index 2cba1f7..c9ba4d7 100644
--- a/src/plugins/kbddrivers/vr41xx/main.cpp
+++ b/src/plugins/kbddrivers/vr41xx/main.cpp
@@ -66,10 +66,9 @@ QStringList QVr41xxKbdDriver::keys() const
QWSKeyboardHandler* QVr41xxKbdDriver::create(const QString &driver,
const QString &device)
{
- Q_UNUSED(device);
if (driver.compare(QLatin1String("VR41xx"), Qt::CaseInsensitive))
return 0;
- return new QWSVr41xxKeyboardHandler(driver);
+ return new QWSVr41xxKeyboardHandler(device);
}
Q_EXPORT_PLUGIN2(qwsvr41xxkbddriver, QVr41xxKbdDriver)
diff --git a/src/plugins/kbddrivers/yopy/main.cpp b/src/plugins/kbddrivers/yopy/main.cpp
index bfddabe..7079d88 100644
--- a/src/plugins/kbddrivers/yopy/main.cpp
+++ b/src/plugins/kbddrivers/yopy/main.cpp
@@ -66,10 +66,9 @@ QStringList QYopyKbdDriver::keys() const
QWSKeyboardHandler* QYopyKbdDriver::create(const QString &driver,
const QString &device)
{
- Q_UNUSED(device);
if (driver.compare(QLatin1String("Yopy"), Qt::CaseInsensitive))
return 0;
- return new QWSYopyKeyboardHandler(driver);
+ return new QWSYopyKeyboardHandler(device);
}
Q_EXPORT_PLUGIN2(qwsyopykbddriver, QYopyKbdDriver)
diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp
index 979eeec..617f116 100644
--- a/src/sql/drivers/oci/qsql_oci.cpp
+++ b/src/sql/drivers/oci/qsql_oci.cpp
@@ -609,7 +609,7 @@ static QSqlField qFromOraInf(const OraFieldInfo &ofi)
QSqlField f(ofi.name, ofi.type);
f.setRequired(ofi.oraIsNull == 0);
- if (ofi.type == QVariant::String)
+ if (ofi.type == QVariant::String && ofi.oraType != SQLT_NUM && ofi.oraType != SQLT_VNU)
f.setLength(ofi.oraFieldLength);
else
f.setLength(ofi.oraPrecision == 0 ? 38 : int(ofi.oraPrecision));
diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp
index 50defdf..fa9031a 100644
--- a/src/sql/drivers/odbc/qsql_odbc.cpp
+++ b/src/sql/drivers/odbc/qsql_odbc.cpp
@@ -89,7 +89,8 @@ public:
enum DefaultCase{Lower, Mixed, Upper, Sensitive};
QODBCDriverPrivate()
: hEnv(0), hDbc(0), useSchema(false), disconnectCount(0), isMySqlServer(false),
- isMSSqlServer(false), hasSQLFetchScroll(true), hasMultiResultSets(false)
+ isMSSqlServer(false), hasSQLFetchScroll(true), hasMultiResultSets(false),
+ isQuoteInitialized(false), quote(QLatin1Char('"'))
{
unicode = false;
}
@@ -116,7 +117,10 @@ public:
QString &schema, QString &table);
DefaultCase defaultCase() const;
QString adjustCase(const QString&) const;
- QChar quoteChar() const;
+ QChar quoteChar();
+private:
+ bool isQuoteInitialized;
+ QChar quote;
};
class QODBCPrivate
@@ -566,10 +570,8 @@ static int qGetODBCVersion(const QString &connOpts)
return SQL_OV_ODBC2;
}
-QChar QODBCDriverPrivate::quoteChar() const
+QChar QODBCDriverPrivate::quoteChar()
{
- static bool isQuoteInitialized = false;
- static QChar quote = QChar::fromLatin1('"');
if (!isQuoteInitialized) {
char driverResponse[4];
SQLSMALLINT length;
@@ -579,9 +581,9 @@ QChar QODBCDriverPrivate::quoteChar() const
sizeof(driverResponse),
&length);
if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- quote = QChar::fromLatin1(driverResponse[0]);
+ quote = QLatin1Char(driverResponse[0]);
} else {
- quote = QChar::fromLatin1('"');
+ quote = QLatin1Char('"');
}
isQuoteInitialized = true;
}
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp
index 0c92013..c61c526 100644
--- a/src/sql/drivers/psql/qsql_psql.cpp
+++ b/src/sql/drivers/psql/qsql_psql.cpp
@@ -54,11 +54,33 @@
#include <qstringlist.h>
#include <qmutex.h>
+
#include <libpq-fe.h>
#include <pg_config.h>
#include <stdlib.h>
#include <math.h>
+// below code taken from an example at http://www.gnu.org/software/hello/manual/autoconf/Function-Portability.html
+#ifndef isnan
+ # define isnan(x) \
+ (sizeof (x) == sizeof (long double) ? isnan_ld (x) \
+ : sizeof (x) == sizeof (double) ? isnan_d (x) \
+ : isnan_f (x))
+ static inline int isnan_f (float x) { return x != x; }
+ static inline int isnan_d (double x) { return x != x; }
+ static inline int isnan_ld (long double x) { return x != x; }
+#endif
+
+#ifndef isinf
+ # define isinf(x) \
+ (sizeof (x) == sizeof (long double) ? isinf_ld (x) \
+ : sizeof (x) == sizeof (double) ? isinf_d (x) \
+ : isinf_f (x))
+ static inline int isinf_f (float x) { return isnan (x - x); }
+ static inline int isinf_d (double x) { return isnan (x - x); }
+ static inline int isinf_ld (long double x) { return isnan (x - x); }
+#endif
+
// workaround for postgres defining their OIDs in a private header file
#define QBOOLOID 16
@@ -601,10 +623,9 @@ static QPSQLDriver::Protocol getPSQLVersion(PGconn* connection)
{
QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6;
PGresult* result = PQexec(connection, "select version()");
- int status = PQresultStatus(result);
+ int status = PQresultStatus(result);
if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) {
QString val = QString::fromAscii(PQgetvalue(result, 0, 0));
- PQclear(result);
QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)"));
rx.setMinimal(true); // enforce non-greedy RegExp
if (rx.indexIn(val) != -1) {
@@ -645,6 +666,7 @@ static QPSQLDriver::Protocol getPSQLVersion(PGconn* connection)
}
}
}
+ PQclear(result);
if (serverVersion < QPSQLDriver::Version71)
qWarning("This version of PostgreSQL is not supported and may not work.");
@@ -1161,6 +1183,21 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
qPQfreemem(data);
break;
}
+ case QVariant::Double: {
+ double val = field.value().toDouble();
+ if (isnan(val))
+ r = QLatin1String("'NaN'");
+ else {
+ int res = isinf(val);
+ if (res == 1)
+ r = QLatin1String("'Infinity'");
+ else if (res == -1)
+ r = QLatin1String("'-Infinity'");
+ else
+ r = QSqlDriver::formatValue(field, trimStrings);
+ }
+ break;
+ }
default:
r = QSqlDriver::formatValue(field, trimStrings);
break;
@@ -1265,15 +1302,15 @@ QStringList QPSQLDriver::subscribedToNotificationsImplementation() const
void QPSQLDriver::_q_handleNotification(int)
{
PQconsumeInput(d->connection);
- PGnotify *notify = PQnotifies(d->connection);
- if (notify) {
- QString name(QLatin1String(notify->relname));
+ PGnotify *notify = 0;
+ while((notify = PQnotifies(d->connection)) != 0) {
+ QString name(QLatin1String(notify->relname));
if (d->seid.contains(name))
emit notification(name);
else
qWarning("QPSQLDriver: received notification for '%s' which isn't subscribed to.",
- qPrintable(name));
+ qPrintable(name));
qPQfreemem(notify);
}
diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp
index 156af26..4315a8c 100644
--- a/src/sql/models/qsqltablemodel.cpp
+++ b/src/sql/models/qsqltablemodel.cpp
@@ -205,7 +205,7 @@ bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement,
editQuery.addBindValue(rec.value(i));
}
for (i = 0; i < whereValues.count(); ++i) {
- if (whereValues.isGenerated(i))
+ if (whereValues.isGenerated(i) && !whereValues.isNull(i))
editQuery.addBindValue(whereValues.value(i));
}
@@ -538,6 +538,7 @@ bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, in
isOk = updateRowInTable(index.row(), d->editBuffer);
if (isOk)
select();
+ emit dataChanged(index, index);
break; }
case OnRowChange:
if (index.row() == d->insertIndex) {
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index 5950fac..5f9d1dd 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -68,6 +68,7 @@
QT_BEGIN_NAMESPACE
+
double qstrtod(const char *s00, char const **se, bool *ok);
static bool parsePathDataFast(const QStringRef &data, QPainterPath &path);
@@ -320,6 +321,7 @@ static qreal toDouble(const QChar *&str)
++str;
}
}
+
temp[pos] = '\0';
qreal val;
@@ -365,16 +367,24 @@ static qreal toDouble(const QChar *&str)
return val;
}
-static qreal toDouble(const QString &str)
+static qreal toDouble(const QString &str, bool *ok = NULL)
{
const QChar *c = str.constData();
- return toDouble(c);
+ qreal res = toDouble(c);
+ if (ok) {
+ *ok = ((*c) == QLatin1Char('\0'));
+ }
+ return res;
}
-static qreal toDouble(const QStringRef &str)
+static qreal toDouble(const QStringRef &str, bool *ok = NULL)
{
const QChar *c = str.constData();
- return toDouble(c);
+ qreal res = toDouble(c);
+ if (ok) {
+ *ok = (c == (str.constData() + str.length()));
+ }
+ return res;
}
static QVector<qreal> parseNumbersList(const QChar *&str)
@@ -497,14 +507,17 @@ static bool constructColor(const QString &colorStr, const QString &opacity,
if (!resolveColor(colorStr, color, handler))
return false;
if (!opacity.isEmpty()) {
- qreal op = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity)));
+ bool ok = true;
+ qreal op = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity, &ok)));
+ if (!ok)
+ op = 1.0;
color.setAlphaF(op);
}
return true;
}
static qreal parseLength(const QString &str, QSvgHandler::LengthType &type,
- QSvgHandler *handler)
+ QSvgHandler *handler, bool *ok = NULL)
{
QString numStr = str.trimmed();
@@ -533,15 +546,15 @@ static qreal parseLength(const QString &str, QSvgHandler::LengthType &type,
type = handler->defaultCoordinateSystem();
//type = QSvgHandler::LT_OTHER;
}
- qreal len = toDouble(numStr);
+ qreal len = toDouble(numStr, ok);
//qDebug()<<"len is "<<len<<", from '"<<numStr << "'";
return len;
}
-static inline qreal convertToNumber(const QString &str, QSvgHandler *handler)
+static inline qreal convertToNumber(const QString &str, QSvgHandler *handler, bool *ok = NULL)
{
QSvgHandler::LengthType type;
- qreal num = parseLength(str, type, handler);
+ qreal num = parseLength(str, type, handler, ok);
if (type == QSvgHandler::LT_PERCENT) {
num = num/100.0;
}
@@ -631,15 +644,32 @@ static void parseBrush(QSvgNode *node,
QString opacity = attributes.value(QLatin1String("fill-opacity")).toString();
QString myId = someId(attributes);
- value = value.trimmed();
- fillRule = fillRule.trimmed();
- if (!value.isEmpty() || !fillRule.isEmpty()) {
- Qt::FillRule f = Qt::WindingFill;
+ QSvgFillStyle *inherited =
+ static_cast<QSvgFillStyle*>(node->parent()->styleProperty(
+ QSvgStyleProperty::FILL));
+ QSvgFillStyle *prop = new QSvgFillStyle(QColor(Qt::black));
+
+ //fill-rule attribute handling
+ Qt::FillRule f = Qt::WindingFill;
+ if (!fillRule.isEmpty() && fillRule != QLatin1String("inherit")) {
if (fillRule == QLatin1String("evenodd"))
f = Qt::OddEvenFill;
+ } else if (inherited) {
+ f = inherited->fillRule();
+ }
+
+ //fill-opacity atttribute handling
+ qreal fillOpacity = 1.0;
+ if (!opacity.isEmpty() && opacity != QLatin1String("inherit")) {
+ fillOpacity = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity)));
+ } else if (inherited) {
+ fillOpacity = inherited->fillOpacity();
+ }
+
+ //fill attribute handling
+ if ((!value.isEmpty()) && (value != QLatin1String("inherit")) ) {
if (value.startsWith(QLatin1String("url"))) {
value = value.remove(0, 3);
- QSvgFillStyle *prop = new QSvgFillStyle(0);
QSvgStyleProperty *style = styleFromUrl(node, value);
if (style) {
prop->setFillStyle(style);
@@ -648,30 +678,26 @@ static void parseBrush(QSvgNode *node,
prop->setGradientId(id);
prop->setGradientResolved(false);
}
- if (!opacity.isEmpty()) {
- qreal clampedOpacity = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity)));
- prop->setFillOpacity(clampedOpacity);
- }
- if (!fillRule.isEmpty())
- prop->setFillRule(f);
- node->appendStyleProperty(prop,myId);
} else if (value != QLatin1String("none")) {
QColor color;
- if (constructColor(value, opacity, color, handler)) {
- QSvgFillStyle *prop = new QSvgFillStyle(QBrush(color));
- if (!fillRule.isEmpty())
- prop->setFillRule(f);
- node->appendStyleProperty(prop, myId);
- }
+ if (resolveColor(value, color, handler))
+ prop->setBrush(QBrush(color));
} else {
- QSvgFillStyle *prop = new QSvgFillStyle(QBrush(Qt::NoBrush));
- if (!fillRule.isEmpty())
- prop->setFillRule(f);
- node->appendStyleProperty(prop, myId);
+ prop->setBrush(QBrush(Qt::NoBrush));
+ }
+ } else if (inherited) {
+ if (inherited->style()) {
+ prop->setFillStyle(inherited->style());
+ } else {
+ prop->setBrush(inherited->qbrush());
}
}
+ prop->setFillOpacity(fillOpacity);
+ prop->setFillRule(f);
+ node->appendStyleProperty(prop,myId);
}
+
static void parseQPen(QPen &pen, QSvgNode *node,
const QSvgAttributes &attributes,
QSvgHandler *handler)
@@ -3006,7 +3032,11 @@ static bool parseStopNode(QSvgStyleProperty *parent,
QString colorStr = attrs.value(QString(), QLatin1String("stop-color")).toString();
QString opacityStr = attrs.value(QString(), QLatin1String("stop-opacity")).toString();
QColor color;
- qreal offset = convertToNumber(offsetStr, handler);
+
+ bool ok = true;
+ qreal offset = convertToNumber(offsetStr, handler, &ok);
+ if (!ok)
+ offset = 0.0;
if (colorStr.isEmpty()) {
colorStr = QLatin1String("#000000");
}
@@ -3095,12 +3125,16 @@ static QSvgNode *createSvgNode(QSvgNode *parent,
QStringList lst = viewBoxStr.split(QLatin1Char(' '), QString::SkipEmptyParts);
if (lst.count() != 4)
lst = viewBoxStr.split(QLatin1Char(','), QString::SkipEmptyParts);
+ int count = lst.count();
+ while (count < 4) {
+ lst.append(QLatin1String(""));
+ count++;
+ }
QString xStr = lst.at(0).trimmed();
QString yStr = lst.at(1).trimmed();
QString widthStr = lst.at(2).trimmed();
QString heightStr = lst.at(3).trimmed();
-
QSvgHandler::LengthType lt;
qreal x = parseLength(xStr, lt, handler);
qreal y = parseLength(yStr, lt, handler);
@@ -3108,15 +3142,14 @@ static QSvgNode *createSvgNode(QSvgNode *parent,
qreal h = parseLength(heightStr, lt, handler);
node->setViewBox(QRectF(x, y, w, h));
- } else if (width && height){
+
+ } else if (width && height) {
if (type == QSvgHandler::LT_PT) {
width = convertToPixels(width, false, type);
height = convertToPixels(height, false, type);
}
-
node->setViewBox(QRectF(0, 0, width, height));
}
-
handler->setDefaultCoordinateSystem(QSvgHandler::LT_PX);
return node;
diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp
index 556201b..4c8247b 100644
--- a/src/svg/qsvgstyle.cpp
+++ b/src/svg/qsvgstyle.cpp
@@ -81,12 +81,12 @@ void QSvgQualityStyle::revert(QPainter *, QSvgExtraStates &)
}
QSvgFillStyle::QSvgFillStyle(const QBrush &brush)
- : m_fill(brush), m_style(0), m_fillRuleSet(false), m_fillOpacitySet(false), m_gradientResolved (true)
+ : m_fill(brush), m_style(0), m_fillRuleSet(false), m_fillOpacitySet(false), m_fillRule(Qt::WindingFill), m_fillOpacity(1.0), m_gradientResolved (true)
{
}
QSvgFillStyle::QSvgFillStyle(QSvgStyleProperty *style)
- : m_style(style), m_fillRuleSet(false), m_fillOpacitySet(false), m_gradientResolved (true)
+ : m_style(style), m_fillRuleSet(false), m_fillOpacitySet(false), m_fillRule(Qt::WindingFill), m_fillOpacity(1.0), m_gradientResolved (true)
{
}
@@ -102,6 +102,16 @@ void QSvgFillStyle::setFillOpacity(qreal opacity)
m_fillOpacity = opacity;
}
+void QSvgFillStyle::setFillStyle(QSvgStyleProperty* style)
+{
+ m_style = style;
+}
+
+void QSvgFillStyle::setBrush(QBrush brush)
+{
+ m_fill = brush;
+}
+
static void recursivelySetFill(QSvgNode *node, Qt::FillRule f)
{
if (node->type() == QSvgNode::PATH) {
diff --git a/src/svg/qsvgstyle_p.h b/src/svg/qsvgstyle_p.h
index f1d0811..ac5e109 100644
--- a/src/svg/qsvgstyle_p.h
+++ b/src/svg/qsvgstyle_p.h
@@ -224,12 +224,29 @@ public:
void setFillRule(Qt::FillRule f);
void setFillOpacity(qreal opacity);
+ void setFillStyle(QSvgStyleProperty* style);
+ void setBrush(QBrush brush);
const QBrush & qbrush() const
{
return m_fill;
}
+ qreal fillOpacity() const
+ {
+ return m_fillOpacity;
+ }
+
+ Qt::FillRule fillRule() const
+ {
+ return m_fillRule;
+ }
+
+ QSvgStyleProperty* style() const
+ {
+ return m_style;
+ }
+
void setGradientId(const QString &Id)
{
m_gradientId = Id;
@@ -240,7 +257,6 @@ public:
return m_gradientId;
}
-
void setGradientResolved(bool resolved)
{
m_gradientResolved = resolved;
@@ -251,16 +267,6 @@ public:
return m_gradientResolved;
}
- void setFillStyle(QSvgStyleProperty* style)
- {
- m_style = style;
- }
-
- void setBrush(QBrush brush)
- {
- m_fill = brush;
- }
-
private:
// fill v v 'inherit' | <Paint.datatype>
// fill-opacity v v 'inherit' | <OpacityValue.datatype>