diff options
author | David Boddie <dboddie@trolltech.com> | 2009-07-13 11:49:08 (GMT) |
---|---|---|
committer | David Boddie <dboddie@trolltech.com> | 2009-07-13 11:49:08 (GMT) |
commit | 821c7c1486beb6d5e65bd3ac8ba74752fec37fe8 (patch) | |
tree | 042ad778ccdfacd2dc1b4751a98e83889e5e10e3 | |
parent | 85fbffa12bcd38b08030561335305c3226312bc6 (diff) | |
parent | cc24c46c117248ecb98200416e7f25375e6bb476 (diff) | |
download | Qt-821c7c1486beb6d5e65bd3ac8ba74752fec37fe8.zip Qt-821c7c1486beb6d5e65bd3ac8ba74752fec37fe8.tar.gz Qt-821c7c1486beb6d5e65bd3ac8ba74752fec37fe8.tar.bz2 |
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt
189 files changed, 7298 insertions, 3018 deletions
@@ -6256,7 +6256,6 @@ esac # debug release # dll staticlib # -# internal # nocrosscompiler # GNUmake # largefile @@ -6736,6 +6735,9 @@ fi if [ "$PLATFORM_MAC" = "yes" ]; then QT_CONFIG="$QT_CONFIG $CFG_MAC_ARCHS" fi +if [ "$CFG_DEV" = "yes" ]; then + QT_CONFIG="$QT_CONFIG private_tests" +fi # Make the application arch follow the Qt arch for single arch builds. # (for multiple-arch builds, set CONFIG manually in the application .pro file) diff --git a/configure.exe b/configure.exe Binary files differindex a139116..10b926e 100644 --- a/configure.exe +++ b/configure.exe diff --git a/doc/src/dnd.qdoc b/doc/src/dnd.qdoc index b5039f6..5ede20c 100644 --- a/doc/src/dnd.qdoc +++ b/doc/src/dnd.qdoc @@ -141,15 +141,17 @@ types of data that the widget accepts. You must reimplement this function if you want to receive either QDragMoveEvent or QDropEvent in your reimplementations of - \l{QWidget::dragMoveEvent()}{dragMoveEvent()} and dropEvent(). + \l{QWidget::dragMoveEvent()}{dragMoveEvent()} and + \l{QWidget::dropEvent()}{dropEvent()}. - The following code shows how dragEnterEvent() can be reimplemented to + The following code shows how \l{QWidget::dragEnterEvent()}{dragEnterEvent()} + can be reimplemented to tell the drag and drop system that we can only handle plain text: \snippet doc/src/snippets/dropevents/window.cpp 3 - The dropEvent() is used to unpack dropped data and handle it in way that - is suitable for your application. + The \l{QWidget::dropEvent()}{dropEvent()} is used to unpack dropped data + and handle it in way that is suitable for your application. In the following code, the text supplied in the event is passed to a QTextBrowser and a QComboBox is filled with the list of MIME types that @@ -159,7 +161,8 @@ In this case, we accept the proposed action without checking what it is. In a real world application, it may be necessary to return from the - dropEvent() function without accepting the proposed action or handling + \l{QWidget::dropEvent()}{dropEvent()} function without accepting the + proposed action or handling the data if the action is not relevant. For example, we may choose to ignore Qt::LinkAction actions if we do not support links to external sources in our application. diff --git a/doc/src/qnamespace.qdoc b/doc/src/qnamespace.qdoc index d509912..ded1577 100644 --- a/doc/src/qnamespace.qdoc +++ b/doc/src/qnamespace.qdoc @@ -1247,8 +1247,9 @@ /*! \typedef Qt::HANDLE Platform-specific handle type for system objects. This is - equivalent to \c{void *} on Windows and Mac OS X, and embedded - Linux, and to \c{unsigned long} on X11. + equivalent to \c{void *} on Mac OS X and embedded Linux, + and to \c{unsigned long} on X11. On Windows it is the + DWORD returned by the Win32 function getCurrentThreadId(). \warning Using this type is not portable. */ diff --git a/doc/src/threads.qdoc b/doc/src/threads.qdoc index 9f7f857..8469f51 100644 --- a/doc/src/threads.qdoc +++ b/doc/src/threads.qdoc @@ -262,48 +262,41 @@ \keyword thread-safe \section1 Reentrancy and Thread-Safety - Throughout the Qt documentation, the terms \e reentrant and \e - thread-safe are used to specify how a function can be used in - multithreaded applications: + Throughout the documentation, the terms \e{reentrant} and + \e{thread-safe} are used to mark classes and functions to indicate + how they can be used in multithread applications: \list - \o A \e reentrant function can be called simultaneously by - multiple threads provided that each invocation of the function - references unique data. - \o A \e thread-safe function can be called simultaneously by - multiple threads when each invocation references shared data. - All access to the shared data is serialized. + \o A \e thread-safe function can be called simultaneously from + multiple threads, even when the invocations use shared data, + because all references to the shared data are serialized. + \o A \e reentrant function can also be called simultaneously from + multiple threads, but only if each invocation uses its own data. \endlist - By extension, a class is said to be reentrant if each and every - one of its functions can be called simultaneously by multiple - threads on different instances of the class. Similarly, the class - is said to be thread-safe if the functions can be called by - different threads on the same instance. + Hence, a \e{thread-safe} function is always \e{reentrant}, but a + \e{reentrant} function is not always \e{thread-safe}. - Classes in the documentation will be documented as thread-safe only - if they are intended to be used by multiple threads. + By extension, a class is said to be \e{reentrant} if its member + functions can be called safely from multiple threads, as long as + each thread uses a \e{different} instance of the class. The class + is \e{thread-safe} if its member functions can be called safely + from multiple threads, even if all the threads use the \e{same} + instance of the class. - Note that the terminology in this domain isn't entirely - standardized. POSIX uses a somewhat different definition of - reentrancy and thread-safety for its C APIs. When dealing with an - object-oriented C++ class library such as Qt, the definitions - must be adapted. - - Most C++ classes are inherently reentrant, since they typically - only reference member data. Any thread can call such a member - function on an instance of the class, as long as no other thread - is calling a member function on the same instance. For example, - the \c Counter class below is reentrant: + C++ classes are often reentrant, simply because they only access + their own member data. Any thread can call a member function on an + instance of a reentrant class, as long as no other thread can call + a member function on the \e{same} instance of the class at the + same time. For example, the \c Counter class below is reentrant: \snippet doc/src/snippets/threads/threads.cpp 3 \snippet doc/src/snippets/threads/threads.cpp 4 The class isn't thread-safe, because if multiple threads try to modify the data member \c n, the result is undefined. This is - because C++'s \c ++ and \c -- operators aren't necessarily - atomic. Indeed, they usually expand to three machine - instructions: + because the \c ++ and \c -- operators aren't always atomic. + Indeed, they usually expand to three machine instructions: \list 1 \o Load the variable's value in a register. @@ -332,14 +325,27 @@ declared with the \c mutable qualifier because we need to lock and unlock the mutex in \c value(), which is a const function. - Most Qt classes are reentrant and not thread-safe, to avoid the - overhead of repeatedly locking and unlocking a QMutex. For - example, QString is reentrant, meaning that you can use it in - different threads, but you can't access the same QString object - from different threads simultaneously (unless you protect it with - a mutex yourself). A few classes and functions are thread-safe; - these are mainly thread-related classes such as QMutex, or - fundamental functions such as QCoreApplication::postEvent(). + Many Qt classes are \e{reentrant}, but they are not made + \e{thread-safe}, because making them thread-safe would incur the + extra overhead of repeatedly locking and unlocking a QMutex. For + example, QString is reentrant but not thread-safe. You can safely + access \e{different} instances of QString from multiple threads + simultaneously, but you can't safely access the \e{same} instance + of QString from multiple threads simultaneously (unless you + protect the accesses yourself with a QMutex). + + Some Qt classes and functions are thread-safe. These are mainly + the thread-related classes (e.g. QMutex) and fundamental functions + (e.g. QCoreApplication::postEvent()). + + \note Qt Classes are only documented as \e{thread-safe} if they + are intended to be used by multiple threads. + + \note Terminology in the multithreading domain isn't entirely + standardized. POSIX uses definitions of reentrant and thread-safe + that are somewhat different for its C APIs. When using other + object-oriented C++ class libraries with Qt, be sure the + definitions are understood. \section1 Threads and QObjects 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 ®ion); 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 ¤t = 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 ¤t, 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 ¤t, 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 ¤t) + { 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> diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 9924904..f94d428 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -150,6 +150,7 @@ SUBDIRS += _networkselftest \ qgraphicspolygonitem \ qgraphicsproxywidget \ qgraphicsscene \ + qgraphicssceneindex \ qgraphicsview \ qgraphicswidget \ qgridlayout \ diff --git a/tests/auto/linguist/lconvert/data/makeplurals.pl b/tests/auto/linguist/lconvert/data/makeplurals.pl new file mode 100755 index 0000000..19bffe0 --- /dev/null +++ b/tests/auto/linguist/lconvert/data/makeplurals.pl @@ -0,0 +1,42 @@ +#! /usr/bin/env perl + +sub makeit2($$$) +{ + for (my $i = 0; $i < (1 << $_[0]); $i++) { + print OUTFILE "\n"; + print OUTFILE "$_[2]\n" unless $3 eq ""; + print OUTFILE "msgid \"singular $_[1] $i\"\n"; + print OUTFILE "msgid_plural \"plural $_[1] $i\"\n"; + for (my $j = 0; $j < $_[0]; $j++) { + my $tr; + if (($i & (1 << $j)) == 0) { + $tr = "translated $_[1] $i $j"; + } + print OUTFILE "msgstr[$j] \"$tr\"\n"; + } + } +} + +sub makeit($$) +{ + open OUTFILE, ">${OUTDIR}plural-$_[0].po" || die "cannot write file in $OUTDIR"; + print OUTFILE <<EOF; +msgid "" +msgstr "" +"X-FooBar: yup\\n" +"X-Language: $_[1]\\n" +EOF + makeit2($_[0], "one", ""); + makeit2($_[0], "two", "#, fuzzy +#| msgid \"old untranslated one\""); + makeit2($_[0], "three", "#, fuzzy +#| msgid \"old untranslated two\" +#| msgid_plural \"old untranslated plural two\""); + makeit2($_[0], "four", "#, fuzzy +#| msgid_plural \"old untranslated only plural three\""); +} + +$OUTDIR = $ARGV[0]; +makeit(1, "zh_CN"); +makeit(2, "de_DE"); +makeit(3, "pl_PL"); diff --git a/tests/auto/linguist/lconvert/data/makeplurals.sh b/tests/auto/linguist/lconvert/data/makeplurals.sh deleted file mode 100755 index 2e0f375..0000000 --- a/tests/auto/linguist/lconvert/data/makeplurals.sh +++ /dev/null @@ -1,43 +0,0 @@ -#! /bin/bash - -function makeit2() -{ - for ((i = 0; i < (1 << $1); i++)); do - echo - test -n "$3" && echo "$3" - echo "msgid \"singular $2 $i\"" - echo "msgid_plural \"plural $2 $i\"" - for ((j = 0; j < $1; j++)); do - tr= - if test $((i & (1 << j))) = 0; then - tr="translated $2 $i $j" - fi - echo "msgstr[$j] \"$tr\"" - done - done -} - -function makeit() -{ - { - cat <<EOF -msgid "" -msgstr "" -"X-FooBar: yup\n" -"X-Language: $2\n" -EOF - makeit2 $1 one "" - makeit2 $1 two "#, fuzzy -#| msgid \"old untranslated one\"" - makeit2 $1 three "#, fuzzy -#| msgid \"old untranslated two\" -#| msgid_plural \"old untranslated plural two\"" - makeit2 $1 four "#, fuzzy -#| msgid_plural \"old untranslated only plural three\"" - } > ${OUTDIR}plural-$1.po -} - -OUTDIR=$1 -makeit 1 zh_CN -makeit 2 de_DE -makeit 3 pl_PL diff --git a/tests/auto/linguist/lconvert/tst_lconvert.cpp b/tests/auto/linguist/lconvert/tst_lconvert.cpp index 40be55a..1ed71ab 100644 --- a/tests/auto/linguist/lconvert/tst_lconvert.cpp +++ b/tests/auto/linguist/lconvert/tst_lconvert.cpp @@ -47,7 +47,7 @@ class tst_lconvert : public QObject Q_OBJECT public: - tst_lconvert() : dataDir("data/") {} + tst_lconvert() : dataDir("data/"), binDir(QLibraryInfo::location(QLibraryInfo::BinariesPath)) {} private slots: void initTestCase(); @@ -73,12 +73,13 @@ private: const QList<QStringList> &args); QString dataDir; + QString binDir; }; void tst_lconvert::initTestCase() { if (!QFile::exists(QLatin1String("data/plural-1.po"))) - QProcess::execute(QLatin1String("data/makeplurals.sh"), QStringList() << QLatin1String("data/")); + QProcess::execute(QLatin1String("perl"), QStringList() << QLatin1String("data/makeplurals.pl") << QLatin1String("data/")); QVERIFY(QFile::exists(QLatin1String("data/plural-1.po"))); } @@ -151,7 +152,7 @@ void tst_lconvert::doCompare(QIODevice *actualDev, const QString &expectedFn) void tst_lconvert::verifyReadFail(const QString &fn) { QProcess cvt; - cvt.start("lconvert", QStringList() << (dataDir + fn)); + cvt.start(binDir + "/lconvert", QStringList() << (dataDir + fn)); QVERIFY(cvt.waitForFinished(1000)); QVERIFY(cvt.exitStatus() == QProcess::NormalExit); QVERIFY2(cvt.exitCode() == 2, "Accepted invalid input"); @@ -178,7 +179,7 @@ void tst_lconvert::convertChain(const QString &_inFileName, const QString &_outF if (!argList.isEmpty()) args += argList[i]; args << "-if" << stations[i] << "-i" << "-" << "-of" << stations[i + 1]; - cvts.at(i)->start("lconvert", args); + cvts.at(i)->start(binDir + "/lconvert", args); } int st = 0; foreach (QProcess *cvt, cvts) @@ -242,7 +243,7 @@ void tst_lconvert::converts() QString outFileNameFq = dataDir + outFileName; QProcess cvt; - cvt.start("lconvert", QStringList() << "-i" << (dataDir + inFileName) << "-of" << format); + cvt.start(binDir + "/lconvert", QStringList() << "-i" << (dataDir + inFileName) << "-of" << format); doWait(&cvt, 0); if (QTest::currentTestFailed()) return; diff --git a/tests/auto/linguist/lrelease/tst_lrelease.cpp b/tests/auto/linguist/lrelease/tst_lrelease.cpp index ff90b3c..45e9d6b 100644 --- a/tests/auto/linguist/lrelease/tst_lrelease.cpp +++ b/tests/auto/linguist/lrelease/tst_lrelease.cpp @@ -49,6 +49,10 @@ class tst_lrelease : public QObject { Q_OBJECT + +public: + tst_lrelease() : binDir(QLibraryInfo::location(QLibraryInfo::BinariesPath)) {} + private: private slots: @@ -60,6 +64,8 @@ private slots: private: void doCompare(const QStringList &actual, const QString &expectedFn); + + QString binDir; }; void tst_lrelease::doCompare(const QStringList &actual, const QString &expectedFn) @@ -112,7 +118,7 @@ void tst_lrelease::doCompare(const QStringList &actual, const QString &expectedF void tst_lrelease::translate() { - QVERIFY(!QProcess::execute("lrelease testdata/translate.ts")); + QVERIFY(!QProcess::execute(binDir + "/lrelease testdata/translate.ts")); QTranslator translator; QVERIFY(translator.load("testdata/translate.qm")); @@ -162,8 +168,8 @@ void tst_lrelease::translate() void tst_lrelease::mixedcodecs() { - QVERIFY(!QProcess::execute("lrelease testdata/mixedcodecs-ts11.ts")); - QVERIFY(!QProcess::execute("lrelease testdata/mixedcodecs-ts20.ts")); + QVERIFY(!QProcess::execute(binDir + "/lrelease testdata/mixedcodecs-ts11.ts")); + QVERIFY(!QProcess::execute(binDir + "/lrelease testdata/mixedcodecs-ts20.ts")); QVERIFY(!QProcess::execute("cmp testdata/mixedcodecs-ts11.qm testdata/mixedcodecs-ts20.qm")); QTranslator translator; QVERIFY(translator.load("testdata/mixedcodecs-ts11.qm")); @@ -177,7 +183,7 @@ void tst_lrelease::mixedcodecs() void tst_lrelease::compressed() { - QVERIFY(!QProcess::execute("lrelease -compress testdata/compressed.ts")); + QVERIFY(!QProcess::execute(binDir + "/lrelease -compress testdata/compressed.ts")); QTranslator translator; QVERIFY(translator.load("testdata/compressed.qm")); @@ -207,7 +213,7 @@ void tst_lrelease::idbased() void tst_lrelease::dupes() { QProcess proc; - proc.start("lrelease testdata/dupes.ts"); + proc.start(binDir + "/lrelease testdata/dupes.ts"); QVERIFY(proc.waitForFinished()); QVERIFY(proc.exitStatus() == QProcess::NormalExit); doCompare(QString(proc.readAllStandardError()).trimmed().remove('\r').split('\n'), "testdata/dupes.errors"); diff --git a/tests/auto/linguist/lupdate/testlupdate.cpp b/tests/auto/linguist/lupdate/testlupdate.cpp index 8abc2b0..04c03f1 100644 --- a/tests/auto/linguist/lupdate/testlupdate.cpp +++ b/tests/auto/linguist/lupdate/testlupdate.cpp @@ -56,8 +56,9 @@ TestLUpdate::TestLUpdate() { childProc = 0; - m_cmdLupdate = QLatin1String("lupdate"); - m_cmdQMake = QLatin1String("qmake"); + QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath); + m_cmdLupdate = binPath + QLatin1String("/lupdate"); + m_cmdQMake = binPath + QLatin1String("/qmake"); } TestLUpdate::~TestLUpdate() diff --git a/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp b/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp index 7facf4a..d799c1b 100644 --- a/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp +++ b/tests/auto/math3d/qmatrixnxn/tst_qmatrixnxn.cpp @@ -172,22 +172,22 @@ private slots: private: static void setMatrix(QMatrix2x2& m, const qreal *values); - static void setMatrixFixed(QMatrix2x2& m, const qreal *values); + static void setMatrixDirect(QMatrix2x2& m, const qreal *values); static bool isSame(const QMatrix2x2& m, const qreal *values); static bool isIdentity(const QMatrix2x2& m); static void setMatrix(QMatrix3x3& m, const qreal *values); - static void setMatrixFixed(QMatrix3x3& m, const qreal *values); + static void setMatrixDirect(QMatrix3x3& m, const qreal *values); static bool isSame(const QMatrix3x3& m, const qreal *values); static bool isIdentity(const QMatrix3x3& m); static void setMatrix(QMatrix4x4& m, const qreal *values); - static void setMatrixFixed(QMatrix4x4& m, const qreal *values); + static void setMatrixDirect(QMatrix4x4& m, const qreal *values); static bool isSame(const QMatrix4x4& m, const qreal *values); static bool isIdentity(const QMatrix4x4& m); static void setMatrix(QMatrix4x3& m, const qreal *values); - static void setMatrixFixed(QMatrix4x3& m, const qreal *values); + static void setMatrixDirect(QMatrix4x3& m, const qreal *values); static bool isSame(const QMatrix4x3& m, const qreal *values); static bool isIdentity(const QMatrix4x3& m); }; @@ -321,8 +321,9 @@ void tst_QMatrix::setMatrix(QMatrix4x3& m, const qreal *values) } // Set a matrix to a specified array of values, which are assumed -// to be in row-major order. This sets the values using fixed-point. -void tst_QMatrix::setMatrixFixed(QMatrix2x2& m, const qreal *values) +// to be in row-major order. This sets the values directly into +// the internal data() array. +void tst_QMatrix::setMatrixDirect(QMatrix2x2& m, const qreal *values) { float *data = m.data(); for (int row = 0; row < 2; ++row) { @@ -331,7 +332,7 @@ void tst_QMatrix::setMatrixFixed(QMatrix2x2& m, const qreal *values) } } } -void tst_QMatrix::setMatrixFixed(QMatrix3x3& m, const qreal *values) +void tst_QMatrix::setMatrixDirect(QMatrix3x3& m, const qreal *values) { float *data = m.data(); for (int row = 0; row < 3; ++row) { @@ -340,7 +341,7 @@ void tst_QMatrix::setMatrixFixed(QMatrix3x3& m, const qreal *values) } } } -void tst_QMatrix::setMatrixFixed(QMatrix4x4& m, const qreal *values) +void tst_QMatrix::setMatrixDirect(QMatrix4x4& m, const qreal *values) { float *data = m.data(); for (int row = 0; row < 4; ++row) { @@ -349,7 +350,7 @@ void tst_QMatrix::setMatrixFixed(QMatrix4x4& m, const qreal *values) } } } -void tst_QMatrix::setMatrixFixed(QMatrix4x3& m, const qreal *values) +void tst_QMatrix::setMatrixDirect(QMatrix4x3& m, const qreal *values) { float *data = m.data(); for (int row = 0; row < 3; ++row) { @@ -359,8 +360,8 @@ void tst_QMatrix::setMatrixFixed(QMatrix4x3& m, const qreal *values) } } -// qFuzzyCompare isn't quite "fuzzy" enough to handle conversion -// to fixed-point and back again. So create "fuzzier" compares. +// qFuzzyCompare isn't always "fuzzy" enough to handle conversion +// between float, double, and qreal. So create "fuzzier" compares. static bool fuzzyCompare(float x, float y, qreal epsilon = 0.001) { float diff = x - y; @@ -511,7 +512,7 @@ void tst_QMatrix::create2x2() QVERIFY(!m2.isIdentity()); QMatrix2x2 m3; - setMatrixFixed(m3, uniqueValues2); + setMatrixDirect(m3, uniqueValues2); QVERIFY(isSame(m3, uniqueValues2)); QMatrix2x2 m4(m3); @@ -546,7 +547,7 @@ void tst_QMatrix::create3x3() QVERIFY(!m2.isIdentity()); QMatrix3x3 m3; - setMatrixFixed(m3, uniqueValues3); + setMatrixDirect(m3, uniqueValues3); QVERIFY(isSame(m3, uniqueValues3)); QMatrix3x3 m4(m3); @@ -581,7 +582,7 @@ void tst_QMatrix::create4x4() QVERIFY(!m2.isIdentity()); QMatrix4x4 m3; - setMatrixFixed(m3, uniqueValues4); + setMatrixDirect(m3, uniqueValues4); QVERIFY(isSame(m3, uniqueValues4)); QMatrix4x4 m4(m3); @@ -623,7 +624,7 @@ void tst_QMatrix::create4x3() QVERIFY(!m2.isIdentity()); QMatrix4x3 m3; - setMatrixFixed(m3, uniqueValues4x3); + setMatrixDirect(m3, uniqueValues4x3); QVERIFY(isSame(m3, uniqueValues4x3)); QMatrix4x3 m4(m3); @@ -2961,10 +2962,6 @@ void tst_QMatrix::extractTranslation() QVERIFY(fuzzyCompare(vec.y(), y, epsilon)); QVERIFY(fuzzyCompare(vec.z(), z, epsilon)); - // Have to be careful with numbers here, it is really easy to blow away - // the precision of a fixed pointer number, especially when doing distance - // formula for vector normalization - QMatrix4x4 lookAt; QVector3D eye(1.5f, -2.5f, 2.5f); lookAt.lookAt(eye, diff --git a/tests/auto/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/math3d/qquaternion/tst_qquaternion.cpp index 395032f..16b87a1 100644 --- a/tests/auto/math3d/qquaternion/tst_qquaternion.cpp +++ b/tests/auto/math3d/qquaternion/tst_qquaternion.cpp @@ -95,8 +95,8 @@ private slots: void nlerp(); }; -// qFuzzyCompare isn't quite "fuzzy" enough to handle conversion -// to fixed-point and back again. So create "fuzzier" compares. +// qFuzzyCompare isn't always "fuzzy" enough to handle conversion +// between float, double, and qreal. So create "fuzzier" compares. static bool fuzzyCompare(float x, float y) { float diff = x - y; diff --git a/tests/auto/math3d/qvectornd/tst_qvectornd.cpp b/tests/auto/math3d/qvectornd/tst_qvectornd.cpp index 0eb5b07..9c1ea83 100644 --- a/tests/auto/math3d/qvectornd/tst_qvectornd.cpp +++ b/tests/auto/math3d/qvectornd/tst_qvectornd.cpp @@ -139,8 +139,8 @@ private slots: void dotProduct4(); }; -// qFuzzyCompare isn't quite "fuzzy" enough to handle conversion -// to fixed-point and back again. So create "fuzzier" compares. +// qFuzzyCompare isn't always "fuzzy" enough to handle conversion +// between float, double, and qreal. So create "fuzzier" compares. static bool fuzzyCompare(float x, float y) { float diff = x - y; diff --git a/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp b/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp index fa786f1..0a2e46e 100644 --- a/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp +++ b/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp @@ -157,11 +157,9 @@ void tst_Q3SqlCursor::createTestTables( QSqlDatabase db ) } if (tst_Databases::isMSAccess(db)) { - QVERIFY_SQL(q, exec("create table " + qTableName("qtest_precision") + " (col1 number)")); - } else if (db.driverName().startsWith("QIBASE")) { - QVERIFY_SQL(q, exec("create table " + qTableName("qtest_precision") + " (col1 numeric(15, 14))")); + QVERIFY_SQL(q, exec("create table " + qTableName("qtest_precision") + " (col1 number)")); } else { - QVERIFY_SQL(q, exec("create table " + qTableName("qtest_precision") + " (col1 numeric(15, 14))")); + QVERIFY_SQL(q, exec("create table " + qTableName("qtest_precision") + " (col1 numeric(15, 14))")); } } @@ -557,7 +555,7 @@ void tst_Q3SqlCursor::unicode() void tst_Q3SqlCursor::precision() { - static const QString precStr = "1.23456789012345"; + static const QString precStr = QLatin1String("1.23456789012345"); static const double precDbl = 2.23456789012345; QFETCH( QString, dbName ); @@ -576,7 +574,10 @@ void tst_Q3SqlCursor::precision() QVERIFY_SQL(cur, select()); QVERIFY( cur.next() ); - QCOMPARE( cur.value( 0 ).asString(), QString( precStr ) ); + if(!tst_Databases::isSqlServer(db)) + QCOMPARE( cur.value( 0 ).asString(), precStr ); + else + QCOMPARE( cur.value( 0 ).asString(), precStr.left(precStr.size()-1) ); // Sql server fails at counting. QVERIFY( cur.next() ); QCOMPARE( cur.value( 0 ).asDouble(), precDbl ); } @@ -760,9 +761,10 @@ void tst_Q3SqlCursor::insertFieldNameContainsWS() { QSqlQuery q(db); tst_Databases::safeDropTable(db, tableName); - QString query = QString("CREATE TABLE %1 (id int, \"first Name\" varchar(20), " - "lastName varchar(20))").arg(tableName); - QVERIFY_SQL(q, exec(query)); + QString query = "CREATE TABLE %1 (id int, " + + db.driver()->escapeIdentifier("first Name", QSqlDriver::FieldName) + + " varchar(20), lastName varchar(20))"; + QVERIFY_SQL(q, exec(query.arg(tableName))); Q3SqlCursor cur(tableName, true, db); cur.select(); diff --git a/tests/auto/qcombobox/tst_qcombobox.cpp b/tests/auto/qcombobox/tst_qcombobox.cpp index c94ace0..67c9ac9 100644 --- a/tests/auto/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/qcombobox/tst_qcombobox.cpp @@ -1973,6 +1973,7 @@ void tst_QComboBox::task190351_layout() listCombo.showPopup(); QTest::qWait(100); +#ifdef QT_BUILD_INTERNAL QFrame *container = qFindChild<QComboBoxPrivateContainer *>(&listCombo); QVERIFY(container); QCOMPARE(static_cast<QAbstractItemView *>(list), qFindChild<QAbstractItemView *>(container)); @@ -1980,6 +1981,7 @@ void tst_QComboBox::task190351_layout() QVERIFY(top); QVERIFY(top->isVisible()); QCOMPARE(top->mapToGlobal(QPoint(0, top->height())).y(), list->mapToGlobal(QPoint()).y()); +#endif QApplication::setStyle(oldStyle); #else @@ -2045,6 +2047,7 @@ void tst_QComboBox::task191329_size() tableCombo.showPopup(); QTest::qWait(100); +#ifdef QT_BUILD_INTERNAL QFrame *container = qFindChild<QComboBoxPrivateContainer *>(&tableCombo); QVERIFY(container); QCOMPARE(static_cast<QAbstractItemView *>(table), qFindChild<QAbstractItemView *>(container)); @@ -2052,6 +2055,7 @@ void tst_QComboBox::task191329_size() //the popup should be large enough to contains everithing so the top and left button are hidden QVERIFY(!button->isVisible()); } +#endif QApplication::setStyle(oldStyle); #else @@ -2107,9 +2111,11 @@ void tst_QComboBox::task248169_popupWithMinimalSize() comboBox.showPopup(); QTest::qWait(100); +#ifdef QT_BUILD_INTERNAL QFrame *container = qFindChild<QComboBoxPrivateContainer *>(&comboBox); QVERIFY(container); QVERIFY(desktop.screenGeometry(container).contains(container->geometry())); +#endif } void tst_QComboBox::task247863_keyBoardSelection() diff --git a/tests/auto/qcssparser/qcssparser.pro b/tests/auto/qcssparser/qcssparser.pro index 57d6804..723e4d3 100644 --- a/tests/auto/qcssparser/qcssparser.pro +++ b/tests/auto/qcssparser/qcssparser.pro @@ -3,6 +3,7 @@ SOURCES += tst_cssparser.cpp DEFINES += SRCDIR=\\\"$$PWD\\\" QT += xml +requires(contains(QT_CONFIG,private_tests)) wince*: { addFiles.sources = testdata diff --git a/tests/auto/qfiledialog/tst_qfiledialog.cpp b/tests/auto/qfiledialog/tst_qfiledialog.cpp index e4fec1d..50cab0e 100644 --- a/tests/auto/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/qfiledialog/tst_qfiledialog.cpp @@ -160,6 +160,7 @@ private slots: void task251321_sideBarHiddenEntries(); void task251341_sideBarRemoveEntries(); void task254490_selectFileMultipleTimes(); + void task257579_sideBarWithNonCleanUrls(); private: QByteArray userSettings; @@ -231,6 +232,7 @@ void tst_QFiledialog::currentChangedSignal() // only emited from the views, sidebar, or lookin combo void tst_QFiledialog::directoryEnteredSignal() { +#if defined QT_BUILD_INTERNAL QNonNativeFileDialog fd(0, "", QDir::root().path()); fd.setOptions(QFileDialog::DontUseNativeDialog); fd.show(); @@ -274,6 +276,7 @@ void tst_QFiledialog::directoryEnteredSignal() QTest::mouseDClick(listView->viewport(), Qt::LeftButton, 0, listView->visualRect(folder).center()); QTRY_COMPARE(spyDirectoryEntered.count(), 1); */ +#endif } Q_DECLARE_METATYPE(QFileDialog::FileMode) @@ -1314,16 +1317,14 @@ void tst_QFiledialog::hooks() void tst_QFiledialog::listRoot() { +#if defined QT_BUILD_INTERNAL QFileInfoGatherer::fetchedRoot = false; QString dir(QDir::currentPath()); QNonNativeFileDialog fd(0, QString(), dir); fd.show(); -#if defined Q_AUTOTEST_EXPORT QCOMPARE(QFileInfoGatherer::fetchedRoot,false); -#endif fd.setDirectory(""); QTest::qWait(500); -#if defined Q_AUTOTEST_EXPORT QCOMPARE(QFileInfoGatherer::fetchedRoot,true); #endif } @@ -1347,6 +1348,7 @@ struct FriendlyQFileDialog : public QFileDialog void tst_QFiledialog::deleteDirAndFiles() { +#if defined QT_BUILD_INTERNAL QString tempPath = QDir::tempPath() + '/' + "QFileDialogTestDir4FullDelete"; QDir dir; QVERIFY(dir.mkpath(tempPath + "/foo")); @@ -1373,6 +1375,7 @@ void tst_QFiledialog::deleteDirAndFiles() QFileInfo info(tempPath); QTest::qWait(2000); QVERIFY(!info.exists()); +#endif } void tst_QFiledialog::filter() @@ -1583,6 +1586,7 @@ QString &dir, const QString &filter) void tst_QFiledialog::task227304_proxyOnFileDialog() { +#if defined QT_BUILD_INTERNAL QNonNativeFileDialog fd(0, "", QDir::currentPath(), 0); fd.setProxyModel(new FilterDirModel(QDir::currentPath())); fd.show(); @@ -1616,6 +1620,7 @@ void tst_QFiledialog::task227304_proxyOnFileDialog() QTest::mouseClick(sidebar->viewport(), Qt::LeftButton, 0, sidebar->visualRect(sidebar->model()->index(1, 0)).center()); QTest::qWait(250); //We shouldn't crash +#endif } void tst_QFiledialog::task227930_correctNavigationKeyboardBehavior() @@ -1727,6 +1732,7 @@ void tst_QFiledialog::task235069_hideOnEscape() void tst_QFiledialog::task236402_dontWatchDeletedDir() { +#if defined QT_BUILD_INTERNAL //THIS TEST SHOULD NOT DISPLAY WARNINGS QDir current = QDir::currentPath(); //make sure it is the first on the list @@ -1746,6 +1752,7 @@ void tst_QFiledialog::task236402_dontWatchDeletedDir() QTest::qWait(200); fd.d_func()->removeDirectory(current.absolutePath() + "/aaaaaaaaaa/"); QTest::qWait(1000); +#endif } void tst_QFiledialog::task203703_returnProperSeparator() @@ -1870,6 +1877,7 @@ void tst_QFiledialog::task218353_relativePaths() void tst_QFiledialog::task251321_sideBarHiddenEntries() { +#if defined QT_BUILD_INTERNAL QNonNativeFileDialog fd; QDir current = QDir::currentPath(); @@ -1899,8 +1907,10 @@ void tst_QFiledialog::task251321_sideBarHiddenEntries() hiddenSubDir.rmdir("happy"); hiddenDir.rmdir("subdir"); current.rmdir(".hidden"); +#endif } +#if defined QT_BUILD_INTERNAL class MyQSideBar : public QSidebar { public : @@ -1918,9 +1928,11 @@ public : model()->removeRow(indexes.at(i).row()); } }; +#endif void tst_QFiledialog::task251341_sideBarRemoveEntries() { +#if defined QT_BUILD_INTERNAL QNonNativeFileDialog fd; QDir current = QDir::currentPath(); @@ -1980,6 +1992,7 @@ void tst_QFiledialog::task251341_sideBarRemoveEntries() QCOMPARE(mySideBar.urls(), expected); current.rmdir("testDir"); +#endif } void tst_QFiledialog::task254490_selectFileMultipleTimes() @@ -2014,5 +2027,25 @@ void tst_QFiledialog::task254490_selectFileMultipleTimes() t->deleteLater(); } +void tst_QFiledialog::task257579_sideBarWithNonCleanUrls() +{ + QDir tempDir = QDir::temp(); + QLatin1String dirname("autotest_task257579"); + tempDir.rmdir(dirname); //makes sure it doesn't exist any more + QVERIFY(tempDir.mkdir(dirname)); + QString url = QString::fromLatin1("%1/%2/..").arg(tempDir.absolutePath()).arg(dirname); + QNonNativeFileDialog fd; + fd.setSidebarUrls(QList<QUrl>() << QUrl::fromLocalFile(url)); + QSidebar *sidebar = qFindChild<QSidebar*>(&fd, "sidebar"); + QCOMPARE(sidebar->urls().count(), 1); + QVERIFY(sidebar->urls().first().toLocalFile() != url); + QCOMPARE(sidebar->urls().first().toLocalFile(), QDir::cleanPath(url)); + QCOMPARE(sidebar->model()->index(0,0).data().toString(), tempDir.dirName()); + + //all tests are finished, we can remove the temporary dir + QVERIFY(tempDir.rmdir(dirname)); +} + + QTEST_MAIN(tst_QFiledialog) #include "tst_qfiledialog.moc" diff --git a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp index e415b02..d49083f 100644 --- a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -254,6 +254,7 @@ void tst_QFileSystemModel::naturalCompare_data() void tst_QFileSystemModel::naturalCompare() { +#ifdef QT_BUILD_INTERNAL QFETCH(QString, s1); QFETCH(QString, s2); QFETCH(int, caseSensitive); @@ -271,6 +272,7 @@ void tst_QFileSystemModel::naturalCompare() // created. The scheduler takes its time to recognize ended threads. QTest::qWait(300); #endif +#endif } void tst_QFileSystemModel::readOnly() diff --git a/tests/auto/qflags/tst_qflags.cpp b/tests/auto/qflags/tst_qflags.cpp index a5f68dc..87d8258 100644 --- a/tests/auto/qflags/tst_qflags.cpp +++ b/tests/auto/qflags/tst_qflags.cpp @@ -45,6 +45,7 @@ class tst_QFlags: public QObject Q_OBJECT private slots: void testFlag() const; + void testFlagZeroFlag() const; void testFlagMultiBits() const; }; @@ -59,8 +60,31 @@ void tst_QFlags::testFlag() const QVERIFY(!btn.testFlag(Qt::LeftButton)); } +void tst_QFlags::testFlagZeroFlag() const +{ + { + Qt::MouseButtons btn = Qt::LeftButton | Qt::RightButton; + /* Qt::NoButton has the value 0. */ + + QVERIFY(!btn.testFlag(Qt::NoButton)); + } + + { + /* A zero enum set should test true with zero. */ + QVERIFY(Qt::MouseButtons().testFlag(Qt::NoButton)); + } + + { + Qt::MouseButtons btn = Qt::NoButton; + QVERIFY(btn.testFlag(Qt::NoButton)); + } +} + void tst_QFlags::testFlagMultiBits() const { + /* Qt::Window is 0x00000001 + * Qt::Dialog is 0x00000002 | Window + */ { const Qt::WindowFlags onlyWindow(Qt::Window); QVERIFY(!onlyWindow.testFlag(Qt::Dialog)); diff --git a/tests/auto/qfontdialog/tst_qfontdialog.cpp b/tests/auto/qfontdialog/tst_qfontdialog.cpp index 5f1797b..cbdd440 100644 --- a/tests/auto/qfontdialog/tst_qfontdialog.cpp +++ b/tests/auto/qfontdialog/tst_qfontdialog.cpp @@ -170,8 +170,12 @@ void tst_QFontDialog::task256466_wrongStyle() for (int i = 0; i < familyList->model()->rowCount(); ++i) { QModelIndex currentFamily = familyList->model()->index(i, 0); familyList->setCurrentIndex(currentFamily); - QCOMPARE(dialog.currentFont(), fdb.font(currentFamily.data().toString(), - styleList->currentIndex().data().toString(), sizeList->currentIndex().data().toInt())); + const QFont current = dialog.currentFont(), + expected = fdb.font(currentFamily.data().toString(), + styleList->currentIndex().data().toString(), sizeList->currentIndex().data().toInt()); + QCOMPARE(current.family(), expected.family()); + QCOMPARE(current.style(), expected.style()); + QCOMPARE(current.pointSizeF(), expected.pointSizeF()); } } diff --git a/tests/auto/qgl/qgl.pro b/tests/auto/qgl/qgl.pro index 55e329d..420c4bb 100644 --- a/tests/auto/qgl/qgl.pro +++ b/tests/auto/qgl/qgl.pro @@ -3,7 +3,8 @@ ############################################################ load(qttest_p4) -contains(QT_CONFIG, opengl):QT += opengl +requires(contains(QT_CONFIG,opengl)) +QT += opengl SOURCES += tst_qgl.cpp diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp index 078c559..96f5ddd 100644 --- a/tests/auto/qgl/tst_qgl.cpp +++ b/tests/auto/qgl/tst_qgl.cpp @@ -44,9 +44,7 @@ #include <qcoreapplication.h> #include <qdebug.h> -#ifndef QT_NO_OPENGL #include <qgl.h> -#endif #include <QGraphicsView> #include <QGraphicsProxyWidget> @@ -78,7 +76,6 @@ tst_QGL::~tst_QGL() { } -#ifndef QT_NO_OPENGL class MyGLContext : public QGLContext { public: @@ -96,13 +93,10 @@ public: bool autoBufferSwap() const { return QGLWidget::autoBufferSwap(); } void setAutoBufferSwap(bool on) { QGLWidget::setAutoBufferSwap(on); } }; -#endif + // Testing get/set functions void tst_QGL::getSetCheck() { -#ifdef QT_NO_OPENGL - QSKIP("QGL not yet supported", SkipAll); -#else if (!QGLFormat::hasOpenGL()) QSKIP("QGL not supported on this platform", SkipAll); @@ -246,10 +240,9 @@ void tst_QGL::getSetCheck() QCOMPARE(false, obj3.autoBufferSwap()); obj3.setAutoBufferSwap(true); QCOMPARE(true, obj3.autoBufferSwap()); -#endif } -#ifndef QT_NO_OPENGL +#ifdef QT_BUILD_INTERNAL QT_BEGIN_NAMESPACE extern QGLFormat::OpenGLVersionFlags qOpenGLVersionFlagsFromString(const QString &versionString); QT_END_NAMESPACE @@ -257,9 +250,7 @@ QT_END_NAMESPACE void tst_QGL::openGLVersionCheck() { -#ifdef QT_NO_OPENGL - QSKIP("QGL not yet supported", SkipAll); -#else +#ifdef QT_BUILD_INTERNAL if (!QGLFormat::hasOpenGL()) QSKIP("QGL not supported on this platform", SkipAll); @@ -366,9 +357,6 @@ public: void tst_QGL::graphicsViewClipping() { -#ifdef QT_NO_OPENGL - QSKIP("QGL not supported", SkipAll); -#else const int size = 64; UnclippedWidget *widget = new UnclippedWidget; widget->setFixedSize(size, size); @@ -403,7 +391,6 @@ void tst_QGL::graphicsViewClipping() p.end(); QCOMPARE(image, expected); -#endif } void tst_QGL::partialGLWidgetUpdates_data() @@ -420,9 +407,6 @@ void tst_QGL::partialGLWidgetUpdates_data() void tst_QGL::partialGLWidgetUpdates() { -#ifdef QT_NO_OPENGL - QSKIP("QGL not yet supported", SkipAll); -#else if (!QGLFormat::hasOpenGL()) QSKIP("QGL not supported on this platform", SkipAll); @@ -466,7 +450,6 @@ void tst_QGL::partialGLWidgetUpdates() QCOMPARE(widget.paintEventRegion, QRegion(50, 50, 50, 50)); else QCOMPARE(widget.paintEventRegion, QRegion(widget.rect())); -#endif } QTEST_MAIN(tst_QGL) diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 7552f18..96ee070 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -231,6 +231,7 @@ private slots: void sorting_data(); void sorting(); void itemHasNoContents(); + void hitTestUntransformableItem(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6580,6 +6581,7 @@ public: void tst_QGraphicsItem::update() { QGraphicsScene scene; + scene.setSceneRect(-100, -100, 200, 200); MyGraphicsView view(&scene); view.show(); @@ -6612,9 +6614,9 @@ void tst_QGraphicsItem::update() qApp->processEvents(); QCOMPARE(item->repaints, 1); QCOMPARE(view.repaints, 1); - const QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform()) - .mapRect(item->boundingRect()).toRect(); - const QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); + QRect itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform()) + .mapRect(item->boundingRect()).toRect(); + QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); // The entire item's bounding rect (adjusted for antialiasing) should have been painted. QCOMPARE(view.paintedRegion, expectedRegion); @@ -6625,6 +6627,90 @@ void tst_QGraphicsItem::update() qApp->processEvents(); QCOMPARE(item->repaints, 0); QCOMPARE(view.repaints, 0); + + // Make sure the area occupied by an item is repainted when hiding it. + view.reset(); + item->repaints = 0; + item->update(); // Full update; all sub-sequent update requests are discarded. + item->hide(); // visible set to 0. ignoreVisible must be set to 1; the item won't be processed otherwise. + qApp->processEvents(); + QCOMPARE(item->repaints, 0); + QCOMPARE(view.repaints, 1); + // The entire item's bounding rect (adjusted for antialiasing) should have been painted. + QCOMPARE(view.paintedRegion, expectedRegion); + + // Make sure item is repainted when shown (after being hidden). + view.reset(); + item->repaints = 0; + item->show(); + qApp->processEvents(); + QCOMPARE(item->repaints, 1); + QCOMPARE(view.repaints, 1); + // The entire item's bounding rect (adjusted for antialiasing) should have been painted. + QCOMPARE(view.paintedRegion, expectedRegion); + + item->repaints = 0; + item->hide(); + qApp->processEvents(); + view.reset(); + const QPointF originalPos = item->pos(); + item->setPos(5000, 5000); + qApp->processEvents(); + QCOMPARE(item->repaints, 0); + QCOMPARE(view.repaints, 0); + qApp->processEvents(); + + item->setPos(originalPos); + qApp->processEvents(); + QCOMPARE(item->repaints, 0); + QCOMPARE(view.repaints, 0); + item->show(); + qApp->processEvents(); + QCOMPARE(item->repaints, 1); + QCOMPARE(view.repaints, 1); + // The entire item's bounding rect (adjusted for antialiasing) should have been painted. + QCOMPARE(view.paintedRegion, expectedRegion); + + QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view)); + item->setPos(originalPos + QPoint(50, 50)); + viewPrivate->updateAll(); + QVERIFY(viewPrivate->fullUpdatePending); + QTest::qWait(50); + item->repaints = 0; + view.reset(); + item->setPos(originalPos); + QTest::qWait(50); + qApp->processEvents(); + QCOMPARE(item->repaints, 1); + QCOMPARE(view.repaints, 1); + QCOMPARE(view.paintedRegion, expectedRegion + expectedRegion.translated(50, 50)); + + // Make sure moving a parent item triggers an update on the children + // (even though the parent itself is outside the viewport). + QGraphicsRectItem *parent = new QGraphicsRectItem(0, 0, 10, 10); + parent->setPos(-400, 0); + item->setParentItem(parent); + item->setPos(400, 0); + scene.addItem(parent); + QTest::qWait(50); + itemDeviceBoundingRect = item->deviceTransform(view.viewportTransform()) + .mapRect(item->boundingRect()).toRect(); + expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); + view.reset(); + item->repaints = 0; + parent->translate(-400, 0); + qApp->processEvents(); + QCOMPARE(item->repaints, 0); + QCOMPARE(view.repaints, 1); + QCOMPARE(view.paintedRegion, expectedRegion); + view.reset(); + item->repaints = 0; + parent->translate(400, 0); + qApp->processEvents(); + QCOMPARE(item->repaints, 1); + QCOMPARE(view.repaints, 1); + QCOMPARE(view.paintedRegion, expectedRegion); + QCOMPARE(view.paintedRegion, expectedRegion); } void tst_QGraphicsItem::setTransformProperties_data() @@ -6837,9 +6923,11 @@ public: //Doesn't use the extended style option so the exposed rect is the boundingRect if (!(flags() & QGraphicsItem::ItemUsesExtendedStyleOption)) { QCOMPARE(option->exposedRect, boundingRect()); + QCOMPARE(option->matrix, QMatrix()); } else { QVERIFY(option->exposedRect != QRect()); QVERIFY(option->exposedRect != boundingRect()); + QCOMPARE(option->matrix, sceneTransform().toAffine()); } } QGraphicsRectItem::paint(painter, option, widget); @@ -6861,6 +6949,8 @@ void tst_QGraphicsItem::itemUsesExtendedStyleOption() scene.addItem(rect); rect->setPos(200, 200); QGraphicsView view(&scene); + rect->startTrack = false; + view.show(); QTest::qWait(500); rect->startTrack = true; rect->update(10, 10, 10, 10); @@ -7023,7 +7113,7 @@ void tst_QGraphicsItem::sorting() QGraphicsView view(&scene); view.setResizeAnchor(QGraphicsView::NoAnchor); view.setTransformationAnchor(QGraphicsView::NoAnchor); - view.resize(100, 100); + view.resize(120, 100); view.setFrameStyle(0); view.show(); #ifdef Q_WS_X11 @@ -7040,6 +7130,7 @@ void tst_QGraphicsItem::sorting() << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3] << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3] << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3] + << grid[4][0] << grid[4][1] << grid[4][2] << grid[4][3] << item1 << item2); } @@ -7069,5 +7160,55 @@ void tst_QGraphicsItem::itemHasNoContents() QCOMPARE(_paintedItems, QList<QGraphicsItem *>() << item2); } +void tst_QGraphicsItem::hitTestUntransformableItem() +{ + QGraphicsScene scene; + scene.setSceneRect(-100, -100, 200, 200); + + QGraphicsView view(&scene); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(100); + + // Confuse the BSP with dummy items. + QGraphicsRectItem *dummy = new QGraphicsRectItem(0, 0, 20, 20); + dummy->setPos(-100, -100); + scene.addItem(dummy); + for (int i = 0; i < 100; ++i) { + QGraphicsItem *parent = dummy; + dummy = new QGraphicsRectItem(0, 0, 20, 20); + dummy->setPos(-100 + i, -100 + i); + dummy->setParentItem(parent); + } + + QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20); + item1->setPos(-200, -200); + + QGraphicsRectItem *item2 = new QGraphicsRectItem(0, 0, 20, 20); + item2->setFlag(QGraphicsItem::ItemIgnoresTransformations); + item2->setParentItem(item1); + item2->setPos(200, 200); + + QGraphicsRectItem *item3 = new QGraphicsRectItem(0, 0, 20, 20); + item3->setParentItem(item2); + item3->setPos(80, 80); + + scene.addItem(item1); + QTest::qWait(100); + + QList<QGraphicsItem *> items = scene.items(QPointF(80, 80)); + QCOMPARE(items.size(), 1); + QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3)); + + scene.setItemIndexMethod(QGraphicsScene::NoIndex); + QTest::qWait(100); + + items = scene.items(QPointF(80, 80)); + QCOMPARE(items.size(), 1); + QCOMPARE(items.at(0), static_cast<QGraphicsItem*>(item3)); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" diff --git a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp index 536c750..bca673f 100644 --- a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp +++ b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp @@ -687,7 +687,6 @@ void tst_QGraphicsLayout::ownership() delete top; //don't crash after that. } - } QTEST_MAIN(tst_QGraphicsLayout) diff --git a/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp index dbc4339..1d0663a 100644 --- a/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp +++ b/tests/auto/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp @@ -178,6 +178,7 @@ private slots: void windowFlags_data(); void windowFlags(); void comboboxWindowFlags(); + void updateAndDelete(); void inputMethod(); }; @@ -3218,6 +3219,44 @@ void tst_QGraphicsProxyWidget::comboboxWindowFlags() QVERIFY((static_cast<QGraphicsWidget *>(popupProxy)->windowFlags() & Qt::Popup) == Qt::Popup); } +void tst_QGraphicsProxyWidget::updateAndDelete() +{ + QGraphicsScene scene; + QGraphicsProxyWidget *proxy = scene.addWidget(new QPushButton("Hello World")); + View view(&scene); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(200); + + const QRect itemDeviceBoundingRect = proxy->deviceTransform(view.viewportTransform()) + .mapRect(proxy->boundingRect()).toRect(); + const QRegion expectedRegion = itemDeviceBoundingRect.adjusted(-2, -2, 2, 2); + + view.npaints = 0; + view.paintEventRegion = QRegion(); + + // Update and hide. + proxy->update(); + proxy->hide(); + QTest::qWait(50); + QCOMPARE(view.npaints, 1); + QCOMPARE(view.paintEventRegion, expectedRegion); + + proxy->show(); + QTest::qWait(50); + view.npaints = 0; + view.paintEventRegion = QRegion(); + + // Update and delete. + proxy->update(); + delete proxy; + QTest::qWait(50); + QCOMPARE(view.npaints, 1); + QCOMPARE(view.paintEventRegion, expectedRegion); +} + class InputMethod_LineEdit : public QLineEdit { bool event(QEvent *e) @@ -3252,7 +3291,7 @@ void tst_QGraphicsProxyWidget::inputMethod() if (i) lineEdit->setFocus(); - + lineEdit->inputMethodEvents = 0; QInputMethodEvent event; qApp->sendEvent(proxy, &event); diff --git a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp index d325f0f..e9d6f1d 100644 --- a/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/qgraphicsscene/tst_qgraphicsscene.cpp @@ -289,28 +289,46 @@ void tst_QGraphicsScene::construction() void tst_QGraphicsScene::sceneRect() { QGraphicsScene scene; + QSignalSpy sceneRectChanged(&scene, SIGNAL(sceneRectChanged(QRectF))); QCOMPARE(scene.sceneRect(), QRectF()); + QCOMPARE(sceneRectChanged.count(), 0); QGraphicsItem *item = scene.addRect(QRectF(0, 0, 10, 10)); - qApp->processEvents(); item->setPos(-5, -5); - qApp->processEvents(); + QCOMPARE(sceneRectChanged.count(), 0); QCOMPARE(scene.itemAt(0, 0), item); QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0); + QCOMPARE(sceneRectChanged.count(), 0); + QCOMPARE(scene.sceneRect(), QRectF(-5, -5, 10, 10)); + QCOMPARE(sceneRectChanged.count(), 1); + QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect()); + + item->setPos(0, 0); QCOMPARE(scene.sceneRect(), QRectF(-5, -5, 15, 15)); + QCOMPARE(sceneRectChanged.count(), 2); + QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect()); scene.setSceneRect(-100, -100, 10, 10); + QCOMPARE(sceneRectChanged.count(), 3); + QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect()); QCOMPARE(scene.itemAt(0, 0), item); QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0); QCOMPARE(scene.sceneRect(), QRectF(-100, -100, 10, 10)); + item->setPos(10, 10); + QCOMPARE(scene.sceneRect(), QRectF(-100, -100, 10, 10)); + QCOMPARE(sceneRectChanged.count(), 3); + QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect()); scene.setSceneRect(QRectF()); - QCOMPARE(scene.itemAt(0, 0), item); - QCOMPARE(scene.itemAt(10, 10), (QGraphicsItem *)0); - QCOMPARE(scene.sceneRect(), QRectF(-5, -5, 15, 15)); + QCOMPARE(scene.itemAt(10, 10), item); + QCOMPARE(scene.itemAt(20, 20), (QGraphicsItem *)0); + QCOMPARE(sceneRectChanged.count(), 4); + QCOMPARE(scene.sceneRect(), QRectF(-5, -5, 25, 25)); + QCOMPARE(sceneRectChanged.count(), 5); + QCOMPARE(sceneRectChanged.last().at(0).toRectF(), scene.sceneRect()); } void tst_QGraphicsScene::itemIndexMethod() @@ -399,8 +417,7 @@ void tst_QGraphicsScene::items() for (int x = minX; x < maxX; x += 100) items << scene.addRect(QRectF(0, 0, 10, 10)); } - - QCOMPARE(scene.items(), items); + QCOMPARE(scene.items().size(), items.size()); scene.itemAt(0, 0); // trigger indexing scene.removeItem(items.at(5)); @@ -415,6 +432,9 @@ void tst_QGraphicsScene::items() QGraphicsLineItem *l2 = scene.addLine(0, -5, 0, 5); QVERIFY(!l1->sceneBoundingRect().intersects(l2->sceneBoundingRect())); QVERIFY(!l2->sceneBoundingRect().intersects(l1->sceneBoundingRect())); + QList<QGraphicsItem *> items; + items<<l1<<l2; + QCOMPARE(scene.items().size(), items.size()); QVERIFY(scene.items(-1, -1, 2, 2).contains(l1)); QVERIFY(scene.items(-1, -1, 2, 2).contains(l2)); } @@ -2742,8 +2762,8 @@ void tst_QGraphicsScene::update() qRegisterMetaType<QList<QRectF> >("QList<QRectF>"); QSignalSpy spy(&scene, SIGNAL(changed(QList<QRectF>))); - // When deleted, the item will lazy-remove itself - delete rect; + // We update the scene. + scene.update(); // This function forces a purge, which will post an update signal scene.itemAt(0, 0); diff --git a/tests/auto/qgraphicssceneindex/qgraphicssceneindex.pro b/tests/auto/qgraphicssceneindex/qgraphicssceneindex.pro new file mode 100644 index 0000000..740a23e --- /dev/null +++ b/tests/auto/qgraphicssceneindex/qgraphicssceneindex.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +SOURCES += tst_qgraphicssceneindex.cpp + diff --git a/tests/auto/qgraphicssceneindex/tst_qgraphicssceneindex.cpp b/tests/auto/qgraphicssceneindex/tst_qgraphicssceneindex.cpp new file mode 100644 index 0000000..3ce5b16 --- /dev/null +++ b/tests/auto/qgraphicssceneindex/tst_qgraphicssceneindex.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite 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$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtGui/qgraphicsscene.h> +#include <private/qgraphicsscenebsptreeindex_p.h> +#include <private/qgraphicssceneindex_p.h> +#include <private/qgraphicsscenelinearindex_p.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QGraphicsSceneIndex : public QObject +{ + Q_OBJECT +public slots: + void initTestCase(); + +private slots: + void customIndex_data(); + void customIndex(); + void scatteredItems_data(); + void scatteredItems(); + void overlappedItems_data(); + void overlappedItems(); + void movingItems_data(); + void movingItems(); + void connectedToSceneRectChanged(); + void items(); + +private: + void common_data(); + QGraphicsSceneIndex *createIndex(const QString &name); +}; + +void tst_QGraphicsSceneIndex::initTestCase() +{ +} + +void tst_QGraphicsSceneIndex::common_data() +{ + QTest::addColumn<QString>("indexMethod"); + + QTest::newRow("BSP") << QString("bsp"); + QTest::newRow("Linear") << QString("linear"); +} + +QGraphicsSceneIndex *tst_QGraphicsSceneIndex::createIndex(const QString &indexMethod) +{ + QGraphicsSceneIndex *index = 0; + QGraphicsScene *scene = new QGraphicsScene(); + if (indexMethod == "bsp") + index = new QGraphicsSceneBspTreeIndex(scene); + + if (indexMethod == "linear") + index = new QGraphicsSceneLinearIndex(scene); + + return index; +} + +void tst_QGraphicsSceneIndex::customIndex_data() +{ + common_data(); +} + +void tst_QGraphicsSceneIndex::customIndex() +{ +#if 0 + QFETCH(QString, indexMethod); + QGraphicsSceneIndex *index = createIndex(indexMethod); + + QGraphicsScene scene; + scene.setSceneIndex(index); + + scene.addRect(0, 0, 30, 40); + QCOMPARE(scene.items(QRectF(0, 0, 10, 10)).count(), 1); +#endif +} + +void tst_QGraphicsSceneIndex::scatteredItems_data() +{ + common_data(); +} + +void tst_QGraphicsSceneIndex::scatteredItems() +{ + QFETCH(QString, indexMethod); + + QGraphicsScene scene; +#if 1 + scene.setItemIndexMethod(indexMethod == "linear" ? QGraphicsScene::NoIndex : QGraphicsScene::BspTreeIndex); +#else + QGraphicsSceneIndex *index = createIndex(indexMethod); + scene.setSceneIndex(index); +#endif + + for (int i = 0; i < 10; ++i) + scene.addRect(i*50, i*50, 40, 35); + + QCOMPARE(scene.items(QPointF(5, 5)).count(), 1); + QCOMPARE(scene.items(QPointF(55, 55)).count(), 1); + QCOMPARE(scene.items(QPointF(-100, -100)).count(), 0); + + QCOMPARE(scene.items(QRectF(0, 0, 10, 10)).count(), 1); + QCOMPARE(scene.items(QRectF(0, 0, 1000, 1000)).count(), 10); + QCOMPARE(scene.items(QRectF(-100, -1000, 0, 0)).count(), 0); +} + +void tst_QGraphicsSceneIndex::overlappedItems_data() +{ + common_data(); +} + +void tst_QGraphicsSceneIndex::overlappedItems() +{ + QFETCH(QString, indexMethod); + + QGraphicsScene scene; +#if 1 + scene.setItemIndexMethod(indexMethod == "linear" ? QGraphicsScene::NoIndex : QGraphicsScene::BspTreeIndex); +#else + QGraphicsSceneIndex *index = createIndex(indexMethod); + scene.setSceneIndex(index); +#endif + + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 10; ++j) + scene.addRect(i*50, j*50, 200, 200); + + QCOMPARE(scene.items(QPointF(5, 5)).count(), 1); + QCOMPARE(scene.items(QPointF(55, 55)).count(), 4); + QCOMPARE(scene.items(QPointF(105, 105)).count(), 9); + QCOMPARE(scene.items(QPointF(-100, -100)).count(), 0); + + QCOMPARE(scene.items(QRectF(0, 0, 1000, 1000)).count(), 100); + QCOMPARE(scene.items(QRectF(-100, -1000, 0, 0)).count(), 0); + QCOMPARE(scene.items(QRectF(0, 0, 200, 200)).count(), 16); + QCOMPARE(scene.items(QRectF(0, 0, 100, 100)).count(), 4); + QCOMPARE(scene.items(QRectF(0, 0, 1, 100)).count(), 2); + QCOMPARE(scene.items(QRectF(0, 0, 1, 1000)).count(), 10); +} + +void tst_QGraphicsSceneIndex::movingItems_data() +{ + common_data(); +} + +void tst_QGraphicsSceneIndex::movingItems() +{ + QFETCH(QString, indexMethod); + + QGraphicsScene scene; +#if 1 + scene.setItemIndexMethod(indexMethod == "linear" ? QGraphicsScene::NoIndex : QGraphicsScene::BspTreeIndex); +#else + QGraphicsSceneIndex *index = createIndex(indexMethod); + scene.setSceneIndex(index); +#endif + + for (int i = 0; i < 10; ++i) + scene.addRect(i*50, i*50, 40, 35); + + QGraphicsRectItem *box = scene.addRect(0, 0, 10, 10); + QCOMPARE(scene.items(QPointF(5, 5)).count(), 2); + QCOMPARE(scene.items(QPointF(-1, -1)).count(), 0); + QCOMPARE(scene.items(QRectF(0, 0, 5, 5)).count(), 2); + + box->setPos(10, 10); + QCOMPARE(scene.items(QPointF(9, 9)).count(), 1); + QCOMPARE(scene.items(QPointF(15, 15)).count(), 2); + QCOMPARE(scene.items(QRectF(0, 0, 1, 1)).count(), 1); + + box->setPos(-5, -5); + QCOMPARE(scene.items(QPointF(-1, -1)).count(), 1); + QCOMPARE(scene.items(QRectF(0, 0, 1, 1)).count(), 2); + + QCOMPARE(scene.items(QRectF(0, 0, 1000, 1000)).count(), 11); +} + +void tst_QGraphicsSceneIndex::connectedToSceneRectChanged() +{ + + class MyScene : public QGraphicsScene + { public: using QGraphicsScene::receivers; }; + + MyScene scene; // Uses QGraphicsSceneBspTreeIndex by default. + QCOMPARE(scene.receivers(SIGNAL(sceneRectChanged(const QRectF&))), 1); + + scene.setItemIndexMethod(QGraphicsScene::NoIndex); // QGraphicsSceneLinearIndex + QCOMPARE(scene.receivers(SIGNAL(sceneRectChanged(const QRectF&))), 1); +} + +void tst_QGraphicsSceneIndex::items() +{ + QGraphicsScene scene; + QGraphicsItem *item1 = scene.addRect(0, 0, 10, 10); + QGraphicsItem *item2 = scene.addRect(10, 10, 10, 10); + QCOMPARE(scene.items().size(), 2); + + // Move from unindexed items into bsp tree. + QTest::qWait(50); + QCOMPARE(scene.items().size(), 2); + + // Add untransformable item. + QGraphicsItem *item3 = new QGraphicsRectItem(QRectF(20, 20, 10, 10)); + item3->setFlag(QGraphicsItem::ItemIgnoresTransformations); + scene.addItem(item3); + QCOMPARE(scene.items().size(), 3); + + // Move from unindexed items into untransformable items. + QTest::qWait(50); + QCOMPARE(scene.items().size(), 3); + + // Move from untransformable items into unindexed items. + item3->setFlag(QGraphicsItem::ItemIgnoresTransformations, false); + QCOMPARE(scene.items().size(), 3); + QTest::qWait(50); + QCOMPARE(scene.items().size(), 3); + + // Make all items untransformable. + item1->setFlag(QGraphicsItem::ItemIgnoresTransformations); + item2->setParentItem(item1); + item3->setParentItem(item2); + QCOMPARE(scene.items().size(), 3); + + // Move from unindexed items into untransformable items. + QTest::qWait(50); + QCOMPARE(scene.items().size(), 3); +} + +QTEST_MAIN(tst_QGraphicsSceneIndex) +#include "tst_qgraphicssceneindex.moc" diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index 8b4ca4c..9a5089b 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -64,6 +64,7 @@ #include <QtGui/QStyle> #include <QtGui/QPushButton> #include <QtGui/QInputContext> +#include <private/qgraphicsview_p.h> //TESTED_CLASS= //TESTED_FILES= @@ -176,6 +177,7 @@ private slots: void transformationAnchor(); void resizeAnchor(); void viewportUpdateMode(); + void viewportUpdateMode2(); void acceptDrops(); void optimizationFlags(); void optimizationFlags_dontSavePainterState(); @@ -196,6 +198,8 @@ private slots: void mouseTracking2(); void render(); void exposeRegion(); + void update_data(); + void update(); void inputMethodSensitivity(); void inputContextReset(); @@ -374,6 +378,7 @@ void tst_QGraphicsView::interactive() QCOMPARE(item->events.size(), 0); QPoint itemPoint = view.mapFromScene(item->scenePos()); + QVERIFY(view.itemAt(itemPoint)); for (int i = 0; i < 100; ++i) { @@ -2109,12 +2114,12 @@ void tst_QGraphicsView::resizeAnchor() view.setResizeAnchor(QGraphicsView::AnchorViewCenter); } view.centerOn(0, 0); - QTest::qWait(100); + QTest::qWait(250); QPointF f = view.mapToScene(50, 50); QPointF center = view.mapToScene(view.viewport()->rect().center()); - QTest::qWait(100); + QTest::qWait(250); for (int size = 200; size <= 400; size += 25) { view.resize(size, size); @@ -2129,7 +2134,7 @@ void tst_QGraphicsView::resizeAnchor() QVERIFY(qAbs(newCenter.x() - center.x()) < slack); QVERIFY(qAbs(newCenter.y() - center.y()) < slack); } - QTest::qWait(100); + QTest::qWait(250); } } } @@ -2231,6 +2236,52 @@ void tst_QGraphicsView::viewportUpdateMode() QCOMPARE(view.lastUpdateRegions.size(), 0); } +void tst_QGraphicsView::viewportUpdateMode2() +{ + // Create a view with viewport rect equal to QRect(0, 0, 200, 200). + QGraphicsScene dummyScene; + CustomView view; + view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + view.setScene(&dummyScene); + int left, top, right, bottom; + view.getContentsMargins(&left, &top, &right, &bottom); + view.resize(200 + left + right, 200 + top + bottom); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(300); + const QRect viewportRect = view.viewport()->rect(); + QCOMPARE(viewportRect, QRect(0, 0, 200, 200)); + QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view)); + + QRect boundingRect; + const QRect rect1(0, 0, 10, 10); + QVERIFY(viewPrivate->updateRect(rect1)); + QVERIFY(!viewPrivate->fullUpdatePending); + boundingRect |= rect1; + QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect); + + const QRect rect2(50, 50, 10, 10); + QVERIFY(viewPrivate->updateRect(rect2)); + QVERIFY(!viewPrivate->fullUpdatePending); + boundingRect |= rect2; + QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect); + + const QRect rect3(190, 190, 10, 10); + QVERIFY(viewPrivate->updateRect(rect3)); + QVERIFY(viewPrivate->fullUpdatePending); + boundingRect |= rect3; + QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect); + + view.lastUpdateRegions.clear(); + viewPrivate->processPendingUpdates(); + QTest::qWait(50); + QCOMPARE(view.lastUpdateRegions.size(), 1); + // Note that we adjust by 2 for antialiasing. + QCOMPARE(view.lastUpdateRegions.at(0), QRegion(boundingRect.adjusted(-2, -2, 2, 2) & viewportRect)); +} + void tst_QGraphicsView::acceptDrops() { QGraphicsView view; @@ -2991,14 +3042,7 @@ void tst_QGraphicsView::embeddedViews() v2->QWidget::render(&actual); QTransform b = item->transform; -#ifdef Q_WS_MAC - // We don't use shared painter on the Mac, so the - // transform should be exactly the same. QVERIFY(a == b); -#else - QVERIFY(a != b); -#endif - delete v1; } @@ -3095,7 +3139,7 @@ void tst_QGraphicsView::moveItemWhileScrolling() #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&view); #endif - QTest::qWait(100); + QTest::qWait(200); view.lastPaintedRegion = QRegion(); view.horizontalScrollBar()->setValue(view.horizontalScrollBar()->value() + 10); @@ -3267,7 +3311,9 @@ void tst_QGraphicsView::mouseTracking2() EventSpy spy(&scene, QEvent::GraphicsSceneMouseMove); QCOMPARE(spy.count(), 0); - sendMouseMove(view.viewport(), view.viewport()->rect().center()); + QMouseEvent event(QEvent::MouseMove,view.viewport()->rect().center(), Qt::NoButton, + Qt::MouseButtons(Qt::NoButton), 0); + QApplication::sendEvent(view.viewport(), &event); QCOMPARE(spy.count(), 1); } @@ -3360,6 +3406,72 @@ void tst_QGraphicsView::exposeRegion() QCOMPARE(item->paints, 0); } +void tst_QGraphicsView::update_data() +{ + // In view.viewport() coordinates. (viewport rect: QRect(0, 0, 200, 200)) + QTest::addColumn<QRect>("updateRect"); + QTest::newRow("empty") << QRect(); + QTest::newRow("outside left") << QRect(-200, 0, 100, 100); + QTest::newRow("outside right") << QRect(400, 0 ,100, 100); + QTest::newRow("outside top") << QRect(0, -200, 100, 100); + QTest::newRow("outside bottom") << QRect(0, 400, 100, 100); + QTest::newRow("partially inside left") << QRect(-50, 0, 100, 100); + QTest::newRow("partially inside right") << QRect(-150, 0, 100, 100); + QTest::newRow("partially inside top") << QRect(0, -150, 100, 100); + QTest::newRow("partially inside bottom") << QRect(0, 150, 100, 100); + QTest::newRow("on topLeft edge") << QRect(-100, -100, 100, 100); + QTest::newRow("on topRight edge") << QRect(200, -100, 100, 100); + QTest::newRow("on bottomRight edge") << QRect(200, 200, 100, 100); + QTest::newRow("on bottomLeft edge") << QRect(-200, 200, 100, 100); + QTest::newRow("inside topLeft") << QRect(-99, -99, 100, 100); + QTest::newRow("inside topRight") << QRect(199, -99, 100, 100); + QTest::newRow("inside bottomRight") << QRect(199, 199, 100, 100); + QTest::newRow("inside bottomLeft") << QRect(-199, 199, 100, 100); + QTest::newRow("large1") << QRect(50, -100, 100, 400); + QTest::newRow("large2") << QRect(-100, 50, 400, 100); + QTest::newRow("large3") << QRect(-100, -100, 400, 400); + QTest::newRow("viewport rect") << QRect(0, 0, 200, 200); +} + +void tst_QGraphicsView::update() +{ + QFETCH(QRect, updateRect); + + // Create a view with viewport rect equal to QRect(0, 0, 200, 200). + QGraphicsScene dummyScene; + CustomView view; + view.setScene(&dummyScene); + int left, top, right, bottom; + view.getContentsMargins(&left, &top, &right, &bottom); + view.resize(200 + left + right, 200 + top + bottom); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(300); + const QRect viewportRect = view.viewport()->rect(); + QCOMPARE(viewportRect, QRect(0, 0, 200, 200)); + + const bool intersects = updateRect.intersects(viewportRect); + QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(&view)); + QCOMPARE(viewPrivate->updateRect(updateRect), intersects); + QCOMPARE(viewPrivate->updateRegion(updateRect), intersects); + + view.lastUpdateRegions.clear(); + viewPrivate->processPendingUpdates(); + QVERIFY(viewPrivate->dirtyRegion.isEmpty()); + QVERIFY(viewPrivate->dirtyBoundingRect.isEmpty()); + QTest::qWait(50); + if (!intersects) { + QVERIFY(view.lastUpdateRegions.isEmpty()); + } else { + QCOMPARE(view.lastUpdateRegions.size(), 1); + // Note that we adjust by 2 for antialiasing. + QCOMPARE(view.lastUpdateRegions.at(0), QRegion(updateRect.adjusted(-2, -2, 2, 2) & viewportRect)); + } + QVERIFY(!viewPrivate->fullUpdatePending); +} + void tst_QGraphicsView::inputMethodSensitivity() { QGraphicsScene scene; diff --git a/tests/auto/qhttpnetworkconnection/qhttpnetworkconnection.pro b/tests/auto/qhttpnetworkconnection/qhttpnetworkconnection.pro index 3283873..e19d962 100644 --- a/tests/auto/qhttpnetworkconnection/qhttpnetworkconnection.pro +++ b/tests/auto/qhttpnetworkconnection/qhttpnetworkconnection.pro @@ -2,4 +2,6 @@ load(qttest_p4) SOURCES += tst_qhttpnetworkconnection.cpp INCLUDEPATH += $$(QTDIR)/src/3rdparty/zlib +requires(contains(QT_CONFIG,private_tests)) + QT = core network diff --git a/tests/auto/qhttpnetworkreply/qhttpnetworkreply.pro b/tests/auto/qhttpnetworkreply/qhttpnetworkreply.pro index 2e41fcd..f86250a 100644 --- a/tests/auto/qhttpnetworkreply/qhttpnetworkreply.pro +++ b/tests/auto/qhttpnetworkreply/qhttpnetworkreply.pro @@ -2,4 +2,6 @@ load(qttest_p4) SOURCES += tst_qhttpnetworkreply.cpp INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/zlib +requires(contains(QT_CONFIG,private_tests)) + QT = core network diff --git a/tests/auto/qitemeditorfactory/tst_qitemeditorfactory.cpp b/tests/auto/qitemeditorfactory/tst_qitemeditorfactory.cpp index d9a7d56..e235ff5 100644 --- a/tests/auto/qitemeditorfactory/tst_qitemeditorfactory.cpp +++ b/tests/auto/qitemeditorfactory/tst_qitemeditorfactory.cpp @@ -59,13 +59,13 @@ void tst_QItemEditorFactory::createEditor() QCOMPARE(w->metaObject()->className(), "QExpandingLineEdit"); } -void tst_QItemEditorFactory::createCustomEditor() +//we make it inherit from QObject so that we can use QPointer +class MyEditor : public QObject, public QStandardItemEditorCreator<QDoubleSpinBox> { - //we make it inherit from QObject so that we can use QPointer - class MyEditor : public QObject, public QStandardItemEditorCreator<QDoubleSpinBox> - { - }; +}; +void tst_QItemEditorFactory::createCustomEditor() +{ QPointer<MyEditor> creator = new MyEditor; QPointer<MyEditor> creator2 = new MyEditor; diff --git a/tests/auto/qkeysequence/tst_qkeysequence.cpp b/tests/auto/qkeysequence/tst_qkeysequence.cpp index aeb57ef..2e4b850 100644 --- a/tests/auto/qkeysequence/tst_qkeysequence.cpp +++ b/tests/auto/qkeysequence/tst_qkeysequence.cpp @@ -270,7 +270,7 @@ void tst_QKeySequence::checkMultipleNames() void tst_QKeySequence::ensureSorted() { //### accessing static members from private classes does not work on msvc at the moment -#ifndef Q_WS_WIN +#if defined(QT_BUILD_INTERNAL) && !defined(Q_WS_WIN) uint N = QKeySequencePrivate::numberOfKeyBindings; uint val = QKeySequencePrivate::keyBindings[0].shortcut; for ( uint i = 1 ; i < N ; ++i) { diff --git a/tests/auto/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/qlocalsocket/tst_qlocalsocket.cpp index 0f636a4..a41eecd 100644 --- a/tests/auto/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/qlocalsocket/tst_qlocalsocket.cpp @@ -104,6 +104,7 @@ private slots: void recycleServer(); void multiConnect(); + void writeOnlySocket(); void debug(); @@ -906,6 +907,22 @@ void tst_QLocalSocket::multiConnect() QVERIFY(server.nextPendingConnection() != 0); } +void tst_QLocalSocket::writeOnlySocket() +{ + QLocalServer server; + QVERIFY(server.listen("writeOnlySocket")); + + QLocalSocket client; + client.connectToServer("writeOnlySocket", QIODevice::WriteOnly); + QVERIFY(client.waitForConnected()); + + QVERIFY(server.waitForNewConnection()); + QLocalSocket* serverSocket = server.nextPendingConnection(); + + QCOMPARE(client.bytesAvailable(), qint64(0)); + QCOMPARE(client.state(), QLocalSocket::ConnectedState); +} + void tst_QLocalSocket::debug() { // Make sure this compiles diff --git a/tests/auto/qmainwindow/tst_qmainwindow.cpp b/tests/auto/qmainwindow/tst_qmainwindow.cpp index e46c2e1..6ae7a3e 100644 --- a/tests/auto/qmainwindow/tst_qmainwindow.cpp +++ b/tests/auto/qmainwindow/tst_qmainwindow.cpp @@ -1400,6 +1400,7 @@ void AddDockWidget::apply(QMainWindow *mw) const } } +#ifdef QT_BUILD_INTERNAL struct MoveSeparator { MoveSeparator() {} @@ -1436,6 +1437,7 @@ void MoveSeparator::apply(QMainWindow *mw) const l->layoutState.dockAreaLayout.separatorMove(path, QPoint(0, 0), QPoint(delta, delta)); } +#endif QMap<QString, QRect> dockWidgetGeometries(QMainWindow *mw) { @@ -1463,6 +1465,7 @@ QMap<QString, QRect> dockWidgetGeometries(QMainWindow *mw) void tst_QMainWindow::saveRestore_data() { +#ifdef QT_BUILD_INTERNAL QTest::addColumn<AddList >("addList"); QTest::addColumn<MoveList >("moveList"); @@ -1497,10 +1500,12 @@ void tst_QMainWindow::saveRestore_data() << MoveSeparator(-30, "right1") << MoveSeparator(30, "right2a") ); +#endif } void tst_QMainWindow::saveRestore() { +#ifdef QT_BUILD_INTERNAL QFETCH(AddList, addList); QFETCH(MoveList, moveList); @@ -1570,6 +1575,7 @@ void tst_QMainWindow::saveRestore() mainWindow.show(); COMPARE_DOCK_WIDGET_GEOS(dockWidgetGeos, dockWidgetGeometries(&mainWindow)); } +#endif } void tst_QMainWindow::iconSizeChanged() diff --git a/tests/auto/qmenubar/tst_qmenubar.cpp b/tests/auto/qmenubar/tst_qmenubar.cpp index 500465c..1245de1 100644 --- a/tests/auto/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/qmenubar/tst_qmenubar.cpp @@ -1576,8 +1576,9 @@ void tst_QMenuBar::menubarSizeHint() return 11; case PM_MenuBarPanelWidth: return 1; + default: + return QWindowsStyle::pixelMetric(metric, option, widget); } - return QWindowsStyle::pixelMetric(metric, option, widget); } } style; diff --git a/tests/auto/qnativesocketengine/qnativesocketengine.pro b/tests/auto/qnativesocketengine/qnativesocketengine.pro index 320f24c..ad40d53 100644 --- a/tests/auto/qnativesocketengine/qnativesocketengine.pro +++ b/tests/auto/qnativesocketengine/qnativesocketengine.pro @@ -3,6 +3,8 @@ SOURCES += tst_qnativesocketengine.cpp include(../qnativesocketengine/qsocketengine.pri) +requires(contains(QT_CONFIG,private_tests)) + MOC_DIR=tmp QT = core network diff --git a/tests/auto/qnetworkreply/qnetworkreply.pro b/tests/auto/qnetworkreply/qnetworkreply.pro index 0bcf067..fd8454c 100644 --- a/tests/auto/qnetworkreply/qnetworkreply.pro +++ b/tests/auto/qnetworkreply/qnetworkreply.pro @@ -1,4 +1,6 @@ TEMPLATE = subdirs SUBDIRS = test +requires(contains(QT_CONFIG,private_tests)) + !wince*:SUBDIRS += echo diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 89e850c..8318b60 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -245,6 +245,8 @@ private Q_SLOTS: void authorizationError(); void httpConnectionCount(); + void httpDownloadPerformance_data(); + void httpDownloadPerformance(); }; QT_BEGIN_NAMESPACE @@ -3696,5 +3698,128 @@ void tst_QNetworkReply::httpConnectionCount() QCOMPARE(pendingConnectionCount, 6); } +class HttpDownloadPerformanceClient : QObject { + Q_OBJECT; + QIODevice *device; + public: + HttpDownloadPerformanceClient (QIODevice *dev) : device(dev){ + connect(dev, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + } + + public slots: + void readyReadSlot() { + device->readAll(); + } + +}; + +class HttpDownloadPerformanceServer : QObject { + Q_OBJECT; + qint64 dataSize; + qint64 dataSent; + QTcpServer server; + QTcpSocket *client; + bool serverSendsContentLength; + bool chunkedEncoding; + +public: + HttpDownloadPerformanceServer (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0), + client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) { + server.listen(); + connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot())); + } + + int serverPort() { + return server.serverPort(); + } + +public slots: + + void newConnectionSlot() { + client = server.nextPendingConnection(); + client->setParent(this); + connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64))); + } + + void readyReadSlot() { + client->readAll(); + client->write("HTTP/1.0 200 OK\n"); + if (serverSendsContentLength) + client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toAscii()); + if (chunkedEncoding) + client->write(QString("Transfer-Encoding: chunked\n").toAscii()); + client->write("Connection: close\n\n"); + } + + void bytesWrittenSlot(qint64 amount) { + if (dataSent == dataSize && client) { + // close eventually + + // chunked encoding: we have to send a last "empty" chunk + if (chunkedEncoding) + client->write(QString("0\r\n\r\n").toAscii()); + + client->disconnectFromHost(); + server.close(); + client = 0; + return; + } + + // send data + if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) { + qint64 amount = qMin(qint64(16*1024), dataSize - dataSent); + QByteArray data(amount, '@'); + + if (chunkedEncoding) { + client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toAscii()); + client->write(data.constData(), amount); + client->write(QString("\r\n").toAscii()); + } else { + client->write(data.constData(), amount); + } + + dataSent += amount; + } + } +}; + +void tst_QNetworkReply::httpDownloadPerformance_data() +{ + QTest::addColumn<bool>("serverSendsContentLength"); + QTest::addColumn<bool>("chunkedEncoding"); + + QTest::newRow("Server sends no Content-Length") << false << false; + QTest::newRow("Server sends Content-Length") << true << false; + QTest::newRow("Server uses chunked encoding") << false << true; + +} + +void tst_QNetworkReply::httpDownloadPerformance() +{ + QFETCH(bool, serverSendsContentLength); + QFETCH(bool, chunkedEncoding); + + enum {UploadSize = 1000*1024*1024}; // 1000 MB + HttpDownloadPerformanceServer server(UploadSize, serverSendsContentLength, chunkedEncoding); + + QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1")); + QNetworkReply* reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + HttpDownloadPerformanceClient client(reply); + + QTime time; + time.start(); + QTestEventLoop::instance().enterLoop(40); + QVERIFY(!QTestEventLoop::instance().timeout()); + + qint64 elapsed = time.elapsed(); + qWarning() << "tst_QNetworkReply::httpDownloadPerformance" << elapsed << "msec, " + << ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec"; + + delete reply; +} + QTEST_MAIN(tst_QNetworkReply) #include "tst_qnetworkreply.moc" diff --git a/tests/auto/qpathclipper/qpathclipper.pro b/tests/auto/qpathclipper/qpathclipper.pro index 675e463..dc9d60f 100644 --- a/tests/auto/qpathclipper/qpathclipper.pro +++ b/tests/auto/qpathclipper/qpathclipper.pro @@ -3,6 +3,8 @@ INCLUDEPATH += . HEADERS += paths.h SOURCES += tst_qpathclipper.cpp paths.cpp +requires(contains(QT_CONFIG,private_tests)) + unix:!mac:LIBS+=-lm diff --git a/tests/auto/qplaintextedit/tst_qplaintextedit.cpp b/tests/auto/qplaintextedit/tst_qplaintextedit.cpp index fceefd2..40ad539 100644 --- a/tests/auto/qplaintextedit/tst_qplaintextedit.cpp +++ b/tests/auto/qplaintextedit/tst_qplaintextedit.cpp @@ -1106,6 +1106,7 @@ void tst_QPlainTextEdit::mimeDataReimplementations() QCOMPARE(ed.canInsertCallCount, 0); QCOMPARE(ed.insertCallCount, 0); +#ifdef QT_BUILD_INTERNAL QTextControl *control = qFindChild<QTextControl *>(&ed); QVERIFY(control); @@ -1120,6 +1121,7 @@ void tst_QPlainTextEdit::mimeDataReimplementations() QCOMPARE(ed.createMimeDataCallCount, 1); QCOMPARE(ed.canInsertCallCount, 1); QCOMPARE(ed.insertCallCount, 1); +#endif } void tst_QPlainTextEdit::shiftEnterShouldInsertLineSeparator() diff --git a/tests/auto/qregion/tst_qregion.cpp b/tests/auto/qregion/tst_qregion.cpp index 3ffa87e..2ad202d 100644 --- a/tests/auto/qregion/tst_qregion.cpp +++ b/tests/auto/qregion/tst_qregion.cpp @@ -96,7 +96,7 @@ private slots: #ifdef Q_OS_WIN void handle(); #endif -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) && defined(QT_BUILD_INTERNAL) void clipRectangles(); #endif @@ -865,7 +865,7 @@ void tst_QRegion::handle() } #endif -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) && defined(QT_BUILD_INTERNAL) void tst_QRegion::clipRectangles() { QRegion region(30, 30, 30, 30); @@ -967,6 +967,7 @@ void tst_QRegion::regionToPath_data() void tst_QRegion::regionToPath() { +#ifdef QT_BUILD_INTERNAL extern QPainterPath qt_regionToPath(const QRegion ®ion); QFETCH(QPainterPath, path); @@ -1002,6 +1003,7 @@ void tst_QRegion::regionToPath() QCOMPARE(ia, ib); QCOMPARE(a.boundingRect(), b.boundingRect()); } +#endif } QTEST_MAIN(tst_QRegion) diff --git a/tests/auto/qsettings/tst_qsettings.cpp b/tests/auto/qsettings/tst_qsettings.cpp index f0f446d..77fef1f 100644 --- a/tests/auto/qsettings/tst_qsettings.cpp +++ b/tests/auto/qsettings/tst_qsettings.cpp @@ -713,6 +713,7 @@ void tst_QSettings::testErrorHandling_data() void tst_QSettings::testErrorHandling() { +#ifdef QT_BUILD_INTERNAL #ifdef Q_OS_WIN QSKIP("Windows doesn't support most file modes, including read-only directories, so this test is moot.", SkipAll); #else @@ -776,6 +777,7 @@ void tst_QSettings::testErrorHandling() QCOMPARE((int)settings.status(), statusAfterSetAndSync); } #endif // !Q_OS_WIN +#endif } Q_DECLARE_METATYPE(QVariant) @@ -821,6 +823,7 @@ void tst_QSettings::testIniParsing_data() void tst_QSettings::testIniParsing() { +#ifdef QT_BUILD_INTERNAL qRegisterMetaType<QVariant>("QVariant"); qRegisterMetaType<QSettings::Status>("QSettings::Status"); @@ -854,6 +857,7 @@ void tst_QSettings::testIniParsing() } QCOMPARE(settings.status(), status); +#endif } /* @@ -1058,6 +1062,7 @@ void tst_QSettings::testVariantTypes_data() void tst_QSettings::testVariantTypes() { +#ifdef QT_BUILD_INTERNAL #define testVal(key, val, tp, rtype) \ { \ QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); \ @@ -1141,6 +1146,7 @@ void tst_QSettings::testVariantTypes() } #undef testVal +#endif } void tst_QSettings::remove() @@ -1801,9 +1807,7 @@ void tst_QSettings::testNormalizedKey_data() void tst_QSettings::testNormalizedKey() { -#ifdef QTEST_REDUCED_EXPORTS - QSKIP("We can't test QSettingsPrivate on Windows", SkipAll); -#else +#ifdef QT_BUILD_INTERNAL QFETCH(QString, inKey); QFETCH(QString, outKey); @@ -1981,6 +1985,7 @@ void tst_QSettings::fromFile() void tst_QSettings::setIniCodec() { +#ifdef QT_BUILD_INTERNAL QByteArray expeContents4, expeContents5; QByteArray actualContents4, actualContents5; @@ -2040,6 +2045,7 @@ void tst_QSettings::setIniCodec() QCOMPARE(settings4.allKeys().first(), settings5.allKeys().first()); QCOMPARE(settings4.value(settings4.allKeys().first()).toString(), settings5.value(settings5.allKeys().first()).toString()); +#endif } static bool containsSubList(QStringList mom, QStringList son) @@ -2316,6 +2322,7 @@ void tst_QSettings::testArrays() settings1.endArray(); } +#ifdef QT_BUILD_INTERNAL static QByteArray iniEscapedKey(const QString &str) { QByteArray result; @@ -2360,6 +2367,7 @@ static QStringList iniUnescapedStringList(const QByteArray &ba) #endif return result; } +#endif QString escapeWeirdChars(const QString &s) { @@ -2383,6 +2391,7 @@ QString escapeWeirdChars(const QString &s) void tst_QSettings::testEscapes() { +#ifdef QT_BUILD_INTERNAL QSettings settings(QSettings::UserScope, "software.org", "KillerAPP"); #define testEscapedKey(plainKey, escKey) \ @@ -2505,6 +2514,7 @@ void tst_QSettings::testEscapes() testBadEscape("@Rect)", "@Rect)"); testBadEscape("@Rect(1 2 3)", "@Rect(1 2 3)"); testBadEscape("@@Rect(1 2 3)", "@Rect(1 2 3)"); +#endif } void tst_QSettings::testCompatFunctions() @@ -3355,6 +3365,7 @@ void tst_QSettings::childGroups_data() void tst_QSettings::childGroups() { +#ifdef QT_BUILD_INTERNAL QFETCH(QSettings::Format, format); { @@ -3408,6 +3419,7 @@ void tst_QSettings::childGroups() QCOMPARE(settings.childGroups(), QStringList() << "alpha" << "gamma" << "omicron" << "zeta"); } +#endif } void tst_QSettings::childKeys_data() @@ -3417,6 +3429,7 @@ void tst_QSettings::childKeys_data() void tst_QSettings::childKeys() { +#ifdef QT_BUILD_INTERNAL QFETCH(QSettings::Format, format); { @@ -3470,6 +3483,7 @@ void tst_QSettings::childKeys() QCOMPARE(settings.childKeys(), QStringList() << "alpha" << "beta" << "gamma"); } +#endif } void tst_QSettings::allKeys_data() @@ -3479,6 +3493,7 @@ void tst_QSettings::allKeys_data() void tst_QSettings::allKeys() { +#ifdef QT_BUILD_INTERNAL QFETCH(QSettings::Format, format); QStringList allKeys; @@ -3527,6 +3542,7 @@ void tst_QSettings::allKeys() QCOMPARE(settings.allKeys(), allKeys); } +#endif } void tst_QSettings::registerFormat() diff --git a/tests/auto/qsharedpointer/qsharedpointer.pro b/tests/auto/qsharedpointer/qsharedpointer.pro index 30c81cb..90fde06 100644 --- a/tests/auto/qsharedpointer/qsharedpointer.pro +++ b/tests/auto/qsharedpointer/qsharedpointer.pro @@ -4,5 +4,6 @@ SOURCES += tst_qsharedpointer.cpp \ forwarddeclared.cpp QT = core DEFINES += SRCDIR=\\\"$$PWD/\\\" +requires(contains(QT_CONFIG,private_tests)) include(externaltests.pri) HEADERS += forwarddeclared.h diff --git a/tests/auto/qsocketnotifier/qsocketnotifier.pro b/tests/auto/qsocketnotifier/qsocketnotifier.pro index 10ed3a5..ec924c1 100644 --- a/tests/auto/qsocketnotifier/qsocketnotifier.pro +++ b/tests/auto/qsocketnotifier/qsocketnotifier.pro @@ -2,6 +2,8 @@ load(qttest_p4) SOURCES += tst_qsocketnotifier.cpp QT = core network +requires(contains(QT_CONFIG,private_tests)) + include(../qnativesocketengine/qsocketengine.pri) diff --git a/tests/auto/qsocks5socketengine/qsocks5socketengine.pro b/tests/auto/qsocks5socketengine/qsocks5socketengine.pro index 2949ee2..d19b732 100644 --- a/tests/auto/qsocks5socketengine/qsocks5socketengine.pro +++ b/tests/auto/qsocks5socketengine/qsocks5socketengine.pro @@ -11,3 +11,4 @@ QT = core network +requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index c6b65a4..9c8c313 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -105,7 +105,11 @@ inline static QString qTableName( const QString& prefix, QSqlDriver* driver = 0 inline static bool testWhiteSpaceNames( const QString &name ) { - return name != QLatin1String("QTDS7"); +/* return name.startsWith( "QPSQL" ) + || name.startsWith( "QODBC" ) + || name.startsWith( "QSQLITE" ) + || name.startsWith( "QMYSQL" );*/ + return name != QLatin1String("QSQLITE2"); } inline static QString toHex( const QString& binary ) @@ -245,10 +249,11 @@ public: // addDb( "QODBC3", "DRIVER={SQL Native Client};SERVER=silence.nokia.troll.no\\SQLEXPRESS", "troll", "trond", "" ); // addDb( "QODBC", "DRIVER={MySQL ODBC 3.51 Driver};SERVER=mysql5-nokia.trolltech.com.au;DATABASE=testdb", "testuser", "Ee4Gabf6_", "" ); -// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=horsehead.nokia.troll.no;DATABASE=testdb;PORT=4101;UID=troll;PWD=trondk;TDS_Version=8.0", "troll", "trondk", "" ); -// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=silence.nokia.troll.no;DATABASE=testdb;PORT=2392;UID=troll;PWD=trond;TDS_Version=8.0", "troll", "trond", "" ); -// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=bq-winserv2003-x86-01.apac.nokia.com;DATABASE=testdb;PORT=1433;UID=testuser;PWD=Ee4Gabf6_;TDS_Version=8.0", "testuser", "Ee4Gabf6_", "" ); -// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=bq-winserv2008-x86-01.apac.nokia.com;DATABASE=testdb;PORT=1433;UID=testuser;PWD=Ee4Gabf6_;TDS_Version=8.0", "testuser", "Ee4Gabf6_", "" ); +// addDb( "QODBC", "DRIVER={MySQL ODBC 5.1 Driver};SERVER=mysql4-nokia.trolltech.com.au;DATABASE=testdb", "testuser", "Ee4Gabf6_", "" ); +// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=horsehead.nokia.troll.no;DATABASE=testdb;PORT=4101;UID=troll;PWD=trondk", "troll", "trondk", "" ); +// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=silence.nokia.troll.no;DATABASE=testdb;PORT=2392;UID=troll;PWD=trond", "troll", "trond", "" ); +// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=bq-winserv2003-x86-01.apac.nokia.com;DATABASE=testdb;PORT=1433;UID=testuser;PWD=Ee4Gabf6_;TDS_Version=8.0", "", "", "" ); +// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=bq-winserv2008-x86-01.apac.nokia.com;DATABASE=testdb;PORT=1433;UID=testuser;PWD=Ee4Gabf6_;TDS_Version=8.0", "", "", "" ); // addDb( "QTDS7", "testdb", "testuser", "Ee4Gabf6_", "bq-winserv2003" ); // addDb( "QTDS7", "testdb", "testuser", "Ee4Gabf6_", "bq-winserv2008" ); // addDb( "QODBC3", "DRIVER={SQL SERVER};SERVER=bq-winserv2003-x86-01.apac.nokia.com;DATABASE=testdb;PORT=1433", "testuser", "Ee4Gabf6_", "" ); @@ -469,6 +474,16 @@ public: return db.databaseName().contains( "Access Driver", Qt::CaseInsensitive ); } + static bool isPostgreSQL( QSqlDatabase db ) + { + return db.driverName().startsWith("QPSQL") || (db.driverName().startsWith("QODBC") && db.databaseName().contains("PostgreSQL") ); + } + + static bool isMySQL( QSqlDatabase db ) + { + return db.driverName().startsWith("QMYSQL") || (db.driverName().startsWith("QODBC") && db.databaseName().contains("MySQL") ); + } + // -1 on fail, else Oracle version static int getOraVersion( QSqlDatabase db ) { diff --git a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp index a5095f1..994a3d7 100644 --- a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp +++ b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp @@ -188,7 +188,7 @@ private slots: void oci_fieldLength_data() { generic_data("QOCI"); } void oci_fieldLength(); - void sqlite_bindAndFetchUInt_data() { generic_data("QSQLITE3"); } + void sqlite_bindAndFetchUInt_data() { generic_data("QSQLITE"); } void sqlite_bindAndFetchUInt(); void sqlStatementUseIsNull_189093_data() { generic_data(); } @@ -256,6 +256,8 @@ static int createFieldTable(const FieldDef fieldDefs[], QSqlDatabase db) QString autoName = tst_Databases::autoFieldName(db); if (tst_Databases::isMSAccess(db)) qs.append(" (id int not null"); + else if (tst_Databases::isPostgreSQL(db)) + qs.append(" (id serial not null"); else qs.append(QString("(id integer not null %1 primary key").arg(autoName)); @@ -916,7 +918,7 @@ void tst_QSqlDatabase::recordOCI() FieldDef("varchar(20)", QVariant::String, QString("blah2")), FieldDef("nchar(20)", QVariant::String, QString("blah3")), FieldDef("nvarchar2(20)", QVariant::String, QString("blah4")), - FieldDef("number(10,5)", QVariant::String, 1.1234567), + FieldDef("number(10,5)", QVariant::Double, 1.1234567), FieldDef("date", QVariant::DateTime, dt), #ifdef QT3_SUPPORT //X? FieldDef("long raw", QVariant::ByteArray, QByteArray(Q3CString("blah5"))), @@ -1345,6 +1347,8 @@ void tst_QSqlDatabase::transaction() } QVERIFY_SQL(q, exec("select * from " + qTableName("qtest") + " where id = 41")); + if(db.driverName().startsWith("QODBC") && dbName.contains("MySQL")) + QEXPECT_FAIL("", "Some odbc drivers don't actually roll back despite telling us they do, especially the mysql driver", Continue); QVERIFY(!q.next()); populateTestTables(db); @@ -1422,7 +1426,8 @@ void tst_QSqlDatabase::caseSensivity() bool cs = false; if (db.driverName().startsWith("QMYSQL") || db.driverName().startsWith("QSQLITE") - || db.driverName().startsWith("QTDS")) + || db.driverName().startsWith("QTDS") + || db.driverName().startsWith("QODBC")) cs = true; QSqlRecord rec = db.record(qTableName("qtest")); @@ -1521,6 +1526,7 @@ void tst_QSqlDatabase::psql_escapedIdentifiers() QString field1Name = QString("fIeLdNaMe"); QString field2Name = QString("ZuLu"); + q.exec(QString("DROP SCHEMA \"%1\" CASCADE").arg(schemaName)); QString createSchema = QString("CREATE SCHEMA \"%1\"").arg(schemaName); QVERIFY_SQL(q, exec(createSchema)); QString createTable = QString("CREATE TABLE \"%1\".\"%2\" (\"%3\" int PRIMARY KEY, \"%4\" varchar(20))").arg(schemaName).arg(tableName).arg(field1Name).arg(field2Name); @@ -1652,6 +1658,8 @@ void tst_QSqlDatabase::precisionPolicy() q.setNumericalPrecisionPolicy(QSql::LowPrecisionInt32); QVERIFY_SQL(q, exec(query)); + if(db.driverName().startsWith("QOCI")) + QEXPECT_FAIL("", "Oracle fails to move to next when data columns are oversize", Abort); QVERIFY_SQL(q, next()); if(db.driverName().startsWith("QSQLITE")) QEXPECT_FAIL("", "SQLite returns this value as determined by contents of the field, not the declaration", Continue); @@ -2279,6 +2287,10 @@ void tst_QSqlDatabase::sqlite_bindAndFetchUInt() QFETCH(QString, dbName); QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); + if (db.driverName().startsWith("QSQLITE2")) { + QSKIP("SQLite3 specific test", SkipSingle); + return; + } QSqlQuery q(db); QString tableName = qTableName("uint_test"); diff --git a/tests/auto/qsqldriver/tst_qsqldriver.cpp b/tests/auto/qsqldriver/tst_qsqldriver.cpp index 6d428df..b79c093 100644 --- a/tests/auto/qsqldriver/tst_qsqldriver.cpp +++ b/tests/auto/qsqldriver/tst_qsqldriver.cpp @@ -158,7 +158,7 @@ void tst_QSqlDriver::record() //check that we can't get records using incorrect tablename casing that's been quoted rec = db.driver()->record(db.driver()->escapeIdentifier(tablename,QSqlDriver::TableName)); - if (db.driverName().startsWith("QMYSQL") || db.driverName().startsWith("QSQLITE") || db.driverName().startsWith("QTDS")) + if (tst_Databases::isMySQL(db) || db.driverName().startsWith("QSQLITE") || db.driverName().startsWith("QTDS")) QCOMPARE(rec.count(), 4); //mysql, sqlite and tds will match else QCOMPARE(rec.count(), 0); @@ -204,7 +204,7 @@ void tst_QSqlDriver::primaryIndex() tablename = tablename.toUpper(); index = db.driver()->primaryIndex(db.driver()->escapeIdentifier(tablename, QSqlDriver::TableName)); - if (db.driverName().startsWith("QMYSQL") || db.driverName().startsWith("QSQLITE") || db.driverName().startsWith("QTDS")) + if (tst_Databases::isMySQL(db) || db.driverName().startsWith("QSQLITE") || db.driverName().startsWith("QTDS")) QCOMPARE(index.count(), 1); //mysql will always find the table name regardless of casing else QCOMPARE(index.count(), 0); diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp index ab7f0c9..f3dd920 100644 --- a/tests/auto/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp @@ -188,6 +188,9 @@ private slots: void task_205701_data() { generic_data("QMYSQL"); } void task_205701(); + void task_233829_data() { generic_data("QPSQL"); } + void task_233829(); + private: // returns all database connections @@ -293,6 +296,9 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) << qTableName( "oraRowId" ) << qTableName( "qtest_batch" ); + if ( db.driverName().startsWith("QPSQL") ) + tablenames << qTableName("task_233829"); + if ( db.driverName().startsWith("QSQLITE") ) tablenames << qTableName( "record_sqlite" ); @@ -302,7 +308,7 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) tablenames << qTableName( "qtest_lockedtable" ); tablenames << qTableName( "Planet" ); - + tablenames << qTableName( "task_250026" ); tablenames << qTableName( "task_234422" ); @@ -318,7 +324,10 @@ void tst_QSqlQuery::createTestTables( QSqlDatabase db ) // in the MySQL server startup script q.exec( "set table_type=innodb" ); - QVERIFY_SQL( q, exec( "create table " + qTableName( "qtest" ) + " (id int "+tst_Databases::autoFieldName(db) +" NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id))" ) ); + if(tst_Databases::isPostgreSQL(db)) + QVERIFY_SQL( q, exec( "create table " + qTableName( "qtest" ) + " (id serial NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id)) WITH OIDS" ) ); + else + QVERIFY_SQL( q, exec( "create table " + qTableName( "qtest" ) + " (id int "+tst_Databases::autoFieldName(db) +" NOT NULL, t_varchar varchar(20), t_char char(20), primary key(id))" ) ); if ( tst_Databases::isSqlServer( db ) || db.driverName().startsWith( "QTDS" ) ) QVERIFY_SQL( q, exec( "create table " + qTableName( "qtest_null" ) + " (id int null, t_varchar varchar(20) null)" ) ); @@ -486,7 +495,9 @@ void tst_QSqlQuery::mysqlOutValues() QVERIFY_SQL( q, exec( "create procedure " + qTableName( "qtestproc" ) + " () " "BEGIN select * from " + qTableName( "qtest" ) + " order by id; END" ) ); QVERIFY_SQL( q, exec( "call " + qTableName( "qtestproc" ) + "()" ) ); + QEXPECT_FAIL("", "There's a mysql bug that means only selects think they return data when running in prepared mode", Continue); QVERIFY_SQL( q, next() ); + QEXPECT_FAIL("", "There's a mysql bug that means only selects think they return data when running in prepared mode", Continue); QCOMPARE( q.value( 1 ).toString(), QString( "VarChar1" ) ); QVERIFY_SQL( q, exec( "drop procedure " + qTableName( "qtestproc" ) ) ); @@ -1870,7 +1881,7 @@ void tst_QSqlQuery::invalidQuery() QVERIFY( !q.next() ); QVERIFY( !q.isActive() ); - if ( !db.driverName().startsWith( "QOCI" ) && !db.driverName().startsWith( "QDB2" ) ) { + if ( !db.driverName().startsWith( "QOCI" ) && !db.driverName().startsWith( "QDB2" ) && !db.driverName().startsWith( "QODBC" ) ) { // oracle and db2 just prepares everything without complaining if ( db.driver()->hasFeature( QSqlDriver::PreparedQueries ) ) QVERIFY( !q.prepare( "blahfasel" ) ); @@ -2007,7 +2018,7 @@ void tst_QSqlQuery::oraArrayBind() q.bindValue( 0, list, QSql::In ); - QVERIFY_SQL( q, execBatch( QSqlQuery::ValuesAsRows ) ); + QVERIFY_SQL( q, execBatch( QSqlQuery::ValuesAsColumns ) ); QVERIFY_SQL( q, prepare( "BEGIN " "ora_array_test.get_table(?); " @@ -2019,7 +2030,7 @@ void tst_QSqlQuery::oraArrayBind() q.bindValue( 0, list, QSql::Out ); - QVERIFY_SQL( q, execBatch( QSqlQuery::ValuesAsRows ) ); + QVERIFY_SQL( q, execBatch( QSqlQuery::ValuesAsColumns ) ); QVariantList out_list = q.boundValue( 0 ).toList(); @@ -2565,7 +2576,7 @@ void tst_QSqlQuery::blobsPreparedQuery() QString typeName( "BLOB" ); if ( db.driverName().startsWith( "QPSQL" ) ) typeName = "BYTEA"; - else if ( db.driverName().startsWith( "QODBC" ) ) + else if ( db.driverName().startsWith( "QODBC" ) && tst_Databases::isSqlServer( db )) typeName = "IMAGE"; QVERIFY_SQL( q, exec( QString( "CREATE TABLE %1(id INTEGER, data %2)" ).arg( tableName ).arg( typeName ) ) ); @@ -2771,5 +2782,24 @@ void tst_QSqlQuery::task_234422() #endif +void tst_QSqlQuery::task_233829() +{ + QFETCH( QString, dbName ); + QSqlDatabase db = QSqlDatabase::database( dbName ); + CHECK_DATABASE( db ); + + QSqlQuery q( db ); + QString tableName = qTableName("task_233829"); + QVERIFY_SQL(q,exec("CREATE TABLE " + tableName + "(dbl1 double precision,dbl2 double precision) without oids;")); + + QString queryString("INSERT INTO " + tableName +"(dbl1, dbl2) VALUES(?,?)"); + + double k = 0.0; + QVERIFY_SQL(q,prepare(queryString)); + q.bindValue(0,0.0 / k); // nan + q.bindValue(1,0.0 / k); // nan + QVERIFY_SQL(q,exec()); +} + QTEST_MAIN( tst_QSqlQuery ) #include "tst_qsqlquery.moc" diff --git a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp index d934b35..1e23d3d 100644 --- a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp +++ b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp @@ -145,8 +145,17 @@ void tst_QSqlRelationalTableModel::recreateTestTables(QSqlDatabase db) void tst_QSqlRelationalTableModel::initTestCase() { - foreach (const QString &dbname, dbs.dbNames) - recreateTestTables(QSqlDatabase::database(dbname)); + foreach (const QString &dbname, dbs.dbNames) { + QSqlDatabase db=QSqlDatabase::database(dbname); + if (db.driverName().startsWith("QIBASE")) + db.exec("SET DIALECT 3"); + else if (tst_Databases::isSqlServer(db)) { + QSqlQuery q(db); + QVERIFY_SQL(q, exec("SET ANSI_DEFAULTS ON")); + QVERIFY_SQL(q, exec("SET IMPLICIT_TRANSACTIONS OFF")); + } + recreateTestTables(db); + } } void tst_QSqlRelationalTableModel::cleanupTestCase() @@ -490,6 +499,7 @@ void tst_QSqlRelationalTableModel::insertWithStrategies() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); + model.setSort(0, Qt::AscendingOrder); if (!db.driverName().startsWith("QTDS")) model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); @@ -914,8 +924,8 @@ void tst_QSqlRelationalTableModel::casing() QSqlDatabase db = QSqlDatabase::database(dbName); CHECK_DATABASE(db); - if (db.driverName().startsWith("QSQLITE")) - QSKIP("The casing test for SQLITE is irrelevant since SQLITE is case insensitive", SkipAll); + if (db.driverName().startsWith("QSQLITE") || db.driverName().startsWith("QIBASE") || tst_Databases::isSqlServer(db)) + QSKIP("The casing test for this database is irrelevant since this database does not treat different cases as separate entities", SkipAll); QSqlQuery q(db); QVERIFY_SQL( q, exec("create table " + qTableName("CASETEST1", db.driver()).toUpper() + diff --git a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp index 1445f34..576c190 100644 --- a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp @@ -116,6 +116,8 @@ private slots: void insertRecordsInLoop(); void sqlite_attachedDatabase_data() { generic_data("QSQLITE"); } void sqlite_attachedDatabase(); // For task 130799 + void tableModifyWithBlank_data() { generic_data(); } + void tableModifyWithBlank(); // For mail task private: void generic_data(const QString& engine=QString()); @@ -141,6 +143,7 @@ void tst_QSqlTableModel::dropTestTables() tableNames << qTableName("test") << qTableName("test2") << qTableName("test3") + << qTableName("test4") << qTableName("emptytable") << qTableName("bigtable") << qTableName("foo"); @@ -167,6 +170,8 @@ void tst_QSqlTableModel::createTestTables() QVERIFY_SQL( q, exec("create table " + qTableName("test3") + "(id int, random varchar(20), randomtwo varchar(20))")); + QVERIFY_SQL( q, exec("create table " + qTableName("test4") + "(column1 varchar(50), column2 varchar(50), column3 varchar(50))")); + QVERIFY_SQL( q, exec("create table " + qTableName("emptytable") + "(id int)")); if (testWhiteSpaceNames(db.driverName())) { @@ -927,5 +932,62 @@ void tst_QSqlTableModel::sqlite_attachedDatabase() QCOMPARE(model.data(model.index(0, 1), Qt::DisplayRole).toString(), QLatin1String("main")); } + +void tst_QSqlTableModel::tableModifyWithBlank() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QSqlTableModel model(0, db); + model.setTable(qTableName("test4")); + model.select(); + + //generate a time stamp for the test. Add one second to the current time to make sure + //it is different than the QSqlQuery test. + QString timeString=QDateTime::currentDateTime().addSecs(1).toString(Qt::ISODate); + + //insert a new row, with column0 being the timestamp. + //Should be equivalent to QSqlQuery INSERT INTO... command) + QVERIFY_SQL(model, insertRow(0)); + QVERIFY_SQL(model, setData(model.index(0,0),timeString)); + QVERIFY_SQL(model, submitAll()); + + //set a filter on the table so the only record we get is the one we just made + //I could just do another setData command, but I want to make sure the TableModel + //matches exactly what is stored in the database + model.setFilter("column1='"+timeString+"'"); //filter to get just the newly entered row + QVERIFY_SQL(model, select()); + + //Make sure we only get one record, and that it is the one we just made + QCOMPARE(model.rowCount(), 1); //verify only one entry + QCOMPARE(model.record(0).value(0).toString(), timeString); //verify correct record + + //At this point we know that the intial value (timestamp) was succsefully stored in the database + //Attempt to modify the data in the new record + //equivalent to query.exec("update test set column3="... command in direct test + //set the data in the first column to "col1ModelData" + QVERIFY_SQL(model, setData(model.index(0,1), "col1ModelData")); + + //do a quick check to make sure that the setData command properly set the value in the model + QCOMPARE(model.record(0).value(1).toString(), QLatin1String("col1ModelData")); + + //submit the changed data to the database + //This is where I have been getting errors. + QVERIFY_SQL(model, submitAll()); + + //make sure the model has the most current data for our record + QVERIFY_SQL(model, select()); + + //verify that our new record was the only record returned + QCOMPARE(model.rowCount(), 1); + + //And that the record returned is, in fact, our test record. + QCOMPARE(model.record(0).value(0).toString(), timeString); + + //Make sure the value of the first column matches what we set it to previously. + QCOMPARE(model.record(0).value(1).toString(), QLatin1String("col1ModelData")); +} + QTEST_MAIN(tst_QSqlTableModel) #include "tst_qsqltablemodel.moc" diff --git a/tests/auto/qstandarditemmodel/tst_qstandarditemmodel.cpp b/tests/auto/qstandarditemmodel/tst_qstandarditemmodel.cpp index fa44034..fba7b1b 100644 --- a/tests/auto/qstandarditemmodel/tst_qstandarditemmodel.cpp +++ b/tests/auto/qstandarditemmodel/tst_qstandarditemmodel.cpp @@ -1454,6 +1454,7 @@ static QStandardItem *itemFromText(QStandardItem *parent, const QString &text) return item; } +#ifdef QT_BUILD_INTERNAL static QModelIndex indexFromText(QStandardItemModel *model, const QString &text) { QStandardItem *item = itemFromText(model->invisibleRootItem(), text); @@ -1467,9 +1468,11 @@ struct FriendlyTreeView : public QTreeView friend class tst_QStandardItemModel; Q_DECLARE_PRIVATE(QTreeView) }; +#endif void tst_QStandardItemModel::treeDragAndDrop() { +#ifdef QT_BUILD_INTERNAL const int nRow = 5; const int nCol = 3; @@ -1605,6 +1608,7 @@ void tst_QStandardItemModel::treeDragAndDrop() QVERIFY(compareModels(&model, &checkModel)); } +#endif } void tst_QStandardItemModel::removeRowsAndColumns() diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index a859866..efcb983 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -1015,6 +1015,7 @@ void tst_QStateMachine::rootState() void tst_QStateMachine::addAndRemoveState() { +#ifdef QT_BUILD_INTERNAL QStateMachine machine; QStatePrivate *root_d = QStatePrivate::get(machine.rootState()); QCOMPARE(root_d->childStates().size(), 0); @@ -1075,6 +1076,7 @@ void tst_QStateMachine::addAndRemoveState() delete s2; // ### how to deal with this? // machine.removeState(machine.errorState()); +#endif } void tst_QStateMachine::stateEntryAndExit() diff --git a/tests/auto/qstringbuilder/tst_qstringbuilder.cpp b/tests/auto/qstringbuilder/tst_qstringbuilder.cpp index fdbaf21..72889bc 100644 --- a/tests/auto/qstringbuilder/tst_qstringbuilder.cpp +++ b/tests/auto/qstringbuilder/tst_qstringbuilder.cpp @@ -85,28 +85,18 @@ #undef QT_NO_CAST_TO_ASCII #endif - #include <QtTest/QtTest> //TESTED_CLASS=QStringBuilder //TESTED_FILES=qstringbuilder.cpp -#include <qtest.h> - #define LITERAL "some literal" class tst_QStringBuilder : public QObject { Q_OBJECT -public: - tst_QStringBuilder() {} - ~tst_QStringBuilder() {} - -public slots: - void init() {} - void cleanup() {} - +private slots: void scenario(); }; @@ -119,6 +109,7 @@ void tst_QStringBuilder::scenario() QLatin1Char achar('c'); QString r2(QLatin1String(LITERAL LITERAL)); QString r; + QByteArray ba(LITERAL); r = l1literal P l1literal; QCOMPARE(r, r2); @@ -139,6 +130,10 @@ void tst_QStringBuilder::scenario() QCOMPARE(r, r2); r = LITERAL P string; QCOMPARE(r, r2); + r = ba P string; + QCOMPARE(r, r2); + r = string P ba; + QCOMPARE(r, r2); #endif } diff --git a/tests/auto/qstylesheetstyle/qstylesheetstyle.pro b/tests/auto/qstylesheetstyle/qstylesheetstyle.pro index 6acb0b4..f6101f4 100644 --- a/tests/auto/qstylesheetstyle/qstylesheetstyle.pro +++ b/tests/auto/qstylesheetstyle/qstylesheetstyle.pro @@ -13,3 +13,4 @@ contains(QT_CONFIG, qt3support): QT += qt3support # Input SOURCES += tst_qstylesheetstyle.cpp RESOURCES += resources.qrc +requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index 7b62eae..2bbe897 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -81,6 +81,8 @@ private slots: void paths(); void displayMode(); void strokeInherit(); + void testFillInheritance(); + void testStopOffsetOpacity(); #ifndef QT_NO_COMPRESS void testGzLoading(); @@ -625,9 +627,11 @@ void tst_QSvgRenderer::testGzLoading() QVERIFY(autoDetectGzData.isValid()); } +#ifdef QT_BUILD_INTERNAL QT_BEGIN_NAMESPACE QByteArray qt_inflateGZipDataFrom(QIODevice *device); QT_END_NAMESPACE +#endif void tst_QSvgRenderer::testGzHelper_data() { @@ -660,6 +664,7 @@ void tst_QSvgRenderer::testGzHelper_data() void tst_QSvgRenderer::testGzHelper() { +#ifdef QT_BUILD_INTERNAL QFETCH(QByteArray, in); QFETCH(QByteArray, out); @@ -668,6 +673,7 @@ void tst_QSvgRenderer::testGzHelper() QVERIFY(buffer.isReadable()); QByteArray result = qt_inflateGZipDataFrom(&buffer); QCOMPARE(result, out); +#endif } #endif @@ -1049,5 +1055,155 @@ void tst_QSvgRenderer::strokeInherit() } } +void tst_QSvgRenderer::testFillInheritance() +{ + static const char *svgs[] = { + //reference + "<svg viewBox = \"0 0 200 200\">" + " <polygon points=\"20,20 50,120 100,10 40,80 50,80\" fill= \"red\" stroke = \"blue\" fill-opacity = \"0.5\" fill-rule = \"evenodd\"/>" + "</svg>", + "<svg viewBox = \"0 0 200 200\">" + " <polygon points=\"20,20 50,120 100,10 40,80 50,80\" fill= \"red\" stroke = \"blue\" fill-opacity = \"0.5\" fill-rule = \"evenodd\"/>" + " <rect x = \"40\" y = \"40\" width = \"70\" height =\"20\" fill = \"green\" fill-opacity = \"0\"/>" + "</svg>", + "<svg viewBox = \"0 0 200 200\">" + " <g fill = \"red\" fill-opacity = \"0.5\" fill-rule = \"evenodd\">" + " <polygon points=\"20,20 50,120 100,10 40,80 50,80\" stroke = \"blue\"/>" + " </g>" + " <rect x = \"40\" y = \"40\" width = \"70\" height =\"20\" fill = \"green\" fill-opacity = \"0\"/>" + "</svg>", + "<svg viewBox = \"0 0 200 200\">" + " <g fill = \"green\" fill-rule = \"nonzero\">" + " <polygon points=\"20,20 50,120 100,10 40,80 50,80\" stroke = \"blue\" fill = \"red\" fill-opacity = \"0.5\" fill-rule = \"evenodd\"/>" + " </g>" + " <g fill-opacity = \"0.8\" fill = \"red\">" + " <rect x = \"40\" y = \"40\" width = \"70\" height =\"20\" fill = \"green\" fill-opacity = \"0\"/>" + " </g>" + "</svg>", + "<svg viewBox = \"0 0 200 200\">" + " <g fill = \"red\" >" + " <g fill-opacity = \"0.5\">" + " <g fill-rule = \"evenodd\">" + " <g>" + " <polygon points=\"20,20 50,120 100,10 40,80 50,80\" stroke = \"blue\"/>" + " </g>" + " </g>" + " </g>" + " </g>" + " <g fill-opacity = \"0.8\" >" + " <rect x = \"40\" y = \"40\" width = \"70\" height =\"20\" fill = \"none\"/>" + " </g>" + "</svg>", + "<svg viewBox = \"0 0 200 200\">" + " <g fill = \"none\" fill-opacity = \"0\">" + " <polygon points=\"20,20 50,120 100,10 40,80 50,80\" stroke = \"blue\" fill = \"red\" fill-opacity = \"0.5\" fill-rule = \"evenodd\"/>" + " </g>" + " <g fill-opacity = \"0\" >" + " <rect x = \"40\" y = \"40\" width = \"70\" height =\"20\" fill = \"green\"/>" + " </g>" + "</svg>" + }; + + const int COUNT = sizeof(svgs) / sizeof(svgs[0]); + QImage images[COUNT]; + QPainter p; + + for (int i = 0; i < COUNT; ++i) { + QByteArray data(svgs[i]); + QSvgRenderer renderer(data); + QVERIFY(renderer.isValid()); + images[i] = QImage(200, 200, QImage::Format_ARGB32_Premultiplied); + images[i].fill(-1); + p.begin(&images[i]); + renderer.render(&p); + p.end(); + if (i != 0) { + QCOMPARE(images[0], images[i]); + } + } +} +void tst_QSvgRenderer::testStopOffsetOpacity() +{ + static const char *svgs[] = { + //reference + "<svg viewBox=\"0 0 64 64\">" + "<radialGradient id=\"MyGradient1\" gradientUnits=\"userSpaceOnUse\" cx=\"50\" cy=\"50\" r=\"30\" fx=\"20\" fy=\"20\">" + "<stop offset=\"0.0\" style=\"stop-color:red\" stop-opacity=\"0.3\"/>" + "<stop offset=\"0.5\" style=\"stop-color:green\" stop-opacity=\"1\"/>" + "<stop offset=\"1\" style=\"stop-color:yellow\" stop-opacity=\"1\"/>" + "</radialGradient>" + "<radialGradient id=\"MyGradient2\" gradientUnits=\"userSpaceOnUse\" cx=\"50\" cy=\"70\" r=\"70\" fx=\"20\" fy=\"20\">" + "<stop offset=\"0.0\" style=\"stop-color:blue\" stop-opacity=\"0.3\"/>" + "<stop offset=\"0.5\" style=\"stop-color:violet\" stop-opacity=\"1\"/>" + "<stop offset=\"1\" style=\"stop-color:orange\" stop-opacity=\"1\"/>" + "</radialGradient>" + "<rect x=\"5\" y=\"5\" width=\"55\" height=\"55\" fill=\"url(#MyGradient1)\" stroke=\"black\" />" + "<rect x=\"20\" y=\"20\" width=\"35\" height=\"35\" fill=\"url(#MyGradient2)\"/>" + "</svg>", + //Stop Offset + "<svg viewBox=\"0 0 64 64\">" + "<radialGradient id=\"MyGradient1\" gradientUnits=\"userSpaceOnUse\" cx=\"50\" cy=\"50\" r=\"30\" fx=\"20\" fy=\"20\">" + "<stop offset=\"abc\" style=\"stop-color:red\" stop-opacity=\"0.3\"/>" + "<stop offset=\"0.5\" style=\"stop-color:green\" stop-opacity=\"1\"/>" + "<stop offset=\"1\" style=\"stop-color:yellow\" stop-opacity=\"1\"/>" + "</radialGradient>" + "<radialGradient id=\"MyGradient2\" gradientUnits=\"userSpaceOnUse\" cx=\"50\" cy=\"70\" r=\"70\" fx=\"20\" fy=\"20\">" + "<stop offset=\"-3.bc\" style=\"stop-color:blue\" stop-opacity=\"0.3\"/>" + "<stop offset=\"0.5\" style=\"stop-color:violet\" stop-opacity=\"1\"/>" + "<stop offset=\"1\" style=\"stop-color:orange\" stop-opacity=\"1\"/>" + "</radialGradient>" + "<rect x=\"5\" y=\"5\" width=\"55\" height=\"55\" fill=\"url(#MyGradient1)\" stroke=\"black\" />" + "<rect x=\"20\" y=\"20\" width=\"35\" height=\"35\" fill=\"url(#MyGradient2)\"/>" + "</svg>", + //Stop Opacity + "<svg viewBox=\"0 0 64 64\">" + "<radialGradient id=\"MyGradient1\" gradientUnits=\"userSpaceOnUse\" cx=\"50\" cy=\"50\" r=\"30\" fx=\"20\" fy=\"20\">" + "<stop offset=\"0.0\" style=\"stop-color:red\" stop-opacity=\"0.3\"/>" + "<stop offset=\"0.5\" style=\"stop-color:green\" stop-opacity=\"x.45\"/>" + "<stop offset=\"1\" style=\"stop-color:yellow\" stop-opacity=\"-3.abc\"/>" + "</radialGradient>" + "<radialGradient id=\"MyGradient2\" gradientUnits=\"userSpaceOnUse\" cx=\"50\" cy=\"70\" r=\"70\" fx=\"20\" fy=\"20\">" + "<stop offset=\"0.0\" style=\"stop-color:blue\" stop-opacity=\"0.3\"/>" + "<stop offset=\"0.5\" style=\"stop-color:violet\" stop-opacity=\"-0.xy\"/>" + "<stop offset=\"1\" style=\"stop-color:orange\" stop-opacity=\"z.5\"/>" + "</radialGradient>" + "<rect x=\"5\" y=\"5\" width=\"55\" height=\"55\" fill=\"url(#MyGradient1)\" stroke=\"black\" />" + "<rect x=\"20\" y=\"20\" width=\"35\" height=\"35\" fill=\"url(#MyGradient2)\"/>" + "</svg>", + //Stop offset and Stop opacity + "<svg viewBox=\"0 0 64 64\">" + "<radialGradient id=\"MyGradient1\" gradientUnits=\"userSpaceOnUse\" cx=\"50\" cy=\"50\" r=\"30\" fx=\"20\" fy=\"20\">" + "<stop offset=\"abc\" style=\"stop-color:red\" stop-opacity=\"0.3\"/>" + "<stop offset=\"0.5\" style=\"stop-color:green\" stop-opacity=\"x.45\"/>" + "<stop offset=\"1\" style=\"stop-color:yellow\" stop-opacity=\"-3.abc\"/>" + "</radialGradient>" + "<radialGradient id=\"MyGradient2\" gradientUnits=\"userSpaceOnUse\" cx=\"50\" cy=\"70\" r=\"70\" fx=\"20\" fy=\"20\">" + "<stop offset=\"-3.bc\" style=\"stop-color:blue\" stop-opacity=\"0.3\"/>" + "<stop offset=\"0.5\" style=\"stop-color:violet\" stop-opacity=\"-0.xy\"/>" + "<stop offset=\"1\" style=\"stop-color:orange\" stop-opacity=\"z.5\"/>" + "</radialGradient>" + "<rect x=\"5\" y=\"5\" width=\"55\" height=\"55\" fill=\"url(#MyGradient1)\" stroke=\"black\" />" + "<rect x=\"20\" y=\"20\" width=\"35\" height=\"35\" fill=\"url(#MyGradient2)\"/>" + "</svg>" + }; + + QImage images[4]; + QPainter p; + + for (int i = 0; i < 4; ++i) { + QByteArray data(svgs[i]); + QSvgRenderer renderer(data); + QVERIFY(renderer.isValid()); + images[i] = QImage(64, 64, QImage::Format_ARGB32_Premultiplied); + images[i].fill(-1); + p.begin(&images[i]); + renderer.render(&p); + p.end(); + } + QCOMPARE(images[0], images[1]); + QCOMPARE(images[0], images[2]); + QCOMPARE(images[0], images[3]); +} + QTEST_MAIN(tst_QSvgRenderer) #include "tst_qsvgrenderer.moc" diff --git a/tests/auto/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp b/tests/auto/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp index 22e9455..1699e72 100644 --- a/tests/auto/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp +++ b/tests/auto/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp @@ -99,7 +99,8 @@ private slots: void avoidUnnecessaryRehighlight(); void noContentsChangedDuringHighlight(); void rehighlight(); - + void rehighlightBlock(); + private: QTextDocument *doc; QTestDocumentLayout *lout; @@ -517,6 +518,32 @@ void tst_QSyntaxHighlighter::rehighlight() QCOMPARE(hl->callCount, 1); } +void tst_QSyntaxHighlighter::rehighlightBlock() +{ + TestHighlighter *hl = new TestHighlighter(doc); + + cursor.movePosition(QTextCursor::Start); + cursor.beginEditBlock(); + cursor.insertText("Hello"); + cursor.insertBlock(); + cursor.insertText("World"); + cursor.endEditBlock(); + + hl->callCount = 0; + hl->highlightedText.clear(); + QTextBlock block = doc->begin(); + hl->rehighlightBlock(block); + + QCOMPARE(hl->highlightedText, QString("Hello")); + QCOMPARE(hl->callCount, 1); + + hl->callCount = 0; + hl->highlightedText.clear(); + hl->rehighlightBlock(block.next()); + + QCOMPARE(hl->highlightedText, QString("World")); + QCOMPARE(hl->callCount, 1); +} QTEST_MAIN(tst_QSyntaxHighlighter) #include "tst_qsyntaxhighlighter.moc" diff --git a/tests/auto/qtableview/tst_qtableview.cpp b/tests/auto/qtableview/tst_qtableview.cpp index ae023ba..6fa57f0 100644 --- a/tests/auto/qtableview/tst_qtableview.cpp +++ b/tests/auto/qtableview/tst_qtableview.cpp @@ -175,6 +175,8 @@ private slots: // task-specific tests: void task173773_updateVerticalHeader(); void task227953_setRootIndex(); + void task240266_veryBigColumn(); + void task248688_autoScrollNavigation(); void mouseWheel_data(); void mouseWheel(); @@ -586,7 +588,7 @@ void tst_QTableView::keyboardNavigation() QModelIndex index = model.index(rowCount - 1, columnCount - 1); view.setCurrentIndex(index); - QApplication::instance()->processEvents(); + QApplication::processEvents(); int row = rowCount - 1; int column = columnCount - 1; @@ -618,7 +620,7 @@ void tst_QTableView::keyboardNavigation() } QTest::keyClick(&view, key); - QApplication::instance()->processEvents(); + QApplication::processEvents(); QModelIndex index = model.index(row, column); QCOMPARE(view.currentIndex(), index); @@ -3127,6 +3129,56 @@ void tst_QTableView::task227953_setRootIndex() QVERIFY(!tableView.verticalHeader()->isHidden()); } +void tst_QTableView::task240266_veryBigColumn() +{ + QTableView table; + table.setFixedSize(500, 300); //just to make sure we have the 2 first columns visible + QStandardItemModel model(1, 3); + table.setModel(&model); + table.setColumnWidth(0, 100); //normal column + table.setColumnWidth(1, 100); //normal column + table.setColumnWidth(2, 9000); //very big column + table.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(100); + + QScrollBar *scroll = table.horizontalScrollBar(); + QCOMPARE(scroll->minimum(), 0); + QCOMPARE(scroll->maximum(), model.columnCount() - 1); + QCOMPARE(scroll->singleStep(), 1); + + //1 is not always a very correct value for pageStep. Ideally this should be dynamic. + //Maybe something for Qt 5 ;-) + QCOMPARE(scroll->pageStep(), 1); + +} + +void tst_QTableView::task248688_autoScrollNavigation() +{ + //we make sure that when navigating with the keyboard the view is correctly scrolled + //to the current item + QStandardItemModel model(16, 16); + QTableView view; + view.setModel(&model); + + view.hideColumn(8); + view.hideRow(8); + view.show(); + for (int r = 0; r < model.rowCount(); ++r) { + if (view.isRowHidden(r)) + continue; + for (int c = 0; c < model.columnCount(); ++c) { + if (view.isColumnHidden(c)) + continue; + QModelIndex index = model.index(r, c); + view.setCurrentIndex(index); + QVERIFY(view.viewport()->rect().contains(view.visualRect(index))); + } + } +} + void tst_QTableView::mouseWheel_data() { diff --git a/tests/auto/qtextedit/tst_qtextedit.cpp b/tests/auto/qtextedit/tst_qtextedit.cpp index 3bc1517..d54645c 100644 --- a/tests/auto/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/qtextedit/tst_qtextedit.cpp @@ -1460,6 +1460,7 @@ void tst_QTextEdit::mimeDataReimplementations() QCOMPARE(ed.canInsertCallCount, 0); QCOMPARE(ed.insertCallCount, 0); +#ifdef QT_BUILD_INTERNAL QTextControl *control = qFindChild<QTextControl *>(&ed); QVERIFY(control); @@ -1474,6 +1475,7 @@ void tst_QTextEdit::mimeDataReimplementations() QCOMPARE(ed.createMimeDataCallCount, 1); QCOMPARE(ed.canInsertCallCount, 1); QCOMPARE(ed.insertCallCount, 1); +#endif } void tst_QTextEdit::ctrlEnterShouldInsertLineSeparator_NOT() @@ -2066,6 +2068,7 @@ void tst_QTextEdit::cursorRect() void tst_QTextEdit::setDocumentPreservesPalette() { +#ifdef QT_BUILD_INTERNAL QTextControl *control = qFindChild<QTextControl *>(ed); QVERIFY(control); @@ -2085,6 +2088,7 @@ void tst_QTextEdit::setDocumentPreservesPalette() QVERIFY(control->document() == newDoc); QVERIFY(whitePal.color(QPalette::Active, QPalette::Text) == control->palette().color(QPalette::Active, QPalette::Text)); +#endif } class PublicTextEdit : public QTextEdit diff --git a/tests/auto/qtextpiecetable/qtextpiecetable.pro b/tests/auto/qtextpiecetable/qtextpiecetable.pro index 318a8c7..0926b83 100644 --- a/tests/auto/qtextpiecetable/qtextpiecetable.pro +++ b/tests/auto/qtextpiecetable/qtextpiecetable.pro @@ -2,7 +2,6 @@ load(qttest_p4) SOURCES += tst_qtextpiecetable.cpp HEADERS += ../qtextdocument/common.h -!win32:DEFINES += QTEST_REDUCED_EXPORTS - - +requires(!win32) +requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/qtextpiecetable/tst_qtextpiecetable.cpp b/tests/auto/qtextpiecetable/tst_qtextpiecetable.cpp index accbabb..0e60c16 100644 --- a/tests/auto/qtextpiecetable/tst_qtextpiecetable.cpp +++ b/tests/auto/qtextpiecetable/tst_qtextpiecetable.cpp @@ -42,9 +42,7 @@ #include <QtTest/QtTest> -#ifdef QTEST_REDUCED_EXPORTS #define private public -#endif #include <qtextdocument.h> #include <private/qtextdocument_p.h> @@ -65,7 +63,6 @@ public: tst_QTextPieceTable(); -#ifdef QTEST_REDUCED_EXPORTS public slots: void init(); void cleanup(); @@ -112,13 +109,7 @@ private slots: void removeFrameDirect(); void removeWithChildFrame(); void clearWithFrames(); -#else -public slots: - void init(); - void cleanup(); -private slots: - void skip(); -#endif + private: QTextDocument *doc; QTextDocumentPrivate *table; @@ -130,8 +121,6 @@ tst_QTextPieceTable::tst_QTextPieceTable() { doc = 0; table = 0; } -#ifdef QTEST_REDUCED_EXPORTS - void tst_QTextPieceTable::init() { doc = new QTextDocument(0); @@ -1148,25 +1137,6 @@ void tst_QTextPieceTable::clearWithFrames() QVERIFY(true); } -#else // QTEST_REDUCED_EXPORTS - -void tst_QTextPieceTable::init() -{ -} - -void tst_QTextPieceTable::cleanup() -{ -} - -void tst_QTextPieceTable::skip() -{ - QSKIP( "Not tested on win32", SkipAll ); -} - - -#endif // QTEST_REDUCED_EXPORTS - - QTEST_MAIN(tst_QTextPieceTable) diff --git a/tests/auto/qurl/tst_qurl.cpp b/tests/auto/qurl/tst_qurl.cpp index ea551da..723f882 100644 --- a/tests/auto/qurl/tst_qurl.cpp +++ b/tests/auto/qurl/tst_qurl.cpp @@ -3057,12 +3057,15 @@ void tst_QUrl::nameprep_testsuite_data() << QString() << 0 << 0; } +#ifdef QT_BUILD_INTERNAL QT_BEGIN_NAMESPACE extern QString qt_nameprep(const QString &source); QT_END_NAMESPACE +#endif void tst_QUrl::nameprep_testsuite() { +#ifdef QT_BUILD_INTERNAL QFETCH(QString, in); QFETCH(QString, out); QFETCH(QString, profile); @@ -3082,6 +3085,7 @@ void tst_QUrl::nameprep_testsuite() QEXPECT_FAIL("Larger test (expanding)", "Investigate further", Continue); QCOMPARE(qt_nameprep(in), out); +#endif } void tst_QUrl::ace_testsuite_data() diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index fa36496..0f0a1af 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -351,6 +351,7 @@ private slots: #endif void updateOnDestroyedSignal(); void toplevelLineEditFocus(); + void inputFocus_task257832(); void focusWidget_task254563(); void rectOutsideCoordinatesLimit_task144779(); @@ -9152,5 +9153,19 @@ void tst_QWidget::rectOutsideCoordinatesLimit_task144779() QCOMPARE(pixmap.toImage().copy(center), correct.toImage().copy(center)); } +void tst_QWidget::inputFocus_task257832() +{ + QLineEdit *widget = new QLineEdit; + QInputContext *context = widget->inputContext(); + if (!context) + QSKIP("No input context", SkipSingle); + widget->setFocus(); + context->setFocusWidget(widget); + QCOMPARE(context->focusWidget(), widget); + widget->setReadOnly(true); + QVERIFY(!context->focusWidget()); + delete widget; +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" diff --git a/tests/auto/xmlpatternsdiagnosticsts/xmlpatternsdiagnosticsts.pro b/tests/auto/xmlpatternsdiagnosticsts/xmlpatternsdiagnosticsts.pro index e90b335..3d82eaf 100644 --- a/tests/auto/xmlpatternsdiagnosticsts/xmlpatternsdiagnosticsts.pro +++ b/tests/auto/xmlpatternsdiagnosticsts/xmlpatternsdiagnosticsts.pro @@ -2,3 +2,4 @@ TEMPLATE = subdirs CONFIG += ordered SUBDIRS = ../xmlpatternsxqts test +requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/xmlpatternsview/xmlpatternsview.pro b/tests/auto/xmlpatternsview/xmlpatternsview.pro index 3544264..04ee4d0 100644 --- a/tests/auto/xmlpatternsview/xmlpatternsview.pro +++ b/tests/auto/xmlpatternsview/xmlpatternsview.pro @@ -6,3 +6,4 @@ SUBDIRS = ../xmlpatternsxqts test contains(QT_CONFIG,xmlpatterns) { SUBDIRS += view } +requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/xmlpatternsxqts/xmlpatternsxqts.pro b/tests/auto/xmlpatternsxqts/xmlpatternsxqts.pro index 368a028..a3b13da 100644 --- a/tests/auto/xmlpatternsxqts/xmlpatternsxqts.pro +++ b/tests/auto/xmlpatternsxqts/xmlpatternsxqts.pro @@ -9,3 +9,6 @@ contains(QT_CONFIG,xmlpatterns) { # Needed on the win32-g++ setup and on the test machine arsia. INCLUDEPATH += $$QT_BUILD_TREE/include/QtXmlPatterns/private \ ../../../include/QtXmlPatterns/private + +requires(contains(QT_CONFIG,private_tests)) + diff --git a/tests/auto/xmlpatternsxslts/xmlpatternsxslts.pro b/tests/auto/xmlpatternsxslts/xmlpatternsxslts.pro index 4a688c4..9b63a52 100644 --- a/tests/auto/xmlpatternsxslts/xmlpatternsxslts.pro +++ b/tests/auto/xmlpatternsxslts/xmlpatternsxslts.pro @@ -23,3 +23,4 @@ wince*: { DEPLOYMENT += testdata } +requires(contains(QT_CONFIG,private_tests)) diff --git a/tools/assistant/lib/qhelpsearchengine.cpp b/tools/assistant/lib/qhelpsearchengine.cpp index 9faafe0..2a41d04 100644 --- a/tools/assistant/lib/qhelpsearchengine.cpp +++ b/tools/assistant/lib/qhelpsearchengine.cpp @@ -84,18 +84,17 @@ private: , resultWidget(0) , helpEngine(helpEngine) { - hitList.clear(); indexReader = 0; indexWriter = 0; } ~QHelpSearchEnginePrivate() { - hitList.clear(); delete indexReader; delete indexWriter; } + int hitsCount() const { int count = 0; @@ -107,12 +106,9 @@ private: QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const { - QList<QHelpSearchEngine::SearchHit> returnValue; - if (indexReader) { - for (int i = start; i < end && i < hitsCount(); ++i) - returnValue.append(indexReader->hit(i)); - } - return returnValue; + return indexReader ? + indexReader->hits(start, end) : + QList<QHelpSearchEngine::SearchHit>(); } void updateIndex(bool reindex = false) @@ -131,11 +127,9 @@ private: connect(indexWriter, SIGNAL(indexingFinished()), this, SLOT(optimizeIndex())); } - if (indexWriter) { - indexWriter->cancelIndexing(); - indexWriter->updateIndex(helpEngine->collectionFile(), - indexFilesFolder(), reindex); - } + indexWriter->cancelIndexing(); + indexWriter->updateIndex(helpEngine->collectionFile(), + indexFilesFolder(), reindex); } void cancelIndexing() @@ -159,11 +153,9 @@ private: connect(indexReader, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int))); } - if (indexReader) { - m_queryList = queryList; - indexReader->cancelSearching(); - indexReader->search(helpEngine->collectionFile(), indexFilesFolder(), queryList); - } + m_queryList = queryList; + indexReader->cancelSearching(); + indexReader->search(helpEngine->collectionFile(), indexFilesFolder(), queryList); } void cancelSearching() @@ -204,7 +196,6 @@ private: QHelpSearchIndexWriter *indexWriter; QPointer<QHelpEngineCore> helpEngine; - QList<QHelpSearchEngine::SearchHit> hitList; QList<QHelpSearchQuery> m_queryList; }; diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp index 227e558..89d6040 100644 --- a/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp @@ -70,7 +70,6 @@ QHelpSearchIndexReader::~QHelpSearchIndexReader() { mutex.lock(); this->m_cancel = true; - waitCondition.wakeOne(); mutex.unlock(); wait(); @@ -86,8 +85,8 @@ void QHelpSearchIndexReader::cancelSearching() void QHelpSearchIndexReader::search(const QString &collectionFile, const QString &indexFilesFolder, const QList<QHelpSearchQuery> &queryList) { - QMutexLocker lock(&mutex); - + wait(); + this->hitList.clear(); this->m_cancel = false; this->m_query = queryList; @@ -99,12 +98,18 @@ void QHelpSearchIndexReader::search(const QString &collectionFile, const QString int QHelpSearchIndexReader::hitsCount() const { + QMutexLocker lock(&mutex); return hitList.count(); } -QHelpSearchEngine::SearchHit QHelpSearchIndexReader::hit(int index) const +QList<QHelpSearchEngine::SearchHit> QHelpSearchIndexReader::hits(int start, + int end) const { - return hitList.at(index); + QList<QHelpSearchEngine::SearchHit> hits; + QMutexLocker lock(&mutex); + for (int i = start; i < end && i < hitList.count(); ++i) + hits.append(hitList.at(i)); + return hits; } void QHelpSearchIndexReader::run() @@ -135,7 +140,7 @@ void QHelpSearchIndexReader::run() if(QCLuceneIndexReader::indexExists(indexPath)) { mutex.lock(); if (m_cancel) { - mutex.unlock(); + mutex.unlock(); return; } mutex.unlock(); @@ -213,7 +218,9 @@ void QHelpSearchIndexReader::run() #if !defined(QT_NO_EXCEPTIONS) } catch(...) { + mutex.lock(); hitList.clear(); + mutex.unlock(); emit searchingFinished(0); } #endif @@ -416,8 +423,9 @@ void QHelpSearchIndexReader::boostSearchHits(const QHelpEngineCore &engine, boostedList.append(it.value()); } while (it != hitMap.constBegin()); boostedList += hitList.mid(count, hitList.count()); - + mutex.lock(); hitList = boostedList; + mutex.unlock(); } } diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h index 47af43f..8876d80 100644 --- a/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h @@ -85,9 +85,8 @@ public: void search(const QString &collectionFile, const QString &indexFilesFolder, const QList<QHelpSearchQuery> &queryList); - int hitsCount() const; - QHelpSearchEngine::SearchHit hit(int index) const; + QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const; signals: void searchingStarted(); @@ -105,10 +104,8 @@ private: const QList<QHelpSearchQuery> &queryList); private: - QMutex mutex; + mutable QMutex mutex; QList<QHelpSearchEngine::SearchHit> hitList; - QWaitCondition waitCondition; - bool m_cancel; QString m_collectionFile; QList<QHelpSearchQuery> m_query; diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 509444b..80cfc64 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1135,6 +1135,10 @@ void Configure::parseCmdLine() useUnixSeparators = (dictionary["QMAKESPEC"] == "win32-g++"); + // Allow tests for private classes to be compiled against internal builds + if (dictionary["BUILDDEV"] == "yes") + qtConfig += "private_tests"; + #if !defined(EVAL) for( QStringList::Iterator dis = disabledModules.begin(); dis != disabledModules.end(); ++dis ) { @@ -1521,7 +1525,7 @@ bool Configure::displayHelp() desc( "-graphicssystem <sys>", "Specify which graphicssystem should be used.\n" "Available values for <sys>:"); desc("GRAPHICS_SYSTEM", "raster", "", " raster - Software rasterizer", ' '); - desc("GRAPHICS_SYSTEM", "opengl", "", " opengl - Using OpenGL accelleration, experimental!", ' '); + desc("GRAPHICS_SYSTEM", "opengl", "", " opengl - Using OpenGL acceleration, experimental!", ' '); desc( "-help, -h, -?", "Display this information.\n"); @@ -1997,7 +2001,6 @@ bool Configure::verifyConfiguration() no-gif gif dll staticlib - internal nocrosscompiler GNUmake largefile diff --git a/tools/designer/src/designer/qdesigner_workbench.cpp b/tools/designer/src/designer/qdesigner_workbench.cpp index f21da8c..2ac9e1f 100644 --- a/tools/designer/src/designer/qdesigner_workbench.cpp +++ b/tools/designer/src/designer/qdesigner_workbench.cpp @@ -410,6 +410,12 @@ void QDesignerWorkbench::switchToDockedMode() switchToNeutralMode(); +#ifndef Q_WS_MAC + QDesignerToolWindow *widgetBoxWrapper = widgetBoxToolWindow(); + widgetBoxWrapper->action()->setVisible(true); + widgetBoxWrapper->setWindowTitle(tr("Widget Box")); +#endif + m_mode = DockedMode; const QDesignerSettings settings(m_core); m_dockedMainWindow = new DockedMainWindow(this, m_toolbarMenu, m_toolWindows); @@ -462,8 +468,6 @@ void QDesignerWorkbench::switchToTopLevelMode() // make sure that the widgetbox is visible if it is different from neutral. QDesignerToolWindow *widgetBoxWrapper = widgetBoxToolWindow(); Q_ASSERT(widgetBoxWrapper); - if (!widgetBoxWrapper->action()->isChecked()) - widgetBoxWrapper->action()->trigger(); switchToNeutralMode(); const QPoint desktopOffset = desktopGeometry().topLeft(); @@ -502,9 +506,6 @@ void QDesignerWorkbench::switchToTopLevelMode() found_visible_window |= tw->isVisible(); } - if (!widgetBoxWrapper->action()->isChecked()) - widgetBoxWrapper->action()->trigger(); - if (!m_toolWindows.isEmpty() && !found_visible_window) m_toolWindows.first()->show(); diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp index c9250c6..a531af8 100644 --- a/tools/linguist/lupdate/main.cpp +++ b/tools/linguist/lupdate/main.cpp @@ -182,9 +182,10 @@ static void updateTsFiles(const Translator &fetchedTor, const QStringList &tsFil if (options & Verbose) printOut(QObject::tr("Updating '%1'...\n").arg(fn)); + UpdateOptions theseOptions = options; if (tor.locationsType() == Translator::NoLocations) // Could be set from file - options |= NoLocations; - Translator out = merge(tor, fetchedTor, options, err); + theseOptions |= NoLocations; + Translator out = merge(tor, fetchedTor, theseOptions, err); if (!codecForTr.isEmpty()) out.setCodecName(codecForTr); diff --git a/tools/linguist/phrasebooks/french.qph b/tools/linguist/phrasebooks/french.qph index f244013..d38da5a 100644 --- a/tools/linguist/phrasebooks/french.qph +++ b/tools/linguist/phrasebooks/french.qph @@ -1,4 +1,5 @@ -<!DOCTYPE QPH><QPH language="fr"> +<!DOCTYPE QPH> +<QPH language="fr"> <phrase> <source>About</source> <target>A propos</target> @@ -1101,4 +1102,228 @@ <source>Yes</source> <target>Oui</target> </phrase> +<phrase> + <source>Split</source> + <target>Scinder</target> +</phrase> +<phrase> + <source>&Edit</source> + <target>&Édition</target> +</phrase> +<phrase> + <source>&Redo</source> + <target>Re&faire</target> +</phrase> +<phrase> + <source>debugger</source> + <target>débogueur</target> +</phrase> +<phrase> + <source>Start Debugger</source> + <target>Lancer le débogueur</target> +</phrase> +<phrase> + <source>Executable:</source> + <target>Exécutable:</target> +</phrase> +<phrase> + <source>Filter:</source> + <target>Filtre:</target> +</phrase> +<phrase> + <source>Clear</source> + <target>Effacer</target> +</phrase> +<phrase> + <source>Host and port:</source> + <target>Hôte et port:</target> +</phrase> +<phrase> + <source>Architecture:</source> + <target>Architecture:</target> +</phrase> +<phrase> + <source>Server start script:</source> + <target>Script de démarrage du serveur:</target> +</phrase> +<phrase> + <source>&Undo</source> + <target>Annu&ler</target> +</phrase> +<phrase> + <source>Add Bookmark</source> + <target>Ajouter un signet</target> +</phrase> +<phrase> + <source>Bookmark:</source> + <target>Signet:</target> +</phrase> +<phrase> + <source>Add in Folder:</source> + <target>Ajouter dans le dossier:</target> +</phrase> +<phrase> + <source>+</source> + <target>+</target> +</phrase> +<phrase> + <source>New Folder</source> + <target>Nouveau dossier</target> +</phrase> +<phrase> + <source>Bookmarks</source> + <target>Signets</target> +</phrase> +<phrase> + <source>Rename Folder</source> + <target>Renommer le dossier</target> +</phrase> +<phrase> + <source>Bookmark</source> + <target>Signet</target> +</phrase> +<phrase> + <source>Remove</source> + <target>Retirer</target> +</phrase> +<phrase> + <source>Delete Folder</source> + <target>Supprimer le dossier</target> +</phrase> +<phrase> + <source>Add</source> + <target>Ajouter</target> +</phrase> +<phrase> + <source>Move Up</source> + <target>Vers le Haut</target> +</phrase> +<phrase> + <source>Move Down</source> + <target>Vers le Bas</target> +</phrase> +<phrase> + <source>Show Bookmark</source> + <target>Afficher le signet</target> +</phrase> +<phrase> + <source>Show Bookmark in New Tab</source> + <target>Afficher le signet dans un nouvel onglet</target> +</phrase> +<phrase> + <source>Delete Bookmark</source> + <target>Supprimer le signet</target> +</phrase> +<phrase> + <source>Rename Bookmark</source> + <target>Renommer le signet</target> +</phrase> +<phrase> + <source>Previous Bookmark</source> + <target>Signet précédent</target> +</phrase> +<phrase> + <source>Next Bookmark</source> + <target>Signet suivant</target> +</phrase> +<phrase> + <source>Condition:</source> + <target>Condition:</target> +</phrase> +<phrase> + <source>Working Directory:</source> + <target>Répertoire de travail:</target> +</phrase> +<phrase> + <source>Environment</source> + <target>Environnement</target> +</phrase> +<phrase> + <source>Arguments</source> + <target>Arguments</target> +</phrase> +<phrase> + <source>Build directory:</source> + <target>Répertoire de compilation:</target> +</phrase> +<phrase> + <source>Path:</source> + <target>Chemin:</target> +</phrase> +<phrase> + <source>General</source> + <target>Général</target> +</phrase> +<phrase> + <source>Username:</source> + <target>Nom d'utilisateur:</target> +</phrase> +<phrase> + <source>User interface</source> + <target>Interface utilisateur</target> +</phrase> +<phrase> + <source>Open Link</source> + <target>Ouvrir le lien</target> +</phrase> +<phrase> + <source> [read only]</source> + <target> [lecture seule]</target> +</phrase> +<phrase> + <source> [directory]</source> + <target> [répertoire]</target> +</phrase> +<phrase> + <source>Close All</source> + <target>Fermer tout</target> +</phrase> +<phrase> + <source>Failed!</source> + <target>Échec!</target> +</phrase> +<phrase> + <source>Proceed</source> + <target>Continuer</target> +</phrase> +<phrase> + <source>Make writable</source> + <target>Rendre inscriptible</target> +</phrase> +<phrase> + <source>Qt Creator</source> + <target>Qt Creator</target> +</phrase> +<phrase> + <source>&File</source> + <target>&Fichier</target> +</phrase> +<phrase> + <source>Activate %1</source> + <target>Activer %1</target> +</phrase> +<phrase> + <source>New Project</source> + <target>Nouveau projet</target> +</phrase> +<phrase> + <source>Close %1</source> + <target>Fermer %1</target> +</phrase> +<phrase> + <source>*</source> + <target>*</target> +</phrase> +<phrase> + <source>&Change</source> + <target>&Modifier</target> +</phrase> +<phrase> + <source>Close Other Editors</source> + <target>Fermer les autres éditeurs</target> +</phrase> +<phrase> + <source>Close All Except %1</source> + <target>Fermer tout sauf %1</target> +</phrase> </QPH> diff --git a/tools/linguist/phrasebooks/russian.qph b/tools/linguist/phrasebooks/russian.qph index 629c60b..69af041 100644 --- a/tools/linguist/phrasebooks/russian.qph +++ b/tools/linguist/phrasebooks/russian.qph @@ -10,7 +10,7 @@ </phrase> <phrase> <source>accessibility</source> - <target>удобство</target> + <target>специальные возможности</target> </phrase> <phrase> <source>action handle</source> @@ -345,8 +345,8 @@ <target>активная зона</target> </phrase> <phrase> - <source>icon</source> - <target>пиктограмма</target> + <source>Icon</source> + <target>Значок</target> </phrase> <phrase> <source>inactive</source> @@ -402,7 +402,7 @@ </phrase> <phrase> <source>list view</source> - <target>древовидный список</target> + <target>список</target> </phrase> <phrase> <source>manual link</source> @@ -901,10 +901,6 @@ <target>панель инструментов</target> </phrase> <phrase> - <source>tooltip</source> - <target>всплывающая подсказка</target> -</phrase> -<phrase> <source>tree view control</source> <target>древовидный список</target> </phrase> @@ -1054,10 +1050,46 @@ </phrase> <phrase> <source>Case Sensitive</source> - <target>Регистрозависимо</target> + <target>Учитывать регистр</target> </phrase> <phrase> <source>Whole words</source> - <target>Слова полностью</target> + <target>Слова целиком</target> +</phrase> +<phrase> + <source>Find Next</source> + <target>Найти следующее</target> +</phrase> +<phrase> + <source>Find Previous</source> + <target>Найти предыдущее</target> +</phrase> +<phrase> + <source>Case Sensitive</source> + <target>Учитывать регистр символов</target> +</phrase> +<phrase> + <source>Whole words only</source> + <target>Только слова целиком</target> +</phrase> +<phrase> + <source>Subwindow</source> + <target>Дочернее окно</target> +</phrase> +<phrase> + <source>Next</source> + <target>Далее</target> +</phrase> +<phrase> + <source>tree view</source> + <target>древовидный список</target> +</phrase> +<phrase> + <source>ToolTip</source> + <target>Подсказка</target> +</phrase> +<phrase> + <source>Checkable</source> + <target>Переключаемое</target> </phrase> </QPH> diff --git a/tools/linguist/shared/profileevaluator.cpp b/tools/linguist/shared/profileevaluator.cpp index 47c1ec2..a962152 100644 --- a/tools/linguist/shared/profileevaluator.cpp +++ b/tools/linguist/shared/profileevaluator.cpp @@ -68,8 +68,10 @@ #ifdef Q_OS_WIN32 #define QT_POPEN _popen +#define QT_PCLOSE _pclose #else #define QT_POPEN popen +#define QT_PCLOSE pclose #endif QT_BEGIN_NAMESPACE @@ -1513,6 +1515,8 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun output += QLatin1String(buff); } ret += split_value_list(output); + if (proc) + QT_PCLOSE(proc); } } break; @@ -2067,7 +2071,7 @@ bool ProFileEvaluator::Private::evaluateFile(const QString &fileName, bool *resu ProFile *pro = q->parsedProFile(fileName); if (pro) { m_profileStack.push(pro); - ok = (currentProFile() ? pro->Accept(this) : false); + ok = pro->Accept(this); m_profileStack.pop(); q->releaseParsedProFile(pro); @@ -2077,16 +2081,6 @@ bool ProFileEvaluator::Private::evaluateFile(const QString &fileName, bool *resu if (result) *result = false; } -/* if (ok && readFeatures) { - QStringList configs = values("CONFIG"); - QSet<QString> processed; - foreach (const QString &fn, configs) { - if (!processed.contains(fn)) { - processed.insert(fn); - evaluateFeatureFile(fn, 0); - } - } - } */ return ok; } diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp index 222b9a1..d5aca0e 100644 --- a/tools/qdoc3/doc.cpp +++ b/tools/qdoc3/doc.cpp @@ -1677,10 +1677,13 @@ void DocParser::startSection(Doc::SectioningUnit unit, int cmd) leavePara(); if (currentSectioningUnit == Doc::Book) { +#if 0 + // mws didn't think this was necessary. if (unit > Doc::Section1) location().warning(tr("Unexpected '\\%1' without '\\%2'") .arg(cmdName(cmd)) .arg(cmdName(CMD_SECTION1))); +#endif currentSectioningUnit = (Doc::SectioningUnit) (unit - 1); priv->constructExtra(); priv->extra->sectioningUnit = currentSectioningUnit; diff --git a/tools/qtconfig/translations/translations.pro b/tools/qtconfig/translations/translations.pro index fbbdb2bba2..1f9f572 100644 --- a/tools/qtconfig/translations/translations.pro +++ b/tools/qtconfig/translations/translations.pro @@ -8,6 +8,7 @@ HEADERS += ../colorbutton.h ../previewframe.h ../previewwidget.h ../mainw FORMS = ../mainwindowbase.ui ../paletteeditoradvancedbase.ui ../previewwidgetbase.ui TRANSLATIONS=$$[QT_INSTALL_TRANSLATIONS]/qtconfig_pl.ts \ + $$[QT_INSTALL_TRANSLATIONS]/qtconfig_ru.ts \ $$[QT_INSTALL_TRANSLATIONS]/qtconfig_untranslated.ts \ $$[QT_INSTALL_TRANSLATIONS]/qtconfig_zh_CN.ts \ $$[QT_INSTALL_TRANSLATIONS]/qtconfig_zh_TW.ts diff --git a/tools/qtestlib/wince/cetest/activesyncconnection.cpp b/tools/qtestlib/wince/cetest/activesyncconnection.cpp index 0f98619..1080477 100644 --- a/tools/qtestlib/wince/cetest/activesyncconnection.cpp +++ b/tools/qtestlib/wince/cetest/activesyncconnection.cpp @@ -385,10 +385,14 @@ bool ActiveSyncConnection::execute(QString program, QString arguments, int timeo DWORD error = 0; HRESULT res = CeRapiInvoke(dllLocation.utf16(), functionName.utf16(), 0, 0, &outputSize, &output, &stream, 0); if (S_OK != res) { - if (S_OK != CeGetLastError()) - debugOutput(QString::fromLatin1("Error: Could not invoke method on QtRemote"),1); - else - debugOutput(QString::fromLatin1("Error: QtRemote return unexpectedly with error Code %1").arg(res), 1); + DWORD ce_error = CeGetLastError(); + if (S_OK != ce_error) { + qWarning("Error invoking %s on %s: %s", qPrintable(functionName), + qPrintable(dllLocation), strwinerror(ce_error).constData()); + } else { + qWarning("Error: %s on %s unexpectedly returned %d", qPrintable(functionName), + qPrintable(dllLocation), res); + } } else { DWORD written; int strSize = program.length(); diff --git a/tools/qtestlib/wince/cetest/main.cpp b/tools/qtestlib/wince/cetest/main.cpp index ba3ef8d..782f6d9 100644 --- a/tools/qtestlib/wince/cetest/main.cpp +++ b/tools/qtestlib/wince/cetest/main.cpp @@ -320,6 +320,7 @@ int main(int argc, char **argv) cout << endl << "Remote Launch:" << qPrintable(TestConfiguration::remoteExecutable) << " " << qPrintable(launchArguments.join(" ")) << endl; if (!connection.execute(TestConfiguration::remoteExecutable, launchArguments.join(" "), timeout)) { cout << "Error: Could not execute target file" << endl; + return -1; } diff --git a/tools/qtestlib/wince/cetest/remoteconnection.cpp b/tools/qtestlib/wince/cetest/remoteconnection.cpp index 75788e2..3d0c3f3 100644 --- a/tools/qtestlib/wince/cetest/remoteconnection.cpp +++ b/tools/qtestlib/wince/cetest/remoteconnection.cpp @@ -66,8 +66,8 @@ QByteArray strwinerror(DWORD errorcode) out.chop(2); /* Append error number to error message for good measure */ - out.append(" ("); - out.append(QByteArray::number((int)errorcode)); + out.append(" (0x"); + out.append(QByteArray::number(uint(errorcode), 16).rightJustified(8, '0')); out.append(")"); } return out; diff --git a/tools/qvfb/translations/translations.pro b/tools/qvfb/translations/translations.pro index 736a72c..f667bb8 100644 --- a/tools/qvfb/translations/translations.pro +++ b/tools/qvfb/translations/translations.pro @@ -27,6 +27,7 @@ SOURCES = ../qvfb.cpp \ ../../shared/deviceskin/deviceskin.cpp TRANSLATIONS=$$[QT_INSTALL_TRANSLATIONS]/qvfb_pl.ts \ + $$[QT_INSTALL_TRANSLATIONS]/qvfb_ru.ts \ $$[QT_INSTALL_TRANSLATIONS]/qvfb_untranslated.ts \ $$[QT_INSTALL_TRANSLATIONS]/qvfb_zh_CN.ts \ $$[QT_INSTALL_TRANSLATIONS]/qvfb_zh_TW.ts diff --git a/translations/assistant_adp_ru.ts b/translations/assistant_adp_ru.ts index a587a91..c47798b 100644 --- a/translations/assistant_adp_ru.ts +++ b/translations/assistant_adp_ru.ts @@ -4,10 +4,12 @@ <context> <name>AssistantServer</name> <message> + <location filename="../tools/assistant/compat/main.cpp" line="+226"/> <source>Failed to bind to port %1</source> <translation>Не удалось открыть порт %1</translation> </message> <message> + <location line="-1"/> <source>Qt Assistant</source> <translation>Qt Assistant</translation> </message> @@ -15,22 +17,27 @@ <context> <name>FontPanel</name> <message> + <location filename="../tools/shared/fontpanel/fontpanel.cpp" line="+77"/> <source>&Family</source> <translation>Се&мейство</translation> </message> <message> + <location line="+4"/> <source>&Style</source> <translation>&Стиль</translation> </message> <message> + <location line="-18"/> <source>Font</source> <translation>Шрифт</translation> </message> <message> + <location line="+11"/> <source>&Writing system</source> <translation>Система &письма</translation> </message> <message> + <location line="+11"/> <source>&Point size</source> <translation>&Размер в пикселях</translation> </message> @@ -38,22 +45,27 @@ <context> <name>FontSettingsDialog</name> <message> + <location filename="../tools/assistant/compat/fontsettingsdialog.cpp" line="+75"/> <source>Application</source> <translation>Приложение</translation> </message> <message> + <location line="-1"/> <source>Browser</source> <translation>Обозреватель</translation> </message> <message> + <location line="-4"/> <source>Font settings for:</source> <translation>Настройки шрифта для:</translation> </message> <message> + <location line="+11"/> <source>Use custom settings</source> <translation>Использование индивидуальных настроек</translation> </message> <message> + <location line="-18"/> <source>Font Settings</source> <translation>Настройки шрифта</translation> </message> @@ -61,202 +73,261 @@ <context> <name>HelpDialog</name> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="+108"/> <source>&Index</source> <translation>&Указатель</translation> </message> <message> + <location line="+12"/> <source>&Look For:</source> <translation>&Искать:</translation> </message> <message> + <location line="+91"/> <source>&New</source> - <translation>&Создать</translation> + <translation>&Новая</translation> </message> <message> + <location line="+23"/> + <location line="+111"/> <source>&Search</source> <translation>&Поиск</translation> </message> <message> + <location line="-212"/> <source><b>Enter a keyword.</b><p>The list will select an item that matches the entered string best.</p></source> - <translation><b>Ввод слова.</b><p>В список попадет то, что лучше соответствует введенной строке.</p></translation> + <translation type="unfinished"><b>Указание ключевого слова.</b><p>Список заполняется элементами, лучше соответствующими указанному ключевому слову.</p></translation> </message> <message> + <location line="+142"/> <source><b>Enter search word(s).</b><p>Enter here the word(s) you are looking for. The words may contain wildcards (*). For a sequence of words quote them.</p></source> - <translation><b>Ввод одного или более слов для поиска.</b><p>Сюда следует ввести одно или несколько слов, которые требуется найти. Слова могут содержкать символы-заменители (*). Если требуется найти словосочетание, то его нужно заключить в кавычки.</p></translation> + <translation type="unfinished"><b>Указание слов для поиска.</b><p>Введите одно или несколько слов, по которым требуется осуществить поиск. Слова могут содержкать символы-заменители (*). Если требуется найти сочетание слов, заключите искомую фразу в кавычки.</p></translation> </message> <message> + <location line="+10"/> <source><b>Found documents</b><p>This list contains all found documents from the last search. The documents are ordered, i.e. the first document has the most matches.</p></source> - <translation><b>Найденные документы</b><p>В этом списке представлены все найденные при последнем поиске документы. Документы упорядочены по релевантности, т.е. чем выше, тем чаще в нём встречаются указанные слова.</p></translation> + <translation type="unfinished"><b>Найденные документы</b><p>В данном списке представлены все найденные при последнем поиске документы. Документы упорядочены по релевантности, т.е. чем выше в списке, тем чаще в нём встречаются искомые слова.</p></translation> </message> <message> + <location line="-196"/> <source><b>Help topics organized by category.</b><p>Double-click an item to see the topics in that category. To view a topic, just double-click it.</p></source> - <translation><b>Статьи справки распределённые по разделам.</b><p>Дважды кликните по одному из пунктов, чтобы увидеть какие статьи содержатся в данном разделе. Для открытия статьи просто дважды щелкните на ней.</p></translation> + <translation type="unfinished"><b>Разделы справки, распределённые по категориям.</b><p>Дважды щёлкните по одному из пунктов для отображения разделов в данной категории. Для открытия раздела дважды щёлкните по нему.</p></translation> </message> <message> + <location line="-31"/> <source><b>Help</b><p>Choose the topic you want help on from the contents list, or search the index for keywords.</p></source> - <translation><b>Справка</b><p>Выберите необходимую статью справки из списка разделов или воспользуйтесь поиском по предметному указателю.</p></translation> + <translation type="unfinished"><b>Справка</b><p>Выберите раздел справки из содержания или воспользуйтесь поиском по предметному указателю.</p></translation> </message> <message> + <location line="+85"/> <source><b>List of available help topics.</b><p>Double-click on an item to open its help page. If more than one is found, you must specify which page you want.</p></source> - <translation><b>Список доступных статей справки.</b><p>Дважды щёлкните на пункте для открытия страницы помощи. Если найдено более одной, то потребуется выбрать желаемую страницу.</p></translation> + <translation type="unfinished"><b>Список доступных разделов справки.</b><p>Дважды щёлкните по одному из пунктов для открытия страницы справки. Если найдено более одной страницы, выберите желаемую.</p></translation> </message> <message> + <location line="+62"/> <source>Add new bookmark</source> - <translation>Добавить новую закладку</translation> + <translation>Добавить закладку</translation> </message> <message> + <location line="+3"/> <source>Add the currently displayed page as a new bookmark.</source> - <translation>Добавление текущей открытой страницы в закладки.</translation> + <translation>Добавить отображаемую страницу в закладки.</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="+393"/> <source>Cannot open the index file %1</source> <translation>Не удаётся открыть файл индекса %1</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="-134"/> <source>Con&tents</source> <translation>Содер&жание</translation> </message> <message> + <location line="+144"/> <source>Delete bookmark</source> <translation>Удалить закладку</translation> </message> <message> + <location line="+3"/> <source>Delete the selected bookmark.</source> - <translation>Удаление выбранной закладки.</translation> + <translation>Удалить выбранную закладку.</translation> </message> <message> + <location line="+92"/> <source>Display the help page for the full text search.</source> - <translation>Открытие справки по полнотекстовому поиску.</translation> + <translation>Показать справку по полнотекстовому поиску.</translation> </message> <message> + <location line="-3"/> <source>Display the help page.</source> - <translation>Открыть страницу справки.</translation> + <translation>Показать страницу справки.</translation> </message> <message> + <location line="-240"/> <source>Displays help topics organized by category, index or bookmarks. Another tab inherits the full text search.</source> - <translation>Здесь отображается список тем, распределенных по разделам, указатель или закладки. Последняя вкладка содержит полнотекстовый поиск.</translation> + <translation>Отображает список разделов, распредёленных по категориям, указатель или закладки. Последняя вкладка содержит панель полнотекстового поиска.</translation> </message> <message> + <location line="+96"/> <source>Displays the list of bookmarks.</source> <translation>Отображает список закладок.</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="+59"/> + <location line="+124"/> <source>Documentation file %1 does not exist! Skipping file.</source> <translation>Файл документации %1 не существует! Пропущен.</translation> </message> <message> + <location line="+8"/> <source>Documentation file %1 is not compatible! Skipping file.</source> - <translation>Файл документации %1 не совместим! + <translation>Несовместимый файл документации %1! Пропущен.</translation> </message> <message> + <location line="+48"/> + <location line="+469"/> <source>Done</source> <translation>Готово</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="-36"/> <source>Enter keyword</source> <translation>Введите ключевое слово</translation> </message> <message> + <location line="+142"/> <source>Enter searchword(s).</source> - <translation>Введите одно или более слов для поиска.</translation> + <translation>Введите одно или несколько слов для поиска.</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="-725"/> <source>Failed to load keyword index file Assistant will not work!</source> <translation>Не удалось загрузить файл индекса ключевых слов -Assistant не будет работать!</translation> +Qt Assistant не будет работать!</translation> </message> <message> + <location line="+678"/> <source>Failed to save fulltext search index Assistant will not work!</source> <translation>Не удалось сохранить индекс полнотекстового поиска -Assistant не будет работать!</translation> +Qt Assistant не будет работать!</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="+20"/> <source>Found &Documents:</source> <translation>Найденные &документы:</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="+90"/> + <location line="+9"/> <source>Full Text Search</source> <translation>Полнотекстовый поиск</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="+24"/> <source>He&lp</source> <translation>&Справка</translation> </message> <message> + <location line="-261"/> <source>Help</source> <translation>Справка</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="-70"/> <source>Indexing files...</source> <translation>Индексирование файлов...</translation> </message> <message> + <location line="-798"/> <source>Open Link in New Tab</source> <translation>Открыть ссылку в новой вкладке</translation> </message> <message> + <location line="-3"/> <source>Open Link in New Window</source> <translation>Открыть ссылку в новом окне</translation> </message> <message> + <location line="+182"/> + <location line="+133"/> <source>Parse Error</source> <translation>Ошибка обработки</translation> </message> <message> + <location line="-239"/> + <location line="+82"/> <source>Prepare...</source> <translation>Подготовка...</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="+321"/> <source>Preparing...</source> <translation>Подготовка...</translation> </message> <message> + <location line="-34"/> <source>Pressing this button starts the search.</source> <translation>Нажатие на эту кнопку запустит процесс поиска.</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="-64"/> + <location line="+16"/> + <location line="+661"/> <source>Qt Assistant</source> <translation>Qt Assistant</translation> </message> <message> + <location line="+45"/> <source>Reading dictionary...</source> <translation>Чтение каталога...</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="-80"/> <source>Searching f&or:</source> <translation>&Искать:</translation> </message> <message> + <location line="+77"/> <source>Start searching.</source> <translation>Начать поиск.</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="+56"/> <source>The closing quotation mark is missing.</source> <translation>Пропущена закрывающая кавычка.</translation> </message> <message> + <location line="-9"/> <source>Using a wildcard within phrases is not allowed.</source> - <translation>Использование символов-заменителей внутри фраз не допустимо.</translation> + <translation>Использование символов-заменителей внутри фраз недопустимо.</translation> </message> <message> + <location line="-694"/> + <location line="+124"/> + <location line="+8"/> <source>Warning</source> <translation>Предупреждение</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="-240"/> + <location line="+74"/> <source>column 1</source> <translation>столбец 1</translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.cpp" line="-304"/> <source>Open Link in Current Tab</source> <translation>Открыть ссылку в текущей вкладке</translation> </message> <message numerus="yes"> + <location line="+882"/> <source>%n document(s) found.</source> <translation> <numerusform>Найден %n документ.</numerusform> @@ -265,10 +336,12 @@ Assistant не будет работать!</translation> </translation> </message> <message> + <location filename="../tools/assistant/compat/helpdialog.ui" line="-22"/> <source>&Bookmarks</source> <translation>&Закладки</translation> </message> <message> + <location line="+73"/> <source>&Delete</source> <translation>&Удалить</translation> </message> @@ -276,38 +349,47 @@ Assistant не будет работать!</translation> <context> <name>HelpWindow</name> <message> + <location filename="../tools/assistant/compat/helpwindow.cpp" line="+127"/> <source><div align="center"><h1>The page could not be found</h1><br><h3>'%1'</h3></div></source> <translation><div align="center"><h1>Страница не найдена</h1><br><h3>'%1'</h3></div></translation> </message> <message> + <location line="+58"/> <source>Copy &Link Location</source> <translation>Копировать &адрес ссылки</translation> </message> <message> + <location line="-56"/> <source>Error...</source> <translation>Ошибка...</translation> </message> <message> + <location line="-3"/> <source>Failed to open link: '%1'</source> <translation>Не удалось открыть ссылку: '%1'</translation> </message> <message> + <location line="-29"/> <source>Help</source> <translation>Справка</translation> </message> <message> + <location line="+2"/> <source>OK</source> <translation>Закрыть</translation> </message> <message> + <location line="+89"/> <source>Open Link in New Tab</source> <translation>Открыть ссылку в новой вкладке</translation> </message> <message> + <location line="+2"/> <source>Open Link in New Window Shift+LMB</source> <translation>Открыть ссылку в новом окне Shift+LMB</translation> </message> <message> + <location line="-92"/> <source>Unable to launch web browser. </source> <translation>Невозможно запустить вэб-браузер. @@ -317,6 +399,7 @@ Assistant не будет работать!</translation> <context> <name>Index</name> <message> + <location filename="../tools/assistant/compat/index.cpp" line="+385"/> <source>Untitled</source> <translation>Неозаглавлено</translation> </message> @@ -324,354 +407,445 @@ Assistant не будет работать!</translation> <context> <name>MainWindow</name> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="+375"/> + <location line="+3"/> <source>"What's This?" context sensitive help.</source> - <translation>"Что это?" - контекстная справка.</translation> + <translation>Контекстная справка "Что это?".</translation> </message> <message> + <location line="-17"/> <source>&Add Bookmark</source> - <translation>&Добавление закладки</translation> + <translation>&Добавить закладку</translation> </message> <message> + <location line="-11"/> <source>&Close</source> <translation>&Закрыть</translation> </message> <message> + <location line="-141"/> <source>&Copy</source> <translation>&Копировать</translation> </message> <message> + <location line="-49"/> <source>&Edit</source> <translation>&Правка</translation> </message> <message> + <location line="-39"/> <source>&File</source> <translation>&Файл</translation> </message> <message> + <location line="+102"/> <source>&Find in Text...</source> <translation>П&оиск по тексту...</translation> </message> <message> + <location line="-82"/> <source>&Go</source> <translation>&Перейти</translation> </message> <message> + <location line="-31"/> <source>&Help</source> <translation>&Справка</translation> </message> <message> + <location line="+143"/> <source>&Home</source> <translation>&Домой</translation> </message> <message> + <location line="+28"/> <source>&Next</source> - <translation>&Вперёд</translation> + <translation>Сл&едующий</translation> </message> <message> + <location line="-14"/> <source>&Previous</source> - <translation>&Назад</translation> + <translation>&Предыдущий</translation> </message> <message> + <location line="-86"/> <source>&Print...</source> <translation>&Печать...</translation> </message> <message> + <location line="-28"/> <source>&View</source> <translation>&Вид</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+121"/> <source>&Window</source> <translation>&Окно</translation> </message> <message> + <location line="+429"/> <source>...</source> <translation>...</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="+150"/> <source>About Qt</source> <translation>О Qt</translation> </message> <message> + <location line="-11"/> <source>About Qt Assistant</source> <translation>О Qt Assistant</translation> </message> <message> + <location line="+94"/> <source>Add Tab</source> <translation>Добавить вкладку</translation> </message> <message> + <location line="-22"/> <source>Add the currently displayed page as a new bookmark.</source> - <translation>Добавление текущей открытой страницы в закладки.</translation> + <translation>Добавить отображаемую страницу в закладки.</translation> </message> <message> + <location line="-228"/> <source>Boo&kmarks</source> <translation>&Закладки</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+244"/> <source>Cannot open file for writing!</source> - <translation>Не удается открыть файл для записи!</translation> + <translation>Не удалось открыть файл для записи!</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="+274"/> <source>Close Tab</source> <translation>Закрыть вкладку</translation> </message> <message> + <location line="-57"/> <source>Close the current window.</source> <translation>Закрыть текущее окно.</translation> </message> <message> + <location line="-58"/> <source>Display further information about Qt Assistant.</source> <translation>Показать дополнительную информацию о Qt Assistant.</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="-514"/> <source>Displays the main page of a specific documentation set.</source> - <translation>Открывает главную страницу выбранного набора документации.</translation> + <translation type="unfinished">Открывает стартовую страницу выбранного набора документации.</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="-103"/> <source>E&xit</source> - <translation>Вы&ход</translation> + <translation>В&ыход</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+69"/> <source>Failed to open about application contents in file: '%1'</source> <translation>Не удалось получить информацию о приложении из файла: '%1'</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="+42"/> <source>Find &Next</source> - <translation>Продолжить п&оиск</translation> + <translation>Найти &следующее</translation> </message> <message> + <location line="+8"/> <source>Find &Previous</source> <translation>Найти &предыдущее</translation> </message> <message> + <location line="+206"/> <source>Font Settings...</source> <translation>Настройки шрифта...</translation> </message> <message> + <location line="-361"/> <source>Go</source> <translation>Перейти</translation> </message> <message> + <location line="+169"/> <source>Go to the home page. Qt Assistant's home page is the Qt Reference Documentation.</source> <translation>Перейти на домашнюю страницу. Домашная страница Qt Assistant - Справочная документация по Qt.</translation> </message> <message> + <location line="+28"/> <source>Go to the next page.</source> <translation>Переход на следующую страницу.</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="-191"/> <source>Initializing Qt Assistant...</source> <translation>Инициализация Qt Assistant...</translation> </message> <message> + <location line="-35"/> <source>Minimize</source> <translation>Свернуть</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="+55"/> <source>New Window</source> <translation>Новое окно</translation> </message> <message> + <location line="+55"/> <source>Next Tab</source> <translation>Следующая вкладка</translation> </message> <message> + <location line="-52"/> <source>Open a new window.</source> <translation>Открыть новое окно.</translation> </message> <message> + <location line="-116"/> <source>Open the Find dialog. Qt Assistant will search the currently displayed page for the text you enter.</source> - <translation>Открыть окно поиска. Qt Assistant произведёт поиск введённого текста на текущей открытой странице.</translation> + <translation>Открыть окно поиска. Qt Assistant произведёт поиск введённого текста на отображаемой странице.</translation> </message> <message> + <location line="+176"/> <source>Previous Tab</source> <translation>Предыдущая вкладка</translation> </message> <message> + <location line="-218"/> <source>Print the currently displayed page.</source> - <translation>Печать текущей открытой страницы.</translation> + <translation>Печатать отображаемую страницу.</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+206"/> + <location line="+1"/> <source>Qt Assistant</source> <translation>Qt Assistant</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="+237"/> <source>Qt Assistant Manual</source> <translation>Руководство по Qt Assistant</translation> </message> <message> + <location line="-366"/> <source>Qt Assistant by Nokia</source> <translation>Qt Assistant от Nokia</translation> </message> <message> + <location line="+140"/> <source>Quit Qt Assistant.</source> <translation>Выйти из Qt Assistant.</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+458"/> + <location line="+6"/> <source>Save Page</source> <translation>Сохранить страницу</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="+234"/> <source>Save Page As...</source> <translation>Сохранить страницу как...</translation> </message> <message> + <location line="+14"/> <source>Select the page in contents tab.</source> - <translation>Выбор страницы в оглавлении.</translation> + <translation>Выбрать страницу во вкладке содержания.</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="-691"/> <source>Sidebar</source> <translation>Боковая панель</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="-3"/> <source>Sync with Table of Contents</source> - <translation>Синхронизировать с оглавлением</translation> + <translation>Синхронизировать с содержанием</translation> </message> <message> + <location line="-380"/> <source>Toolbar</source> <translation>Панель инструментов</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="+97"/> <source>Views</source> <translation>Виды</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="+312"/> <source>What's This?</source> <translation>Что это?</translation> </message> <message> + <location line="-58"/> <source>Zoom &in</source> <translation>У&величить</translation> </message> <message> + <location line="+14"/> <source>Zoom &out</source> <translation>У&меньшить</translation> </message> <message> + <location line="-11"/> <source>Zoom in on the document, i.e. increase the font size.</source> - <translation>Увеличение масштаба документа, т.е. увеличение размера шрифта.</translation> + <translation>Увеличить размер шрифта.</translation> </message> <message> + <location line="+14"/> <source>Zoom out on the document, i.e. decrease the font size.</source> - <translation>Уменьшение масштаба документа, т.е. уменьшение размера шрифта.</translation> + <translation>Уменьшить размер шрифта.</translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.cpp" line="-76"/> <source>Ctrl+M</source> <translation type="unfinished"></translation> </message> <message> + <location line="+60"/> <source>SHIFT+CTRL+=</source> <translation type="unfinished"></translation> </message> <message> + <location line="+4"/> <source>Ctrl+T</source> <translation type="unfinished"></translation> </message> <message> + <location line="+1"/> <source>Ctrl+I</source> <translation type="unfinished"></translation> </message> <message> + <location line="+1"/> <source>Ctrl+B</source> <translation type="unfinished"></translation> </message> <message> + <location line="+1"/> <source>Ctrl+S</source> <translation type="unfinished"></translation> </message> <message> + <location line="+1"/> <source>Ctrl+]</source> <translation type="unfinished"></translation> </message> <message> + <location line="+1"/> <source>Ctrl+[</source> <translation type="unfinished"></translation> </message> <message> + <location filename="../tools/assistant/compat/mainwindow.ui" line="-144"/> <source>Ctrl+P</source> <translation type="unfinished"></translation> </message> <message> + <location line="+11"/> <source>Ctrl+Q</source> <translation type="unfinished"></translation> </message> <message> + <location line="+14"/> <source>Copy the selected text to the clipboard.</source> <translation>Скопировать выделенный текст в буфер обмена.</translation> </message> <message> + <location line="+3"/> <source>Ctrl+C</source> <translation type="unfinished"></translation> </message> <message> + <location line="+14"/> <source>Ctrl+F</source> <translation type="unfinished"></translation> </message> <message> + <location line="+8"/> <source>F3</source> <translation type="unfinished"></translation> </message> <message> + <location line="+8"/> <source>Shift+F3</source> <translation type="unfinished"></translation> </message> <message> + <location line="+14"/> <source>Ctrl+Home</source> <translation type="unfinished"></translation> </message> <message> + <location line="+11"/> <source>Go to the previous page.</source> <translation>Переход на предыдущую страницу.</translation> </message> <message> + <location line="+3"/> <source>Alt+Left</source> <translation type="unfinished"></translation> </message> <message> + <location line="+14"/> <source>Alt+Right</source> <translation type="unfinished"></translation> </message> <message> + <location line="+33"/> <source>Ctrl++</source> <translation type="unfinished"></translation> </message> <message> + <location line="+14"/> <source>Ctrl+-</source> <translation type="unfinished"></translation> </message> <message> + <location line="+11"/> <source>Ctrl+N</source> <translation type="unfinished"></translation> </message> <message> + <location line="+11"/> <source>Ctrl+W</source> <translation type="unfinished"></translation> </message> <message> + <location line="+25"/> <source>Shift+F1</source> <translation type="unfinished"></translation> </message> <message> + <location line="+8"/> <source>Ctrl+Alt+N</source> <translation type="unfinished"></translation> </message> <message> + <location line="+8"/> <source>Ctrl+Alt+Right</source> <translation type="unfinished"></translation> </message> <message> + <location line="+8"/> <source>Ctrl+Alt+Left</source> <translation type="unfinished"></translation> </message> <message> + <location line="+8"/> <source>Ctrl+Alt+Q</source> <translation type="unfinished"></translation> </message> <message> + <location line="+11"/> <source>F1</source> <translation type="unfinished"></translation> </message> <message> + <location line="+8"/> <source>Ctrl+Alt+S</source> <translation type="unfinished"></translation> </message> @@ -679,6 +853,7 @@ Assistant не будет работать!</translation> <context> <name>QObject</name> <message> + <location filename="../tools/assistant/compat/config.cpp" line="+350"/> <source>Qt Assistant by Nokia</source> <translation>Qt Assistant от Nokia</translation> </message> @@ -686,54 +861,67 @@ Assistant не будет работать!</translation> <context> <name>TabbedBrowser</name> <message> + <location filename="../tools/assistant/compat/tabbedbrowser.cpp" line="+149"/> <source>...</source> <translation>...</translation> </message> <message> + <location filename="../tools/assistant/compat/tabbedbrowser.ui" line="+197"/> <source><img src=":/trolltech/assistant/images/wrap.png">&nbsp;Search wrapped</source> <translation><img src=":/trolltech/assistant/images/wrap.png">&nbsp;Поиск с начала</translation> </message> <message> + <location filename="../tools/assistant/compat/tabbedbrowser.cpp" line="+86"/> <source>Add page</source> - <translation>Добавить страницу</translation> + <translation>Добавить вкладку</translation> </message> <message> + <location filename="../tools/assistant/compat/tabbedbrowser.ui" line="-26"/> <source>Case Sensitive</source> - <translation>Регистрозависимо</translation> + <translation>Учитывать регистр</translation> </message> <message> + <location filename="../tools/assistant/compat/tabbedbrowser.cpp" line="+254"/> <source>Close Other Tabs</source> <translation>Закрыть остальные вкладки</translation> </message> <message> + <location line="-1"/> <source>Close Tab</source> <translation>Закрыть вкладку</translation> </message> <message> + <location line="-244"/> <source>Close page</source> - <translation>Закрыть страницу</translation> + <translation>Закрыть вкладку</translation> </message> <message> + <location line="+243"/> <source>New Tab</source> <translation>Новая вкладка</translation> </message> <message> + <location filename="../tools/assistant/compat/tabbedbrowser.ui" line="-19"/> <source>Next</source> - <translation>Следующий</translation> + <translation>Следующее</translation> </message> <message> + <location line="-22"/> <source>Previous</source> - <translation>Предыдущий</translation> + <translation>Предыдущее</translation> </message> <message> + <location line="-62"/> <source>Untitled</source> <translation>Безымянный</translation> </message> <message> + <location line="+110"/> <source>Whole words</source> - <translation>Слова полностью</translation> + <translation>Слова целиком</translation> </message> <message> + <location line="-123"/> <source>TabbedBrowser</source> <translation type="unfinished"></translation> </message> @@ -741,40 +929,49 @@ Assistant не будет работать!</translation> <context> <name>TopicChooser</name> <message> + <location filename="../tools/assistant/compat/topicchooser.ui" line="+149"/> <source>&Close</source> <translation>&Закрыть</translation> </message> <message> + <location line="-16"/> <source>&Display</source> <translation>&Показать</translation> </message> <message> + <location line="-53"/> <source>&Topics</source> - <translation>&Статьи</translation> + <translation>&Разделы</translation> </message> <message> + <location line="-27"/> <source>Choose Topic</source> - <translation>Выбор статьи</translation> + <translation>Выбор раздела</translation> </message> <message> + <location filename="../tools/assistant/compat/topicchooser.cpp" line="+56"/> <source>Choose a topic for <b>%1</b></source> - <translation>Выберите статью для <b>%1</b></translation> + <translation>Выберите раздел для <b>%1</b></translation> </message> <message> + <location filename="../tools/assistant/compat/topicchooser.ui" line="+93"/> <source>Close the Dialog.</source> - <translation>Закрытие окна.</translation> + <translation>Закрыть диалог.</translation> </message> <message> + <location line="-56"/> <source>Displays a list of available help topics for the keyword.</source> - <translation>Показывает список доступных статей справки, соответствующих ключевому слову.</translation> + <translation>Показывает список доступных разделов справки, найденных по ключевому слову.</translation> </message> <message> + <location line="+40"/> <source>Open the topic selected in the list.</source> - <translation>Открытие выбранной в списке темы.</translation> + <translation>Открыть выбранный раздел.</translation> </message> <message> + <location line="-74"/> <source>Select a topic from the list and click the <b>Display</b>-button to open the online help.</source> - <translation>Выберите статью из списка и нажмите на кнопку <b>Показать</b> для открытия онлайн справки.</translation> + <translation>Выберите раздел из списка и нажмите на кнопку <b>Показать</b> для открытия онлайн справки.</translation> </message> </context> </TS> diff --git a/translations/assistant_ru.ts b/translations/assistant_ru.ts index 32aa739..ecec0f8 100644 --- a/translations/assistant_ru.ts +++ b/translations/assistant_ru.ts @@ -57,16 +57,16 @@ <translation>Новая папка</translation> </message> <message> - <location filename="../tools/assistant/tools/assistant/bookmarkmanager.cpp" line="+185"/> + <location filename="../tools/assistant/tools/assistant/bookmarkmanager.cpp" line="+184"/> <location line="+18"/> - <location line="+36"/> - <location line="+24"/> - <location line="+32"/> + <location line="+39"/> + <location line="+18"/> + <location line="+30"/> <source>Bookmarks</source> <translation>Закладки</translation> </message> <message> - <location line="-69"/> + <location line="-61"/> <source>Delete Folder</source> <translation>Удалить папку</translation> </message> @@ -79,12 +79,12 @@ <context> <name>BookmarkManager</name> <message> - <location line="+449"/> + <location line="+434"/> <source>Bookmarks</source> <translation>Закладки</translation> </message> <message> - <location line="+36"/> + <location line="+37"/> <source>Remove</source> <translation>Удалить</translation> </message> @@ -94,7 +94,7 @@ <translation>Удаление папки приведёт к удалению её содержимого.<br>Желаете продолжить?</translation> </message> <message> - <location line="+109"/> + <location line="+143"/> <location line="+9"/> <source>New Folder</source> <translation>Новая папка</translation> @@ -103,7 +103,7 @@ <context> <name>BookmarkWidget</name> <message> - <location line="-436"/> + <location line="-462"/> <source>Delete Folder</source> <translation>Удалить папку</translation> </message> @@ -138,7 +138,7 @@ <translation>Фильтр:</translation> </message> <message> - <location line="+23"/> + <location line="+24"/> <source>Add</source> <translation>Добавить</translation> </message> @@ -161,7 +161,7 @@ <translation>Закрыть текущую страницу</translation> </message> <message> - <location line="+284"/> + <location line="+291"/> <source>Print Document</source> <translation>Печать документа</translation> </message> @@ -226,24 +226,24 @@ <context> <name>FindWidget</name> <message> - <location filename="../tools/assistant/tools/assistant/centralwidget.cpp" line="-925"/> + <location filename="../tools/assistant/tools/assistant/centralwidget.cpp" line="-932"/> <source>Previous</source> - <translation>Предыдущее совпадение</translation> + <translation>Предыдущее</translation> </message> <message> <location line="+4"/> <source>Next</source> - <translation>Следующее совпадение</translation> + <translation>Следующее</translation> </message> <message> <location line="+4"/> <source>Case Sensitive</source> - <translation>Регистрозависимо</translation> + <translation>Учитывать регистр</translation> </message> <message> <location line="+3"/> <source>Whole words</source> - <translation>Слова полностью</translation> + <translation>Слова целиком</translation> </message> <message> <location line="+12"/> @@ -441,31 +441,31 @@ <name>MainWindow</name> <message> <location filename="../tools/assistant/tools/assistant/mainwindow.cpp" line="+108"/> - <location line="+354"/> + <location line="+384"/> <source>Index</source> - <translation>Индекс</translation> + <translation>Указатель</translation> </message> <message> - <location line="-348"/> - <location line="+346"/> + <location line="-378"/> + <location line="+376"/> <source>Contents</source> <translation>Содержание</translation> </message> <message> - <location line="-341"/> - <location line="+345"/> + <location line="-371"/> + <location line="+375"/> <source>Bookmarks</source> <translation>Закладки</translation> </message> <message> - <location line="-333"/> - <location line="+208"/> - <location line="+476"/> + <location line="-363"/> + <location line="+215"/> + <location line="+500"/> <source>Qt Assistant</source> <translation>Qt Assistant</translation> </message> <message> - <location line="-508"/> + <location line="-532"/> <location line="+5"/> <source>Unfiltered</source> <translation>Без фильтрации</translation> @@ -473,10 +473,10 @@ <message> <location line="+21"/> <source>Looking for Qt Documentation...</source> - <translation type="unfinished">Поиск по документации Qt...</translation> + <translation>Поиск документации по Qt...</translation> </message> <message> - <location line="+61"/> + <location line="+84"/> <source>&File</source> <translation>&Файл</translation> </message> @@ -656,7 +656,7 @@ <translation>Добавить закладку...</translation> </message> <message> - <location line="+1"/> + <location line="+2"/> <source>CTRL+D</source> <translation type="unfinished"></translation> </message> @@ -723,12 +723,12 @@ <message> <location line="+114"/> <source>Could not find the associated content item.</source> - <translation type="unfinished">Не удалось найти элемент, связанный с содержанием.</translation> + <translation>Не удалось найти элемент, связанный с содержанием.</translation> </message> <message> <location line="+81"/> <source>About %1</source> - <translation type="unfinished">О %1</translation> + <translation>О %1</translation> </message> <message> <location line="+114"/> @@ -767,7 +767,7 @@ <message> <location line="+1"/> <source>Some documents currently opened in Assistant reference the documentation you are attempting to remove. Removing the documentation will close those documents.</source> - <translation>Некоторые открытые в Qt Assistant документы ссылаются на документацию, которую вы пытаетесь удалить. Удаление данной документации приведёт к закрытию таких документов.</translation> + <translation>Некоторые открытые в Qt Assistant документы ссылаются на документацию, которую вы пытаетесь удалить. Её удаление приведёт к закрытию этих документов.</translation> </message> <message> <location line="+2"/> @@ -830,7 +830,7 @@ <message> <location line="+11"/> <source>1</source> - <translation type="unfinished"></translation> + <translation>1</translation> </message> <message> <location line="+8"/> @@ -876,18 +876,12 @@ <message> <location line="+7"/> <source>Restore to default</source> - <translation type="unfinished">Восстановить по умолчанию</translation> + <translation>Страница по умолчанию</translation> </message> </context> <context> <name>QObject</name> <message> - <location filename="../tools/assistant/tools/assistant/bookmarkmanager.cpp" line="+157"/> - <location line="+1"/> - <source>Bookmark</source> - <translation>Закладка</translation> - </message> - <message> <location filename="../tools/assistant/tools/assistant/cmdlineparser.cpp" line="+112"/> <source>The specified collection file does not exist!</source> <translation type="unfinished">Указанный файл набора отсутствует!</translation> @@ -1037,17 +1031,17 @@ Reason: <message> <location filename="../tools/assistant/tools/assistant/topicchooser.cpp" line="+54"/> <source>Choose a topic for <b>%1</b>:</source> - <translation>Выберите статью для <b>%1</b>:</translation> + <translation>Выберите раздел для <b>%1</b>:</translation> </message> <message> <location filename="../tools/assistant/tools/assistant/topicchooser.ui" line="+16"/> <source>Choose Topic</source> - <translation>Выбор статьи</translation> + <translation>Выбор раздела</translation> </message> <message> <location line="+21"/> <source>&Topics</source> - <translation>&Статьи</translation> + <translation>&Разделы</translation> </message> <message> <location line="+51"/> diff --git a/translations/linguist_ru.ts b/translations/linguist_ru.ts index 058d86a..86c7434 100644 --- a/translations/linguist_ru.ts +++ b/translations/linguist_ru.ts @@ -42,7 +42,7 @@ <message> <location line="+7"/> <source>Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked.</source> - <translation>Имейте в виду, что изменённые записи будут отмечены как незавершённые, если не включен параметр "Помечать переведенные записи как завершённые".</translation> + <translation>Имейте в виду, что изменённые записи будут отмечены как незавершённые, если не включён параметр "Помечать переведенные записи как завершённые".</translation> </message> <message> <location line="+3"/> @@ -289,7 +289,7 @@ Will assume a single universal form.</source> <context> <name>LRelease</name> <message numerus="yes"> - <location filename="../tools/linguist/shared/qm.cpp" line="+715"/> + <location filename="../tools/linguist/shared/qm.cpp" line="+732"/> <source> Generated %n translation(s) (%1 finished and %2 unfinished) </source> <translation> @@ -617,7 +617,7 @@ All files (*)</source> <message> <location line="+6"/> <source><center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist is a tool for adding translations to Qt applications.</p><p>%2</p><p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.</p></source> - <translation type="unfinished"><center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist - инструмент для добавления переводов в приложения на основе Qt.</p><p>%2</p><p>Copyright (C) 2009 Корпорация Nokia и/или её дочерние подразделения.</p><p>Программа предоставляется "как есть" без гарантий любого рода, включая гарантии дизайна, коммерческой ценности и пригодности для определённой цели.</p></translation> + <translation type="unfinished"></translation> </message> <message> <location line="+41"/> @@ -1250,7 +1250,7 @@ All files (*)</source> <message> <location line="+3"/> <source>Toggle checking that phrase suggestions are used.</source> - <translation>Переключение проверки использования предложений для фраз. Если выявлено несовпадение, будет показано сообщение в окне предупреждений.</translation> + <translation>Переключение проверки использования предложений для фраз.</translation> </message> <message> <location line="+3"/> @@ -1466,6 +1466,11 @@ All files (*)</source> </message> <message> <location line="+30"/> + <source>Russian</source> + <translation>Русский</translation> + </message> + <message> + <location line="+1"/> <source>German</source> <translation>Немецкий</translation> </message> @@ -1517,7 +1522,7 @@ All files (*)</source> <message> <location line="+3"/> <source>Developer comments</source> - <translation>Комментарии разработчика</translation> + <translation>Комментарий разработчика</translation> </message> <message> <location line="+3"/> @@ -1547,7 +1552,7 @@ All files (*)</source> <message> <location line="+1"/> <source>%1 translator comments</source> - <translation>Комментарий переводчика на %1</translation> + <translation>%1 перевод: комментарий переводчика</translation> </message> <message> <location line="+140"/> @@ -1583,10 +1588,11 @@ Line: %2</source> <context> <name>MsgEdit</name> <message> - <location filename="../tools/linguist/linguist/messageeditor.cpp" line="-544"/> + <location filename="../tools/linguist/linguist/messageeditor.cpp" line="-545"/> <source></source> <comment>This is the right panel of the main window.</comment> - <translation type="unfinished"></translation> + <translatorcomment>Правая панель главного окна</translatorcomment> + <translation></translation> </message> </context> <context> @@ -1800,17 +1806,17 @@ Line: %2</source> <message> <location filename="../tools/linguist/shared/cpp.cpp" line="+1089"/> <source>C++ source files</source> - <translation>Исходные коды C++</translation> + <translation>Файлы исходных кодов C++</translation> </message> <message> <location filename="../tools/linguist/shared/java.cpp" line="+652"/> <source>Java source files</source> - <translation>Исходные коды Java</translation> + <translation>Файлы исходных кодов Java</translation> </message> <message> <location filename="../tools/linguist/shared/qscript.cpp" line="+2399"/> <source>Qt Script source files</source> - <translation>Исходные коды Qt Script</translation> + <translation>Файлы исходных кодов Qt Script</translation> </message> <message> <location filename="../tools/linguist/shared/ui.cpp" line="+213"/> diff --git a/translations/qt_help_ru.ts b/translations/qt_help_ru.ts index 16748fb..c2dc041 100644 --- a/translations/qt_help_ru.ts +++ b/translations/qt_help_ru.ts @@ -6,17 +6,17 @@ <message> <location filename="../tools/assistant/lib/qhelpsearchresultwidget.cpp" line="+110"/> <source>Search Results</source> - <translation>Результаты поиска</translation> + <translation>Результат поиска</translation> </message> <message> <location line="+7"/> <source>Note:</source> - <translation>Замечание:</translation> + <translation>Примечание:</translation> </message> <message> <location line="+1"/> <source>The search results may not be complete since the documentation is still being indexed!</source> - <translation>Могли быть показаны не все результаты, так как документация ещё индексируется!</translation> + <translation>Результат поиска может быть неполным, так как документация ещё индексируется!</translation> </message> <message> <location line="+11"/> @@ -45,7 +45,7 @@ <location line="+11"/> <location line="+48"/> <source>Cannot open collection file: %1</source> - <translation>Не удалось открыть файл набора: %1</translation> + <translation type="unfinished">Не удалось открыть файл набора: %1</translation> </message> <message> <location line="-39"/> @@ -168,12 +168,12 @@ <message> <location line="+6"/> <source>Insert custom filters...</source> - <translation>Вставка индивидуальных фильтров...</translation> + <translation>Добавление индивидуальных фильтров...</translation> </message> <message> <location line="+12"/> <source>Insert help data for filter section (%1 of %2)...</source> - <translation>Вставка данных справки для секции фильтра (%1 из %2)...</translation> + <translation>Добавление данных справки для раздела фильтра (%1 из %2)...</translation> </message> <message> <location line="+18"/> @@ -198,7 +198,7 @@ <message> <location line="+10"/> <source>Insert files...</source> - <translation>Вставка файлов...</translation> + <translation>Добавление файлов...</translation> </message> <message> <location line="+42"/> @@ -228,22 +228,22 @@ <message> <location line="+24"/> <source>Insert indices...</source> - <translation>Вставка указателей...</translation> + <translation>Добавление указателей...</translation> </message> <message> <location line="+80"/> <source>Insert contents...</source> - <translation>Вставка оглавления...</translation> + <translation>Добавление содержания...</translation> </message> <message> <location line="+8"/> <source>Cannot insert contents!</source> - <translation>Не удаётся вставить оглавление!</translation> + <translation>Не удалось добавить содержание!</translation> </message> <message> <location line="+12"/> <source>Cannot register contents!</source> - <translation>Не удаётся зарегистрировать оглавление!</translation> + <translation>Не удалось зарегистрировать содержание!</translation> </message> </context> <context> @@ -271,12 +271,12 @@ <message> <location line="+5"/> <source><B>without</B> the words:</source> - <translation><B>не содержит</B> слова:</translation> + <translation><B>не содержит</B> слов:</translation> </message> <message> <location line="+5"/> <source>with <B>exact phrase</B>:</source> - <translation>содержит <B>фразу полностью</B>:</translation> + <translation>содержит <B>точную фразу</B>:</translation> </message> <message> <location line="+5"/> @@ -286,7 +286,7 @@ <message> <location line="+5"/> <source>with <B>at least one</B> of the words:</source> - <translation>содержит <B> минимум одно</B> из слов:</translation> + <translation>содержит <B>хотя бы одно</B> из слов:</translation> </message> </context> <context> @@ -294,7 +294,7 @@ <message> <location filename="../tools/assistant/lib/qhelpsearchresultwidget.cpp" line="+235"/> <source>0 - 0 of 0 Hits</source> - <translation>0 - 0 из 0 соответствий</translation> + <translation>0 - 0 из 0 совпадений</translation> </message> </context> <context> @@ -302,7 +302,7 @@ <message> <location line="-61"/> <source>%1 - %2 of %3 Hits</source> - <translation>%1 - %2 из %3 соответствий</translation> + <translation>%1 - %2 из %3 совпадений</translation> </message> </context> <context> @@ -315,12 +315,12 @@ <message> <location filename="../tools/assistant/lib/qhelpprojectdata.cpp" line="+80"/> <source>Unknown token.</source> - <translation type="unfinished">Неизвестный токен.</translation> + <translation>Неизвестный идентификатор.</translation> </message> <message> <location line="+13"/> <source>Unknown token. Expected "QtHelpProject"!</source> - <translation type="unfinished">Неизвестный токен. Ожидается "QtHelpProject"!</translation> + <translation>Неизвестный идентификатор. Ожидается "QtHelpProject"!</translation> </message> <message> <location line="+5"/> diff --git a/translations/qt_ru.ts b/translations/qt_ru.ts index a27b8c4..c856786 100644 --- a/translations/qt_ru.ts +++ b/translations/qt_ru.ts @@ -57,7 +57,7 @@ <message> <location line="+2"/> <source>Accessibility</source> - <translation>Средства для людей с ограниченными возможностями</translation> + <translation>Специальные возможности</translation> </message> </context> <context> @@ -917,22 +917,22 @@ to <context> <name>QAxSelect</name> <message> - <location filename="../src/activeqt/container/qaxselect.ui" line="+54"/> + <location filename="../src/activeqt/container/qaxselect.ui"/> <source>Select ActiveX Control</source> <translation>Выберите компоненту ActiveX</translation> </message> <message> - <location line="+32"/> + <location/> <source>OK</source> <translation>Готово</translation> </message> <message> - <location line="+16"/> + <location/> <source>&Cancel</source> <translation>&Отмена</translation> </message> <message> - <location line="+49"/> + <location/> <source>COM &Object:</source> <translation>COM &Объект:</translation> </message> @@ -1022,7 +1022,7 @@ to <translation>Открыть</translation> </message> <message> - <location filename="../src/gui/itemviews/qitemeditorfactory.cpp" line="+544"/> + <location filename="../src/gui/itemviews/qitemeditorfactory.cpp" line="+556"/> <source>False</source> <translation>Нет</translation> </message> @@ -1491,32 +1491,32 @@ Please verify the correct file name was given.</source> <translation>Показать скр&ытые файлы</translation> </message> <message> - <location filename="../src/gui/dialogs/qfiledialog.ui" line="+84"/> - <location filename="../src/gui/dialogs/qfiledialog_wince.ui" line="+73"/> + <location filename="../src/gui/dialogs/qfiledialog.ui"/> + <location filename="../src/gui/dialogs/qfiledialog_wince.ui"/> <source>Back</source> <translation>Назад</translation> </message> <message> - <location line="+14"/> - <location filename="../src/gui/dialogs/qfiledialog_wince.ui" line="+14"/> + <location/> + <location filename="../src/gui/dialogs/qfiledialog_wince.ui"/> <source>Parent Directory</source> <translation>Родительский каталог</translation> </message> <message> - <location line="+14"/> - <location filename="../src/gui/dialogs/qfiledialog_wince.ui" line="+14"/> + <location/> + <location filename="../src/gui/dialogs/qfiledialog_wince.ui"/> <source>List View</source> <translation>Список</translation> </message> <message> - <location line="+7"/> - <location filename="../src/gui/dialogs/qfiledialog_wince.ui" line="+7"/> + <location/> + <location filename="../src/gui/dialogs/qfiledialog_wince.ui"/> <source>Detail View</source> <translation>Подробный вид</translation> </message> <message> - <location line="+141"/> - <location filename="../src/gui/dialogs/qfiledialog_wince.ui" line="+162"/> + <location/> + <location filename="../src/gui/dialogs/qfiledialog_wince.ui"/> <source>Files of type:</source> <translation>Типы файлов:</translation> </message> @@ -1619,8 +1619,8 @@ Do you want to delete it anyway?</source> <translation>Показать </translation> </message> <message> - <location filename="../src/gui/dialogs/qfiledialog.ui" line="-169"/> - <location filename="../src/gui/dialogs/qfiledialog_wince.ui" line="-190"/> + <location filename="../src/gui/dialogs/qfiledialog.ui"/> + <location filename="../src/gui/dialogs/qfiledialog_wince.ui"/> <source>Forward</source> <translation>Вперед</translation> </message> @@ -1652,14 +1652,14 @@ Do you want to delete it anyway?</source> <translation>&Имя файла:</translation> </message> <message> - <location filename="../src/gui/dialogs/qfiledialog.ui" line="-32"/> - <location filename="../src/gui/dialogs/qfiledialog_wince.ui" line="+212"/> + <location filename="../src/gui/dialogs/qfiledialog.ui"/> + <location filename="../src/gui/dialogs/qfiledialog_wince.ui"/> <source>Look in:</source> <translation>Перейти к:</translation> </message> <message> - <location line="+46"/> - <location filename="../src/gui/dialogs/qfiledialog_wince.ui" line="-198"/> + <location/> + <location filename="../src/gui/dialogs/qfiledialog_wince.ui"/> <source>Create New Folder</source> <translation>Создать каталог</translation> </message> @@ -1828,7 +1828,7 @@ Do you want to delete it anyway?</source> <message> <location line="+3"/> <source>Arabic</source> - <translation type="unfinished"></translation> + <translation>Арабская</translation> </message> <message> <location line="+3"/> @@ -1838,57 +1838,57 @@ Do you want to delete it anyway?</source> <message> <location line="+3"/> <source>Thaana</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Таана</translation> </message> <message> <location line="+3"/> <source>Devanagari</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Деванагири</translation> </message> <message> <location line="+3"/> <source>Bengali</source> - <translation type="unfinished"></translation> + <translation>Бенгальская</translation> </message> <message> <location line="+3"/> <source>Gurmukhi</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Гурмукхи</translation> </message> <message> <location line="+3"/> <source>Gujarati</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Гуджарати</translation> </message> <message> <location line="+3"/> <source>Oriya</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Ория</translation> </message> <message> <location line="+3"/> <source>Tamil</source> - <translation type="unfinished"></translation> + <translation>Тамильская</translation> </message> <message> <location line="+3"/> <source>Telugu</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Телугу</translation> </message> <message> <location line="+3"/> <source>Kannada</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Каннада</translation> </message> <message> <location line="+3"/> <source>Malayalam</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Малайялам</translation> </message> <message> <location line="+3"/> <source>Sinhala</source> - <translation type="unfinished"></translation> + <translation>Сингальская</translation> </message> <message> <location line="+3"/> @@ -1898,7 +1898,7 @@ Do you want to delete it anyway?</source> <message> <location line="+3"/> <source>Lao</source> - <translation type="unfinished"></translation> + <translation>Лаосская</translation> </message> <message> <location line="+3"/> @@ -1908,7 +1908,7 @@ Do you want to delete it anyway?</source> <message> <location line="+3"/> <source>Myanmar</source> - <translation type="unfinished"></translation> + <translation type="unfinished">Мьянма</translation> </message> <message> <location line="+3"/> @@ -1953,7 +1953,7 @@ Do you want to delete it anyway?</source> <message> <location line="+3"/> <source>Ogham</source> - <translation type="unfinished"></translation> + <translation>Огамическая</translation> </message> <message> <location line="+3"/> @@ -2401,7 +2401,7 @@ Do you want to delete it anyway?</source> <context> <name>QIBaseDriver</name> <message> - <location filename="../src/sql/drivers/ibase/qsql_ibase.cpp" line="+1434"/> + <location filename="../src/sql/drivers/ibase/qsql_ibase.cpp" line="+1454"/> <source>Error opening database</source> <translation>Невозможно открыть базу данных</translation> </message> @@ -2424,7 +2424,7 @@ Do you want to delete it anyway?</source> <context> <name>QIBaseResult</name> <message> - <location line="-1095"/> + <location line="-1112"/> <source>Unable to create BLOB</source> <translation>Невозможно создать BLOB</translation> </message> @@ -2470,7 +2470,7 @@ Do you want to delete it anyway?</source> <translation>Невозможно выполнить транзакцию</translation> </message> <message> - <location line="+33"/> + <location line="+42"/> <source>Could not allocate statement</source> <translation>Не удалось получить ресурсы для создания выражения</translation> </message> @@ -2481,12 +2481,12 @@ Do you want to delete it anyway?</source> </message> <message> <location line="+5"/> - <location line="+7"/> + <location line="+11"/> <source>Could not describe input statement</source> <translation>Не удалось описать входящее выражение</translation> </message> <message> - <location line="+10"/> + <location line="+14"/> <source>Could not describe statement</source> <translation>Не удалось описать выражение</translation> </message> @@ -3288,7 +3288,7 @@ Do you want to delete it anyway?</source> <context> <name>QOCIDriver</name> <message> - <location filename="../src/sql/drivers/oci/qsql_oci.cpp" line="+2079"/> + <location filename="../src/sql/drivers/oci/qsql_oci.cpp" line="+2082"/> <source>Unable to logon</source> <translation>Невозможно авторизоваться</translation> </message> @@ -3317,7 +3317,7 @@ Do you want to delete it anyway?</source> <context> <name>QOCIResult</name> <message> - <location line="-973"/> + <location line="-976"/> <location line="+161"/> <location line="+15"/> <source>Unable to bind column for batch execute</source> @@ -3329,7 +3329,7 @@ Do you want to delete it anyway?</source> <translation>Невозможно выполнить пакетное выражение</translation> </message> <message> - <location line="+302"/> + <location line="+305"/> <source>Unable to goto next</source> <translation>Невозможно перейти к следующей строке</translation> </message> @@ -3376,7 +3376,7 @@ Do you want to delete it anyway?</source> <translation>Невозможно соединиться - Драйвер не поддерживает требуемый функционал</translation> </message> <message> - <location line="+242"/> + <location line="+239"/> <source>Unable to disable autocommit</source> <translation>Невозможно отключить автовыполнение транзакции</translation> </message> @@ -3399,7 +3399,7 @@ Do you want to delete it anyway?</source> <context> <name>QODBCResult</name> <message> - <location line="-1218"/> + <location line="-1216"/> <location line="+349"/> <source>QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration</source> <translation>QODBCResult::reset: Невозможно установить 'SQL_CURSOR_STATIC' атрибутом выражение. Проверьте настройки драйвера ODBC</translation> @@ -3428,12 +3428,12 @@ Do you want to delete it anyway?</source> <message> <location filename="../src/sql/drivers/db2/qsql_db2.cpp" line="+194"/> <location filename="../src/sql/drivers/odbc/qsql_odbc.cpp" line="-475"/> - <location line="+578"/> + <location line="+579"/> <source>Unable to fetch last</source> <translation>Невозможно получить последнюю строку</translation> </message> <message> - <location filename="../src/sql/drivers/odbc/qsql_odbc.cpp" line="-672"/> + <location filename="../src/sql/drivers/odbc/qsql_odbc.cpp" line="-673"/> <source>Unable to fetch</source> <translation>Невозможно получить данные</translation> </message> @@ -3520,7 +3520,7 @@ Do you want to delete it anyway?</source> <translation>Не удалось начать транзакцию</translation> </message> <message> - <location line="+17"/> + <location line="+30"/> <source>Could not commit transaction</source> <translation>Не удалось выполнить транзакцию</translation> </message> @@ -3576,86 +3576,82 @@ Do you want to delete it anyway?</source> <translation>Точки (pt)</translation> </message> <message> - <location filename="../src/gui/dialogs/qpagesetupwidget.ui" line="+13"/> + <location filename="../src/gui/dialogs/qpagesetupwidget.ui"/> <source>Form</source> <translation>Форма</translation> </message> <message> - <location line="+29"/> + <location/> <source>Paper</source> <translation>Бумага</translation> </message> <message> - <location line="+6"/> + <location/> <source>Page size:</source> <translation>Размер страницы:</translation> </message> <message> - <location line="+13"/> + <location/> <source>Width:</source> <translation>Ширина:</translation> </message> <message> - <location line="+19"/> + <location/> <source>Height:</source> <translation>Высота:</translation> </message> <message> - <location line="+19"/> + <location/> <source>Paper source:</source> <translation>Источник бумаги:</translation> </message> <message> - <location line="+29"/> + <location/> <source>Orientation</source> <translation>Ориентация страницы</translation> </message> <message> - <location line="+6"/> + <location/> <source>Portrait</source> <translation>Книжная</translation> </message> <message> - <location line="+10"/> + <location/> <source>Landscape</source> <translation>Альбомная</translation> </message> <message> - <location line="+7"/> + <location/> <source>Reverse landscape</source> <translation>Перевёрнутая альбомная</translation> </message> <message> - <location line="+7"/> + <location/> <source>Reverse portrait</source> <translation>Перевёрнутая книжная</translation> </message> <message> - <location line="+26"/> + <location/> <source>Margins</source> <translation>Поля</translation> </message> <message> - <location line="+8"/> - <location line="+3"/> + <location/> <source>top margin</source> <translation>верхнее поле</translation> </message> <message> - <location line="+28"/> - <location line="+3"/> + <location/> <source>left margin</source> <translation>Левое поле</translation> </message> <message> - <location line="+29"/> - <location line="+3"/> + <location/> <source>right margin</source> <translation>правое поле</translation> </message> <message> - <location line="+28"/> - <location line="+3"/> + <location/> <source>bottom margin</source> <translation>Нижнее поле</translation> </message> @@ -4213,17 +4209,17 @@ Please choose a different file name.</source> <context> <name>QPrintPropertiesWidget</name> <message> - <location filename="../src/gui/dialogs/qprintpropertieswidget.ui" line="+13"/> + <location filename="../src/gui/dialogs/qprintpropertieswidget.ui"/> <source>Form</source> <translation>Форма</translation> </message> <message> - <location line="+21"/> + <location/> <source>Page</source> <translation>Страница</translation> </message> <message> - <location line="+10"/> + <location/> <source>Advanced</source> <translation>Дополнительно</translation> </message> @@ -4231,97 +4227,97 @@ Please choose a different file name.</source> <context> <name>QPrintSettingsOutput</name> <message> - <location filename="../src/gui/dialogs/qprintsettingsoutput.ui" line="+13"/> + <location filename="../src/gui/dialogs/qprintsettingsoutput.ui"/> <source>Form</source> <translation>Форма</translation> </message> <message> - <location line="+21"/> + <location/> <source>Copies</source> <translation>Копии</translation> </message> <message> - <location line="+12"/> + <location/> <source>Print range</source> <translation>Печатать диапазон</translation> </message> <message> - <location line="+12"/> + <location/> <source>Print all</source> <translation>Печатать все</translation> </message> <message> - <location line="+18"/> + <location/> <source>Pages from</source> <translation>Страницы от</translation> </message> <message> - <location line="+20"/> + <location/> <source>to</source> <translation>до</translation> </message> <message> - <location line="+35"/> + <location/> <source>Selection</source> <translation>Выделенные</translation> </message> <message> - <location line="+23"/> + <location/> <source>Output Settings</source> <translation>Настройки вывода</translation> </message> <message> - <location line="+6"/> + <location/> <source>Copies:</source> <translation>Количество копий:</translation> </message> <message> - <location line="+33"/> + <location/> <source>Collate</source> <translation>Разобрать про копиям</translation> </message> <message> - <location line="+17"/> + <location/> <source>Reverse</source> <translation>Обратный порядок</translation> </message> <message> - <location line="+32"/> + <location/> <source>Options</source> <translation>Параметры</translation> </message> <message> - <location line="+6"/> + <location/> <source>Color Mode</source> <translation>Режим цвета</translation> </message> <message> - <location line="+19"/> + <location/> <source>Color</source> <translation>Цвет</translation> </message> <message> - <location line="+10"/> + <location/> <source>Grayscale</source> <translation>Оттенки серого</translation> </message> <message> - <location line="+10"/> + <location/> <source>Duplex Printing</source> <translation>Двусторонняя печать</translation> </message> <message> - <location line="+6"/> + <location/> <source>None</source> <translation>Нет</translation> </message> <message> - <location line="+10"/> + <location/> <source>Long side</source> <translation>По длинной стороне</translation> </message> <message> - <location line="+7"/> + <location/> <source>Short side</source> <translation>По короткой стороне</translation> </message> @@ -4329,47 +4325,47 @@ Please choose a different file name.</source> <context> <name>QPrintWidget</name> <message> - <location filename="../src/gui/dialogs/qprintwidget.ui" line="+13"/> + <location filename="../src/gui/dialogs/qprintwidget.ui"/> <source>Form</source> <translation>Форма</translation> </message> <message> - <location line="+9"/> + <location/> <source>Printer</source> <translation>Принтер</translation> </message> <message> - <location line="+6"/> + <location/> <source>&Name:</source> <translation>&Имя:</translation> </message> <message> - <location line="+26"/> + <location/> <source>P&roperties</source> <translation>С&войства</translation> </message> <message> - <location line="+7"/> + <location/> <source>Location:</source> <translation>Положение:</translation> </message> <message> - <location line="+10"/> + <location/> <source>Preview</source> <translation>Предпросмотр</translation> </message> <message> - <location line="+7"/> + <location/> <source>Type:</source> <translation>Тип:</translation> </message> <message> - <location line="+10"/> + <location/> <source>Output &file:</source> <translation>Выходной &файл:</translation> </message> <message> - <location line="+15"/> + <location/> <source>...</source> <translation>...</translation> </message> @@ -6329,7 +6325,7 @@ Please choose a different file name.</source> <context> <name>QWizard</name> <message> - <location filename="../src/gui/dialogs/qwizard.cpp" line="+637"/> + <location filename="../src/gui/dialogs/qwizard.cpp" line="+638"/> <source>Go Back</source> <translation>Назад</translation> </message> diff --git a/translations/qtconfig_ru.ts b/translations/qtconfig_ru.ts new file mode 100644 index 0000000..b1965f2 --- /dev/null +++ b/translations/qtconfig_ru.ts @@ -0,0 +1,906 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="ru"> +<context> + <name>MainWindow</name> + <message> + <location filename="../tools/qtconfig/mainwindow.cpp" line="+202"/> + <source>Desktop Settings (Default)</source> + <translation>Настройки рабочего стола (по умолчанию)</translation> + </message> + <message> + <location line="+5"/> + <source>Choose style and palette based on your desktop settings.</source> + <translation>Выбор стиля и палитры на основе настроек рабочего стола.</translation> + </message> + <message> + <location line="+144"/> + <source>On The Spot</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+33"/> + <location line="+1"/> + <location line="+38"/> + <location line="+1"/> + <source>Auto (default)</source> + <translation>Автоматически (по умолчанию)</translation> + </message> + <message> + <location line="-38"/> + <source>Choose audio output automatically.</source> + <translation>Автоматический выбор звукового выхода.</translation> + </message> + <message> + <location line="+1"/> + <location line="+1"/> + <source>aRts</source> + <translation>aRts</translation> + </message> + <message> + <location line="+1"/> + <source>Experimental aRts support for GStreamer.</source> + <translation>Экспериментальная поддержка aRts в GStreamer.</translation> + </message> + <message> + <location line="+31"/> + <source>Phonon GStreamer backend not available.</source> + <translation type="unfinished">Модуль Phonon поддержки GStreamer не доступен.</translation> + </message> + <message> + <location line="+4"/> + <source>Choose render method automatically</source> + <translation>Автоматический выбор метода отрисовки</translation> + </message> + <message> + <location line="+2"/> + <location line="+1"/> + <source>X11</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Use X11 Overlays</source> + <translation type="unfinished">Использовать оверлеи X11</translation> + </message> + <message> + <location line="+3"/> + <location line="+1"/> + <source>OpenGL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Use OpenGL if avaiable</source> + <translation>Использовать OpenGL, если доступен</translation> + </message> + <message> + <location line="+2"/> + <location line="+1"/> + <source>Software</source> + <translation>Программный</translation> + </message> + <message> + <location line="+0"/> + <source>Use simple software rendering</source> + <translation>Использовать простую программную отрисовку</translation> + </message> + <message> + <location line="+27"/> + <source>No changes to be saved.</source> + <translation>Нет изменений для сохранения.</translation> + </message> + <message> + <location line="+4"/> + <source>Saving changes...</source> + <translation>Сохранение изменений...</translation> + </message> + <message> + <location line="+48"/> + <source>Over The Spot</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Off The Spot</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Root</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+466"/> + <source>Select a Directory</source> + <translation>Выбор каталога</translation> + </message> + <message> + <location line="+17"/> + <source><h3>%1</h3><br/>Version %2<br/><br/>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).<br/><br/>The program is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.<br/> </source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <location line="+1"/> + <location line="+8"/> + <source>Qt Configuration</source> + <translation>Конфигурация Qt</translation> + </message> + <message> + <location line="+22"/> + <source>Save Changes</source> + <translation>Сохранение изменений</translation> + </message> + <message> + <location line="+1"/> + <source>Save changes to settings?</source> + <translation>Сохранить изменения настроек?</translation> + </message> + <message> + <location line="+1"/> + <source>&Yes</source> + <translation>&Да</translation> + </message> + <message> + <location line="+0"/> + <source>&No</source> + <translation>&Нет</translation> + </message> + <message> + <location line="+0"/> + <source>&Cancel</source> + <translation>&Отмена</translation> + </message> +</context> +<context> + <name>MainWindowBase</name> + <message> + <location filename="../tools/qtconfig/mainwindowbase.ui" line="+54"/> + <source>Qt Configuration</source> + <translation>Конфигурация Qt</translation> + </message> + <message> + <location line="+35"/> + <source>Appearance</source> + <translation>Внешний вид</translation> + </message> + <message> + <location line="+18"/> + <source>GUI Style</source> + <translation>Стиль пользовательского графического интерфейса</translation> + </message> + <message> + <location line="+18"/> + <source>Select GUI &Style:</source> + <translation type="unfinished">&Стиль интерфейса:</translation> + </message> + <message> + <location line="+88"/> + <source>Build Palette</source> + <translation type="unfinished">Палитра</translation> + </message> + <message> + <location line="+12"/> + <source>&3-D Effects:</source> + <translation>Эффекты &3-D:</translation> + </message> + <message> + <location line="+31"/> + <source>Window Back&ground:</source> + <translation>&Фон окна:</translation> + </message> + <message> + <location line="+35"/> + <source>&Tune Palette...</source> + <translation>&Настроить палитру...</translation> + </message> + <message> + <location line="+10"/> + <source>Please use the KDE Control Center to set the palette.</source> + <translation>Используйте Центр управления KDE для настройки цветов.</translation> + </message> + <message> + <location line="-154"/> + <source>Preview</source> + <translation>Предпросмотр</translation> + </message> + <message> + <location line="+6"/> + <source>Select &Palette:</source> + <translation>Выбор &палитры:</translation> + </message> + <message> + <location line="+11"/> + <source>Active Palette</source> + <translation>Палитра активных элементов</translation> + </message> + <message> + <location line="+5"/> + <source>Inactive Palette</source> + <translation>Палитра неактивных элементов</translation> + </message> + <message> + <location line="+5"/> + <source>Disabled Palette</source> + <translation>Палитра выключенных элементов</translation> + </message> + <message> + <location line="+138"/> + <source>Fonts</source> + <translation>Шрифты</translation> + </message> + <message> + <location line="+6"/> + <source>Default Font</source> + <translation>Шрифт по умолчанию</translation> + </message> + <message> + <location line="+45"/> + <source>&Style:</source> + <translation>&Стиль:</translation> + </message> + <message> + <location line="+10"/> + <source>&Point Size:</source> + <translation>&Размер в точках:</translation> + </message> + <message> + <location line="+10"/> + <source>F&amily:</source> + <translation>Семе&йство:</translation> + </message> + <message> + <location line="+10"/> + <source>Sample Text</source> + <translation>Текст для примера (Sample Text)</translation> + </message> + <message> + <location line="+13"/> + <source>Font Substitution</source> + <translation>Подстановка шрифтов</translation> + </message> + <message> + <location line="+20"/> + <source>S&elect or Enter a Family:</source> + <translation>&Выберите или введите семейство:</translation> + </message> + <message> + <location line="+38"/> + <source>Current Substitutions:</source> + <translation type="unfinished">Текущие замены:</translation> + </message> + <message> + <location line="+18"/> + <location line="+501"/> + <source>Up</source> + <translation>Выше</translation> + </message> + <message> + <location line="-494"/> + <location line="+508"/> + <source>Down</source> + <translation>Ниже</translation> + </message> + <message> + <location line="-501"/> + <location line="+494"/> + <source>Remove</source> + <translation>Удалить</translation> + </message> + <message> + <location line="-464"/> + <source>Select s&ubstitute Family:</source> + <translation>Выберите п&одставляемое семейство:</translation> + </message> + <message> + <location line="+20"/> + <location line="+487"/> + <source>Add</source> + <translation>Добавить</translation> + </message> + <message> + <location line="-474"/> + <source>Interface</source> + <translation>Интерфейс</translation> + </message> + <message> + <location line="+6"/> + <source>Feel Settings</source> + <translation type="unfinished">Настройка указателя</translation> + </message> + <message> + <location line="+12"/> + <location line="+26"/> + <source> ms</source> + <translation> мс</translation> + </message> + <message> + <location line="-13"/> + <source>&Double Click Interval:</source> + <translation>&Интервал двойного щелчка:</translation> + </message> + <message> + <location line="+10"/> + <source>No blinking</source> + <translation>Без мигания</translation> + </message> + <message> + <location line="+16"/> + <source>&Cursor Flash Time:</source> + <translation>&Период мигания курсора:</translation> + </message> + <message> + <location line="+10"/> + <source> lines</source> + <translation> строк</translation> + </message> + <message> + <location line="+13"/> + <source>Wheel &Scroll Lines:</source> + <translation type="unfinished">&Прокручивать строк при повороте колёсика:</translation> + </message> + <message> + <location line="+10"/> + <source>Resolve symlinks in URLs</source> + <translation>Разрешать символьные ссылки в URL-ах</translation> + </message> + <message> + <location line="+10"/> + <source>GUI Effects</source> + <translation type="unfinished">Эффекты пользовательского интерфейса</translation> + </message> + <message> + <location line="+12"/> + <source>&Enable</source> + <translation>&Включить</translation> + </message> + <message> + <location line="+3"/> + <source>Alt+E</source> + <translation>Alt+D</translation> + </message> + <message> + <location line="+22"/> + <source>&Menu Effect:</source> + <translation>Эффект &меню:</translation> + </message> + <message> + <location line="+10"/> + <source>C&omboBox Effect:</source> + <translation type="unfinished">Эффект C&omboBox:</translation> + </message> + <message> + <location line="+10"/> + <source>&ToolTip Effect:</source> + <translation type="unfinished">Эффект &ToolTip:</translation> + </message> + <message> + <location line="+10"/> + <source>Tool&Box Effect:</source> + <translation type="unfinished">Эффект Tool&Box:</translation> + </message> + <message> + <location line="+17"/> + <location line="+19"/> + <location line="+14"/> + <location line="+19"/> + <source>Disable</source> + <translation>Выключен</translation> + </message> + <message> + <location line="-47"/> + <location line="+19"/> + <location line="+14"/> + <location line="+19"/> + <source>Animate</source> + <translation>Анимация</translation> + </message> + <message> + <location line="-47"/> + <location line="+33"/> + <source>Fade</source> + <translation>Затухание</translation> + </message> + <message> + <location line="+28"/> + <source>Global Strut</source> + <translation type="unfinished">Специальные возможности</translation> + </message> + <message> + <location line="+12"/> + <source>Minimum &Width:</source> + <translation>Минимальная &ширина:</translation> + </message> + <message> + <location line="+10"/> + <source>Minimum Hei&ght:</source> + <translation>Минимальная в&ысота:</translation> + </message> + <message> + <location line="+10"/> + <location line="+10"/> + <source> pixels</source> + <translation> пикселей</translation> + </message> + <message> + <location line="+13"/> + <source>Enhanced support for languages written right-to-left</source> + <translation>Расширенная поддержка письма справа налево</translation> + </message> + <message> + <location line="+7"/> + <source>XIM Input Style:</source> + <translation>Стиль ввода XIM:</translation> + </message> + <message> + <location line="+11"/> + <source>On The Spot</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Over The Spot</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Off The Spot</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Root</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Default Input Method:</source> + <translation>Метод ввода по умолчанию:</translation> + </message> + <message> + <location line="+31"/> + <source>Printer</source> + <translation>Принтер</translation> + </message> + <message> + <location line="+6"/> + <source>Enable Font embedding</source> + <translation>Разрешить встраивание шрифтов</translation> + </message> + <message> + <location line="+16"/> + <source>Font Paths</source> + <translation>Пути к шрифтам</translation> + </message> + <message> + <location line="+77"/> + <source>Browse...</source> + <translation>Обзор...</translation> + </message> + <message> + <location line="+7"/> + <source>Press the <b>Browse</b> button or enter a directory and press Enter to add them to the list.</source> + <translation>Нажмите кнопку <b>Обзор...</b> или укажите каталог и нажмите Ввод для добавления его в список.</translation> + </message> + <message> + <location line="+16"/> + <source>Phonon</source> + <translation>Phonon</translation> + </message> + <message> + <location line="+6"/> + <source>About Phonon</source> + <translation>О Phonon</translation> + </message> + <message> + <location line="+6"/> + <location line="+44"/> + <source>Current Version:</source> + <translation>Текущая версия:</translation> + </message> + <message> + <location line="-37"/> + <location line="+44"/> + <source>Not available</source> + <translation>Недоступно</translation> + </message> + <message> + <location line="-37"/> + <location line="+44"/> + <source>Website:</source> + <translation>Вэб-сайт:</translation> + </message> + <message> + <location line="-37"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://phonon.kde.org"><span style=" text-decoration: underline; color:#0000ff;">http://phonon.kde.org</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>About GStreamer</source> + <translation>О GStreamer</translation> + </message> + <message> + <location line="+27"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://gstreamer.freedesktop.org/"><span style=" text-decoration: underline; color:#0000ff;">http://gstreamer.freedesktop.org/</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>GStreamer backend settings</source> + <translation>Настройки модуля GStreamer</translation> + </message> + <message> + <location line="+6"/> + <source>Preferred audio sink:</source> + <translation>Предпочитаемое звуковое устройство:</translation> + </message> + <message> + <location line="+13"/> + <source>Preferred render method:</source> + <translation>Предпочитаемый метод отрисовки:</translation> + </message> + <message> + <location line="+13"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Note: changes to these settings may prevent applications from starting up correctly.</span></p></body></html></source> + <translation type="unfinished"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Внимание: Изменение данных настроек может повлечь невозможность корректного запуска приложений.</span></p></body></html></translation> + </message> + <message> + <location line="+68"/> + <source>&File</source> + <translation>&Файл</translation> + </message> + <message> + <location line="+19"/> + <source>&Help</source> + <translation>&Справка</translation> + </message> + <message> + <location line="+14"/> + <source>&Save</source> + <translation>&Сохранить</translation> + </message> + <message> + <location line="+3"/> + <source>Save</source> + <translation>Сохранить</translation> + </message> + <message> + <location line="+3"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>E&xit</source> + <translation>В&ыход</translation> + </message> + <message> + <location line="+3"/> + <source>Exit</source> + <translation>Выход</translation> + </message> + <message> + <location line="+8"/> + <source>&About</source> + <translation>&О программе</translation> + </message> + <message> + <location line="+3"/> + <source>About</source> + <translation>О программе</translation> + </message> + <message> + <location line="+8"/> + <source>About &Qt</source> + <translation>О &Qt</translation> + </message> + <message> + <location line="+3"/> + <source>About Qt</source> + <translation>О Qt</translation> + </message> +</context> +<context> + <name>PaletteEditorAdvancedBase</name> + <message> + <location filename="../tools/qtconfig/paletteeditoradvancedbase.ui" line="+61"/> + <source>Tune Palette</source> + <translation>Настройка палитры</translation> + </message> + <message> + <location line="+6"/> + <source><b>Edit Palette</b><p>Change the palette of the current widget or form.</p><p>Use a generated palette or select colors for each color group and each color role.</p><p>The palette can be tested with different widget layouts in the preview section.</p></source> + <translation type="unfinished"><b>Изменение палитры</b><p>Изменение палитры текущего виджета или формы.</p><p>Используйте сформированную палитру или выберите цвета для каждой группы цветов и каждой их роли.</p><p>Палитру можно проверить на виджетах в разных режимах отображения в разделе предпросмотра.</p></translation> + </message> + <message> + <location line="+29"/> + <source>Select &Palette:</source> + <translation>Выбор &палитры:</translation> + </message> + <message> + <location line="+14"/> + <source>Active Palette</source> + <translation>Палитра активных элементов</translation> + </message> + <message> + <location line="+5"/> + <source>Inactive Palette</source> + <translation>Палитра неактивных элементов</translation> + </message> + <message> + <location line="+5"/> + <source>Disabled Palette</source> + <translation>Палитра выключенных элементов</translation> + </message> + <message> + <location line="+21"/> + <source>Auto</source> + <translation type="unfinished">Автоматически</translation> + </message> + <message> + <location line="+18"/> + <source>Build inactive palette from active</source> + <translation type="unfinished">Создать неактивную палитру из активной</translation> + </message> + <message> + <location line="+13"/> + <source>Build disabled palette from active</source> + <translation type="unfinished">Создать выключенную палитру из активной</translation> + </message> + <message> + <location line="+16"/> + <source>Central color &roles</source> + <translation type="unfinished">Роли &цветов</translation> + </message> + <message> + <location line="+18"/> + <source>Choose central color role</source> + <translation type="unfinished">Выберите роль цвета</translation> + </message> + <message> + <location line="+3"/> + <source><b>Select a color role.</b><p>Available central roles are: <ul> <li>Window - general background color.</li> <li>WindowText - general foreground color. </li> <li>Base - used as background color for e.g. text entry widgets, usually white or another light color. </li> <li>Text - the foreground color used with Base. Usually this is the same as WindowText, in what case it must provide good contrast both with Window and Base. </li> <li>Button - general button background color, where buttons need a background different from Window, as in the Macintosh style. </li> <li>ButtonText - a foreground color used with the Button color. </li> <li>Highlight - a color to indicate a selected or highlighted item. </li> <li>HighlightedText - a text color that contrasts to Highlight. </li> <li>BrightText - a text color that is very different from WindowText and contrasts well with e.g. black. </li> </ul> </p></source> + <translation type="unfinished"><b>Выбор роли цвета.</b><p>Доступны следующие роли: <ul><li>Window - основной цвет фона.</li> <li>WindowText - основной цвет текста.</li> <li>Base - используется в качестве фона для, например, виджетов с текстовыми полями, обычно, белый или другой светлый цвет.</li> <li>Text - цвет текста используемый совместно с Base. Обычно, он совпадает с WindowText, так как в этом случае получается максимальный контраст и с Window, и с Base.</li> <li>Button - основной цвет фона кнопки, которой требуется цвет отличный от Window, например, в стиле Macintosh.</li> <li>ButtonText - цвет текста используемый совместно с Button.</li> <li>Highlight - цвет для обозначения выбранного или выделенного элемента.</li> <li>HighlightedText - цвет текста контрастирующий с Highlight.</li> <li>BrightText - цвет текста, который отличается от WindowText и хорошо контрастирует с черным.</li></ul></p></translation> + </message> + <message> + <location line="+4"/> + <source>Window</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>WindowText</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Button</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Base</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Text</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>BrightText</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>ButtonText</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Highlight</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>HighlightedText</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+52"/> + <source>&Select Color:</source> + <translation>&Выбор цвета:</translation> + </message> + <message> + <location line="+24"/> + <location line="+171"/> + <source>Choose a color</source> + <translation>Выберите цвет</translation> + </message> + <message> + <location line="-168"/> + <source>Choose a color for the selected central color role.</source> + <translation>Выберите цвет для указанной роли.</translation> + </message> + <message> + <location line="+15"/> + <source>3-D shadow &effects</source> + <translation>Эффекты т&рехмерной тени</translation> + </message> + <message> + <location line="+29"/> + <source>Build &from button color</source> + <translation>Получ&ить из цвета кнопки</translation> + </message> + <message> + <location line="+6"/> + <source>Generate shadings</source> + <translation type="unfinished">Создание полутонов</translation> + </message> + <message> + <location line="+3"/> + <source>Check to let 3D-effect colors be calculated from button-color.</source> + <translation type="unfinished">Включите, чтобы цвета эффекта трёхмерности были получены из цвета кнопки.</translation> + </message> + <message> + <location line="+10"/> + <source>Choose 3D-effect color role</source> + <translation type="unfinished">Выбор роли цвета дял эффекта трёхмерности</translation> + </message> + <message> + <location line="+3"/> + <source><b>Select a color role.</b><p>Available effect roles are: <ul> <li>Light - lighter than Button color. </li> <li>Midlight - between Button and Light. </li> <li>Mid - between Button and Dark. </li> <li>Dark - darker than Button. </li> <li>Shadow - a very dark color. </li> </ul></source> + <translation><b>Выбор роли цвета.</b><p>Доступны следующие роли: <ul> <li>Light - светлее цвета Button. </li> <li>Midlight - среднее между Light и Button. </li> <li>Mid - среднее между Button и Dark. </li> <li>Dark - темнее цвета Button. </li> <li>Shadow - очень темный цвет. </li> </ul></translation> + </message> + <message> + <location line="+4"/> + <source>Light</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Midlight</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Mid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Dark</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Shadow</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+54"/> + <source>Select Co&lor:</source> + <translation>Выбор &цвета:</translation> + </message> + <message> + <location line="+27"/> + <source>Choose a color for the selected effect color role.</source> + <translation type="unfinished">Выбор цвета для указанной роли.</translation> + </message> + <message> + <location line="+42"/> + <source>OK</source> + <translation>Принять</translation> + </message> + <message> + <location line="+9"/> + <source>Close dialog and apply all changes.</source> + <translation>Закрыть окно с применением изменений.</translation> + </message> + <message> + <location line="+10"/> + <source>Cancel</source> + <translation>Отмена</translation> + </message> + <message> + <location line="+6"/> + <source>Close dialog and discard all changes.</source> + <translation>Закрыть окно с отменой изменений.</translation> + </message> +</context> +<context> + <name>PreviewFrame</name> + <message> + <location filename="../tools/qtconfig/previewframe.cpp" line="+81"/> + <source>Desktop settings will only take effect after an application restart.</source> + <translation type="unfinished">Настройки рабочего стола применятся после перезапуска приложения.</translation> + </message> +</context> +<context> + <name>PreviewWidgetBase</name> + <message> + <location filename="../tools/qtconfig/previewwidgetbase.ui" line="+66"/> + <source>Preview Window</source> + <translation>Окно предпросмотра</translation> + </message> + <message> + <location line="+40"/> + <source>ButtonGroup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+18"/> + <source>RadioButton1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> + <source>RadioButton2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>RadioButton3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> + <source>ButtonGroup2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+18"/> + <source>CheckBox1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> + <source>CheckBox2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+36"/> + <source>LineEdit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>ComboBox</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+29"/> + <source>PushButton</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+41"/> + <source><p> +<a href="http://qtsoftware.com">http://qtsoftware.com</a> +</p> +<p> +<a href="http://www.kde.org">http://www.kde.org</a> +</p></source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/translations/qvfb_ru.ts b/translations/qvfb_ru.ts new file mode 100644 index 0000000..b084380 --- /dev/null +++ b/translations/qvfb_ru.ts @@ -0,0 +1,328 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="ru"> +<context> + <name>AnimationSaveWidget</name> + <message> + <location filename="../tools/qvfb/qvfb.cpp" line="+850"/> + <location line="+204"/> + <source>Record</source> + <translation>Записать</translation> + </message> + <message> + <location line="-202"/> + <source>Reset</source> + <translation>Сбросить</translation> + </message> + <message> + <location line="+2"/> + <source>Save</source> + <translation>Сохранить</translation> + </message> + <message> + <location line="+18"/> + <source>Save in MPEG format (requires netpbm package installed)</source> + <translation>Сохранить в формат MPEG (требуется установленный пакет netpbm)</translation> + </message> + <message> + <location line="+8"/> + <location line="+206"/> + <source>Click record to begin recording.</source> + <translation>Нажмите "Записать" для начала записи.</translation> + </message> + <message> + <location line="-115"/> + <location line="+147"/> + <source>Finished saving.</source> + <translation>Сохранение завершено.</translation> + </message> + <message> + <location line="-63"/> + <source>Paused. Click record to resume, or save if done.</source> + <translation>Приостановлено. Нажмите "Записать" для продолжения или "Сохранить", если готово.</translation> + </message> + <message> + <location line="+6"/> + <source>Pause</source> + <translation>Пауза</translation> + </message> + <message> + <location line="+1"/> + <source>Recording...</source> + <translation>Идёт запись...</translation> + </message> + <message> + <location line="+40"/> + <source>Saving... </source> + <translation>Сохранение... </translation> + </message> + <message> + <location line="+4"/> + <location line="+4"/> + <source>Save animation...</source> + <translation>Сохранение анимации...</translation> + </message> + <message> + <location line="+2"/> + <source>Save canceled.</source> + <translation>Сохранение отменено.</translation> + </message> + <message> + <location line="+9"/> + <source>Save failed!</source> + <translation>Сохранение не удалось!</translation> + </message> +</context> +<context> + <name>Config</name> + <message> + <location filename="../tools/qvfb/config.ui" line="+53"/> + <source>Configure</source> + <translation>Настройка</translation> + </message> + <message> + <location line="+47"/> + <source>Size</source> + <translation>Размер</translation> + </message> + <message> + <location line="+21"/> + <source>176x220 "SmartPhone"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>240x320 "PDA"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>320x240 "TV" / "QVGA"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>640x480 "VGA"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>800x600</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>1024x768</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+30"/> + <source>Custom</source> + <translation>Особый</translation> + </message> + <message> + <location line="+44"/> + <source>Depth</source> + <translation>Глубина</translation> + </message> + <message> + <location line="+21"/> + <source>1 bit monochrome</source> + <translation>1 бит (монохромный)</translation> + </message> + <message> + <location line="+7"/> + <source>4 bit grayscale</source> + <translation>4 бита (градации серого)</translation> + </message> + <message> + <location line="+7"/> + <source>8 bit</source> + <translation>8 бит</translation> + </message> + <message> + <location line="+7"/> + <source>12 (16) bit</source> + <translation>12 (16) бит</translation> + </message> + <message> + <location line="+7"/> + <source>15 bit</source> + <translation>15 бит</translation> + </message> + <message> + <location line="+7"/> + <source>16 bit</source> + <translation>16 бит</translation> + </message> + <message> + <location line="+7"/> + <source>18 bit</source> + <translation>18 бит</translation> + </message> + <message> + <location line="+7"/> + <source>24 bit</source> + <translation>24 бита</translation> + </message> + <message> + <location line="+7"/> + <source>32 bit</source> + <translation>32 бита</translation> + </message> + <message> + <location line="+7"/> + <source>32 bit ARGB</source> + <translation>32 бита (ARGB)</translation> + </message> + <message> + <location line="+29"/> + <source>Skin</source> + <translation>Обложка</translation> + </message> + <message> + <location line="+14"/> + <source>None</source> + <translation>Нет</translation> + </message> + <message> + <location line="+10"/> + <source>Emulate touch screen (no mouse move)</source> + <translation>Эмулировать тачскрин (без перемещения мыши)</translation> + </message> + <message> + <location line="+7"/> + <source>Emulate LCD screen (Only with fixed zoom of 3.0 times magnification)</source> + <translation>Эмулировать ж/к экран (только с 3-х кратным увеличением)</translation> + </message> + <message> + <location line="+26"/> + <source><p>Note that any applications using the virtual framebuffer will be terminated if you change the Size or Depth <i>above</i>. You may freely modify the Gamma <i>below</i>.</source> + <translation><p>Имейте в виду, что любая программа будет завершена, если изменится размер или глубина экрана. Параметр Гамма можно менять свободно.</translation> + </message> + <message> + <location line="+10"/> + <source>Gamma</source> + <translation>Гамма</translation> + </message> + <message> + <location line="+24"/> + <source>Blue</source> + <translation>Синий</translation> + </message> + <message> + <location line="+489"/> + <location line="+496"/> + <location line="+14"/> + <location line="+496"/> + <source>1.0</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-999"/> + <source>Green</source> + <translation>Зеленый</translation> + </message> + <message> + <location line="+496"/> + <source>All</source> + <translation>Все</translation> + </message> + <message> + <location line="+496"/> + <source>Red</source> + <translation>Красный</translation> + </message> + <message> + <location line="+496"/> + <source>Set all to 1.0</source> + <translation>Выставить все в 1.0</translation> + </message> + <message> + <location line="+43"/> + <source>&OK</source> + <translation>&Готово</translation> + </message> + <message> + <location line="+13"/> + <source>&Cancel</source> + <translation>&Отмена</translation> + </message> +</context> +<context> + <name>DeviceSkin</name> + <message> + <location filename="../tools/shared/deviceskin/deviceskin.cpp" line="+79"/> + <source>The image file '%1' could not be loaded.</source> + <translation>Не удалось загрузить изображение '%1'.</translation> + </message> + <message> + <location line="+64"/> + <source>The skin directory '%1' does not contain a configuration file.</source> + <translation>Каталог обложки '%1' не содержит файла настроек.</translation> + </message> + <message> + <location line="+5"/> + <source>The skin configuration file '%1' could not be opened.</source> + <translation>Не удалось открыть файл настроек обложки '%1'.</translation> + </message> + <message> + <location line="+6"/> + <source>The skin configuration file '%1' could not be read: %2</source> + <translation>Не удалось прочитать файл настроек обложки '%1': %2</translation> + </message> + <message> + <location line="+70"/> + <source>Syntax error: %1</source> + <translation>Синтаксическая ошибка: %1</translation> + </message> + <message> + <location line="+21"/> + <source>The skin "up" image file '%1' does not exist.</source> + <translation>Файл изображения "up" '%1' не существует.</translation> + </message> + <message> + <location line="+10"/> + <source>The skin "down" image file '%1' does not exist.</source> + <translation>Файл изображения "down" '%1' не существует.</translation> + </message> + <message> + <location line="+11"/> + <source>The skin "closed" image file '%1' does not exist.</source> + <translation>Файл изображения "closed" '%1' не существует.</translation> + </message> + <message> + <location line="+12"/> + <source>The skin cursor image file '%1' does not exist.</source> + <translation>Файл изображения курсора '%1' не существует.</translation> + </message> + <message> + <location line="+25"/> + <source>Syntax error in area definition: %1</source> + <translation>Синтаксическая ошибка в определении области: %1</translation> + </message> + <message> + <location line="+38"/> + <source>Mismatch in number of areas, expected %1, got %2.</source> + <translation>Несовпадение количества зон: ожидается %1, указано %2.</translation> + </message> +</context> +<context> + <name>QVFb</name> + <message> + <location filename="../tools/qvfb/qvfb.cpp" line="-487"/> + <source>Browse...</source> + <translation>Обзор...</translation> + </message> + <message> + <location line="+126"/> + <source>Load Custom Skin...</source> + <translation>Загрузить обложку пользователя...</translation> + </message> + <message> + <location line="+1"/> + <source>All QVFB Skins (*.skin)</source> + <translation>Все обложки QVFB (*.skin)</translation> + </message> +</context> +</TS> |