diff options
author | Bradley T. Hughes <bradley.hughes@nokia.com> | 2009-05-18 13:25:43 (GMT) |
---|---|---|
committer | Bradley T. Hughes <bradley.hughes@nokia.com> | 2009-05-18 13:25:43 (GMT) |
commit | 86edc526684d80e405bcd1c63b5a314b70408679 (patch) | |
tree | dfe6a3e989d4468d852019d00f062c4b8d48d036 /src | |
parent | 5c42e4328cc2bea53dc4d31eb3f4d10d42ac6ee1 (diff) | |
parent | 7e4d4474d10cb17047d95e3a4820388468c74507 (diff) | |
download | Qt-86edc526684d80e405bcd1c63b5a314b70408679.zip Qt-86edc526684d80e405bcd1c63b5a314b70408679.tar.gz Qt-86edc526684d80e405bcd1c63b5a314b70408679.tar.bz2 |
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt
Diffstat (limited to 'src')
43 files changed, 1648 insertions, 450 deletions
diff --git a/src/corelib/concurrent/qfuturewatcher.cpp b/src/corelib/concurrent/qfuturewatcher.cpp index ea35e9e..39d7698 100644 --- a/src/corelib/concurrent/qfuturewatcher.cpp +++ b/src/corelib/concurrent/qfuturewatcher.cpp @@ -465,7 +465,7 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event) break; emit q->progressValueChanged(event->index1); - if (event->text != QString()) // ### + if (!event->text.isNull()) // ### q->progressTextChanged(event->text); break; case QFutureCallOutEvent::ProgressRange: diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index 8334146..9b0fbe5 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -51,6 +51,7 @@ #include <QtCore/qstring.h> #include <QtCore/qvector.h> #include <QtCore/qset.h> +#include <QtCore/qcontiguouscache.h> QT_BEGIN_HEADER @@ -232,6 +233,24 @@ inline QDebug operator<<(QDebug debug, const QSet<T> &set) return operator<<(debug, set.toList()); } +#if defined(FORCE_UREF) +template <class T> +inline QDebug &operator<<(QDebug debug, const QContiguousCache<T> &cache) +#else +template <class T> +inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache) +#endif +{ + debug.nospace() << "QContiguousCache("; + for (int i = cache.firstIndex(); i <= cache.lastIndex(); ++i) { + debug << cache[i]; + if (i != cache.lastIndex()) + debug << ", "; + } + debug << ")"; + return debug.space(); +} + #if !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); } diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index c21cf87..77ef096 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1710,7 +1710,7 @@ QString QCoreApplication::applicationDirPath() } QCoreApplicationPrivate *d = self->d_func(); - if (d->cachedApplicationDirPath == QString()) + if (d->cachedApplicationDirPath.isNull()) d->cachedApplicationDirPath = QFileInfo(applicationFilePath()).path(); return d->cachedApplicationDirPath; } @@ -1738,7 +1738,7 @@ QString QCoreApplication::applicationFilePath() } QCoreApplicationPrivate *d = self->d_func(); - if (d->cachedApplicationFilePath != QString()) + if (!d->cachedApplicationFilePath.isNull()) return d->cachedApplicationFilePath; #if defined( Q_WS_WIN ) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index b53e91f..b504604 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1173,8 +1173,9 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; and versatile, but may prove less memory and speed efficient than storing specific types in standard data structures. - QVariant also supports the notion of null values, where you have - a defined type with no value set. + QVariant also supports the notion of null values, where you can + have a defined type with no value set. However, note that QVariant + types can only be cast when they have had a value set. \snippet doc/src/snippets/code/src_corelib_kernel_qvariant.cpp 1 diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp new file mode 100644 index 0000000..7db3a5a --- /dev/null +++ b/src/corelib/tools/qcontiguouscache.cpp @@ -0,0 +1,435 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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$ +** +****************************************************************************/ + +#include "qcontiguouscache.h" +#include <QDebug> + +QT_BEGIN_NAMESPACE + +void QContiguousCacheData::dump() const +{ + qDebug() << "capacity:" << alloc; + qDebug() << "count:" << count; + qDebug() << "start:" << start; + qDebug() << "offset:" << offset; +} + +/*! \class QContiguousCache + \brief The QContiguousCache class is a template class that provides a contiguous cache. + \ingroup tools + \ingroup shared + \reentrant + + The QContiguousCache class provides an efficient way of caching items for + display in a user interface view. Unlike QCache, it adds a restriction + that elements within the cache are contiguous. This has the advantage + of matching how user interface views most commonly request data, as + a set of rows localized around the current scrolled position. This + restriction allows the cache to consume less memory and processor + cycles than QCache. The QContiguousCache class also can provide + an upper bound on memory usage via setCapacity(). + + The simplest way of using a contiguous cache is to use the append() + and prepend(). + +\code +MyRecord record(int row) const +{ + Q_ASSERT(row >= 0 && row < count()); + + while(row > cache.lastIndex()) + cache.append(slowFetchRecord(cache.lastIndex()+1)); + while(row < cache.firstIndex()) + cache.prepend(slowFetchRecord(cache.firstIndex()-1)); + + return cache.at(row); +} +\endcode + + If the cache is full then the item at the opposite end of the cache from + where the new item is appended or prepended will be removed. + + This usage can be further optimized by using the insert() function + in the case where the requested row is a long way from the currently cached + items. If there is a gap between where the new item is inserted and the currently + cached items then the existing cached items are first removed to retain + the contiguous nature of the cache. Hence it is important to take some care then + when using insert() in order to avoid unwanted clearing of the cache. + + The range of valid indexes for the QContiguousCache class are from + 0 to INT_MAX. Calling prepend() such that the first index would become less + than 0 or append() such that the last index would become greater + than INT_MAX can result in the indexes of the cache being invalid. + When the cache indexes are invalid it is important to call + normalizeIndexes() before calling any of containsIndex(), firstIndex(), + lastIndex(), at() or the [] operator. Calling these + functions when the cache has invalid indexes will result in undefined + behavior. The indexes can be checked by using areIndexesValid() + + In most cases the indexes will not exceed 0 to INT_MAX, and + normalizeIndexes() will not need to be used. + + See the \l{Contiguous Cache Example}{Contiguous Cache} example. +*/ + +/*! \fn QContiguousCache::QContiguousCache(int capacity) + + Constructs a cache with the given \a capacity. + + \sa setCapacity() +*/ + +/*! \fn QContiguousCache::QContiguousCache(const QContiguousCache<T> &other) + + Constructs a copy of \a other. + + This operation takes \l{constant time}, because QContiguousCache is + \l{implicitly shared}. This makes returning a QContiguousCache from a + function very fast. If a shared instance is modified, it will be + copied (copy-on-write), and that takes \l{linear time}. + + \sa operator=() +*/ + +/*! \fn QContiguousCache::~QContiguousCache() + + Destroys the cache. +*/ + +/*! \fn void QContiguousCache::detach() + + \internal +*/ + +/*! \fn bool QContiguousCache::isDetached() const + + \internal +*/ + +/*! \fn void QContiguousCache::setSharable(bool sharable) + + \internal +*/ + +/*! \fn QContiguousCache<T> &QContiguousCache::operator=(const QContiguousCache<T> &other) + + Assigns \a other to this cache and returns a reference to this cache. +*/ + +/*! \fn bool QContiguousCache::operator==(const QContiguousCache<T> &other) const + + Returns true if \a other is equal to this cache; otherwise returns false. + + Two caches are considered equal if they contain the same values at the same + indexes. This function requires the value type to implement the \c operator==(). + + \sa operator!=() +*/ + +/*! \fn bool QContiguousCache::operator!=(const QContiguousCache<T> &other) const + + Returns true if \a other is not equal to this cache; otherwise + returns false. + + Two caches are considered equal if they contain the same values at the same + indexes. This function requires the value type to implement the \c operator==(). + + \sa operator==() +*/ + +/*! \fn int QContiguousCache::capacity() const + + Returns the number of items the cache can store before it is full. + When a cache contains a number of items equal to its capacity, adding new + items will cause items farthest from the added item to be removed. + + \sa setCapacity(), size() +*/ + +/*! \fn int QContiguousCache::count() const + + \overload + + Same as size(). +*/ + +/*! \fn int QContiguousCache::size() const + + Returns the number of items contained within the cache. + + \sa capacity() +*/ + +/*! \fn bool QContiguousCache::isEmpty() const + + Returns true if no items are stored within the cache. + + \sa size(), capacity() +*/ + +/*! \fn bool QContiguousCache::isFull() const + + Returns true if the number of items stored within the cache is equal + to the capacity of the cache. + + \sa size(), capacity() +*/ + +/*! \fn int QContiguousCache::available() const + + Returns the number of items that can be added to the cache before it becomes full. + + \sa size(), capacity(), isFull() +*/ + +/*! \fn void QContiguousCache::clear() + + Removes all items from the cache. The capacity is unchanged. +*/ + +/*! \fn void QContiguousCache::setCapacity(int size) + + Sets the capacity of the cache to the given \a size. A cache can hold a + number of items equal to its capacity. When inserting, appending or prepending + items to the cache, if the cache is already full then the item farthest from + the added item will be removed. + + If the given \a size is smaller than the current count of items in the cache + then only the last \a size items from the cache will remain. + + \sa capacity(), isFull() +*/ + +/*! \fn const T &QContiguousCache::at(int i) const + + Returns the item at index position \a i in the cache. \a i must + be a valid index position in the cache (i.e, firstIndex() <= \a i <= lastIndex()). + + The indexes in the cache refer to the number of positions the item is from the + first item appended into the cache. That is to say a cache with a capacity of + 100, that has had 150 items appended will have a valid index range of + 50 to 149. This allows inserting and retrieving items into the cache based + on a theoretical infinite list + + \sa firstIndex(), lastIndex(), insert(), operator[]() +*/ + +/*! \fn T &QContiguousCache::operator[](int i) + + Returns the item at index position \a i as a modifiable reference. If + the cache does not contain an item at the given index position \a i + then it will first insert an empty item at that position. + + In most cases it is better to use either at() or insert(). + + Note that using non-const operators can cause QContiguousCache to do a deep + copy. + + \sa insert(), at() +*/ + +/*! \fn const T &QContiguousCache::operator[](int i) const + + \overload + + Same as at(\a i). +*/ + +/*! \fn void QContiguousCache::append(const T &value) + + Inserts \a value at the end of the cache. If the cache is already full + the item at the start of the cache will be removed. + + \sa prepend(), insert(), isFull() +*/ + +/*! \fn void QContiguousCache::prepend(const T &value) + + Inserts \a value at the start of the cache. If the cache is already full + the item at the end of the cache will be removed. + + \sa append(), insert(), isFull() +*/ + +/*! \fn void QContiguousCache::insert(int i, const T &value) + + Inserts the \a value at the index position \a i. If the cache already contains + an item at \a i then that value is replaced. If \a i is either one more than + lastIndex() or one less than firstIndex() it is the equivalent to an append() + or a prepend(). + + If the given index \a i is not within the current range of the cache nor adjacent + to the bounds of the cache's index range, the cache is first cleared before + inserting the item. At this point the cache will have a size of 1. It is + worthwhile taking effort to insert items in an order that starts adjacent + to the current index range for the cache. + + The range of valid indexes for the QContiguousCache class are from + 0 to INT_MAX. Inserting outside of this range has undefined behavior. + + + \sa prepend(), append(), isFull(), firstIndex(), lastIndex() +*/ + +/*! \fn bool QContiguousCache::containsIndex(int i) const + + Returns true if the cache's index range includes the given index \a i. + + \sa firstIndex(), lastIndex() +*/ + +/*! \fn int QContiguousCache::firstIndex() const + + Returns the first valid index in the cache. The index will be invalid if the + cache is empty. + + \sa capacity(), size(), lastIndex() +*/ + +/*! \fn int QContiguousCache::lastIndex() const + + Returns the last valid index in the cache. The index will be invalid if the cache is empty. + + \sa capacity(), size(), firstIndex() +*/ + + +/*! \fn T &QContiguousCache::first() + + Returns a reference to the first item in the cache. This function + assumes that the cache isn't empty. + + \sa last(), isEmpty() +*/ + +/*! \fn T &QContiguousCache::last() + + Returns a reference to the last item in the cache. This function + assumes that the cache isn't empty. + + \sa first(), isEmpty() +*/ + +/*! \fn const T& QContiguousCache::first() const + + \overload +*/ + +/*! \fn const T& QContiguousCache::last() const + + \overload +*/ + +/*! \fn void QContiguousCache::removeFirst() + + Removes the first item from the cache. This function assumes that + the cache isn't empty. + + \sa removeLast() +*/ + +/*! \fn void QContiguousCache::removeLast() + + Removes the last item from the cache. This function assumes that + the cache isn't empty. + + \sa removeFirst() +*/ + +/*! \fn T QContiguousCache::takeFirst() + + Removes the first item in the cache and returns it. This function + assumes that the cache isn't empty. + + If you don't use the return value, removeFirst() is more efficient. + + \sa takeLast(), removeFirst() +*/ + +/*! \fn T QContiguousCache::takeLast() + + Removes the last item in the cache and returns it. This function + assumes that the cache isn't empty. + + If you don't use the return value, removeLast() is more efficient. + + \sa takeFirst(), removeLast() +*/ + +/*! \fn void QContiguousCache::normalizeIndexes() + + Moves the first index and last index of the cache + such that they point to valid indexes. The function does not modify + the contents of the cache or the ordering of elements within the cache. + + It is provided so that index overflows can be corrected when using the + cache as a circular buffer. + + \code + QContiguousCache<int> cache(10); + cache.insert(INT_MAX, 1); // cache contains one value and has valid indexes, INT_MAX to INT_MAX + cache.append(2); // cache contains two values but does not have valid indexes. + cache.normalizeIndexes(); // cache has two values, 1 and 2. New first index will be in the range of 0 to capacity(). + \endcode + + \sa areIndexesValid(), append(), prepend() +*/ + +/*! \fn bool QContiguousCache::areIndexesValid() const + + Returns whether the indexes for items stored in the cache are valid. + Indexes can become invalid if items are appended after the index position + INT_MAX or prepended before the index position 0. This is only expected + to occur in very long lived circular buffer style usage of the + contiguous cache. Indexes can be made valid again by calling + normalizeIndexs(). + + \sa normalizeIndexes(), append(), prepend() +*/ + +/*! \fn void QContiguousCache::dump() const + + \internal + + Sends information about the cache's internal structure to qDebug() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h new file mode 100644 index 0000000..5cd1582 --- /dev/null +++ b/src/corelib/tools/qcontiguouscache.h @@ -0,0 +1,424 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore 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 QCONTIGUOUSCACHE_H +#define QCONTIGUOUSCACHE_H + +#include <QtCore/qatomic.h> +#include <limits.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +struct Q_CORE_EXPORT QContiguousCacheData +{ + QBasicAtomicInt ref; + int alloc; + int count; + int start; + int offset; + uint sharable : 1; + + void dump() const; +}; + +template <typename T> +struct QContiguousCacheTypedData +{ + QBasicAtomicInt ref; + int alloc; + int count; + int start; + int offset; + uint sharable : 1; + + T array[1]; +}; + +template<typename T> +class QContiguousCache { + typedef QContiguousCacheTypedData<T> Data; + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; }; +public: + explicit QContiguousCache(int capacity = 0); + QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); } + + inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(d); } + + inline void detach() { if (d->ref != 1) detach_helper(); } + inline bool isDetached() const { return d->ref == 1; } + inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } + + QContiguousCache<T> &operator=(const QContiguousCache<T> &other); + bool operator==(const QContiguousCache<T> &other) const; + inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); } + + inline int capacity() const {return d->alloc; } + inline int count() const { return d->count; } + inline int size() const { return d->count; } + + inline bool isEmpty() const { return d->count == 0; } + inline bool isFull() const { return d->count == d->alloc; } + inline int available() const { return d->alloc - d->count; } + + void clear(); + void setCapacity(int size); + + const T &at(int pos) const; + T &operator[](int i); + const T &operator[](int i) const; + + void append(const T &value); + void prepend(const T &value); + void insert(int pos, const T &value); + + inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; } + inline int firstIndex() const { return d->offset; } + inline int lastIndex() const { return d->offset + d->count - 1; } + + inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; } + inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; } + inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; } + inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; } + + void removeFirst(); + T takeFirst(); + void removeLast(); + T takeLast(); + + inline bool areIndexesValid() const + { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; } + + inline void normalizeIndexes() { d->offset = d->start; } + // debug + void dump() const { p->dump(); } +private: + void detach_helper(); + + QContiguousCacheData *malloc(int aalloc); + void free(Data *x); + int sizeOfTypedData() { + // this is more or less the same as sizeof(Data), except that it doesn't + // count the padding at the end + return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); + } +}; + +template <typename T> +void QContiguousCache<T>::detach_helper() +{ + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + + x.p = malloc(d->alloc); + x.d->ref = 1; + x.d->count = d->count; + x.d->start = d->start; + x.d->offset = d->offset; + x.d->alloc = d->alloc; + x.d->sharable = true; + + T *dest = x.d->array + x.d->start; + T *src = d->array + d->start; + int count = x.d->count; + while (count--) { + if (QTypeInfo<T>::isComplex) { + new (dest) T(*src); + } else { + *dest = *src; + } + dest++; + if (dest == x.d->array + x.d->alloc) + dest = x.d->array; + src++; + if (src == d->array + d->alloc) + src = d->array; + } + + if (!d->ref.deref()) + free(d); + d = x.d; +} + +template <typename T> +void QContiguousCache<T>::setCapacity(int asize) +{ + if (asize == d->alloc) + return; + detach(); + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + x.p = malloc(asize); + x.d->alloc = asize; + x.d->count = qMin(d->count, asize); + x.d->offset = d->offset + d->count - x.d->count; + x.d->start = x.d->offset % x.d->alloc; + T *dest = x.d->array + (x.d->start + x.d->count-1) % x.d->alloc; + T *src = d->array + (d->start + d->count-1) % d->alloc; + int count = x.d->count; + while (count--) { + if (QTypeInfo<T>::isComplex) { + new (dest) T(*src); + } else { + *dest = *src; + } + if (dest == x.d->array) + dest = x.d->array + x.d->alloc; + dest--; + if (src == d->array) + src = d->array + d->alloc; + src--; + } + /* free old */ + free(d); + d = x.d; +} + +template <typename T> +void QContiguousCache<T>::clear() +{ + if (d->ref == 1) { + if (QTypeInfo<T>::isComplex) { + int count = d->count; + T * i = d->array + d->start; + T * e = d->array + d->alloc; + while (count--) { + i->~T(); + i++; + if (i == e) + i = d->array; + } + } + d->count = d->start = d->offset = 0; + } else { + union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + x.p = malloc(d->alloc); + x.d->ref = 1; + x.d->alloc = d->alloc; + x.d->count = x.d->start = x.d->offset = 0; + x.d->sharable = true; + if (!d->ref.deref()) free(d); + d = x.d; + } +} + +template <typename T> +inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc) +{ + return static_cast<QContiguousCacheData *>(qMalloc(sizeOfTypedData() + (aalloc - 1) * sizeof(T))); +} + +template <typename T> +QContiguousCache<T>::QContiguousCache(int capacity) +{ + p = malloc(capacity); + d->ref = 1; + d->alloc = capacity; + d->count = d->start = d->offset = 0; + d->sharable = true; +} + +template <typename T> +QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &other) +{ + other.d->ref.ref(); + if (!d->ref.deref()) + free(d); + d = other.d; + if (!d->sharable) + detach_helper(); + return *this; +} + +template <typename T> +bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const +{ + if (other.d == d) + return true; + if (other.d->start != d->start + || other.d->count != d->count + || other.d->offset != d->offset + || other.d->alloc != d->alloc) + return false; + for (int i = firstIndex(); i <= lastIndex(); ++i) + if (!(at(i) == other.at(i))) + return false; + return true; +} + +template <typename T> +void QContiguousCache<T>::free(Data *x) +{ + if (QTypeInfo<T>::isComplex) { + int count = d->count; + T * i = d->array + d->start; + T * e = d->array + d->alloc; + while (count--) { + i->~T(); + i++; + if (i == e) + i = d->array; + } + } + qFree(x); +} +template <typename T> +void QContiguousCache<T>::append(const T &value) +{ + detach(); + if (QTypeInfo<T>::isComplex) { + if (d->count == d->alloc) + (d->array + (d->start+d->count) % d->alloc)->~T(); + new (d->array + (d->start+d->count) % d->alloc) T(value); + } else { + d->array[(d->start+d->count) % d->alloc] = value; + } + + if (d->count == d->alloc) { + d->start++; + d->start %= d->alloc; + d->offset++; + } else { + d->count++; + } +} + +template<typename T> +void QContiguousCache<T>::prepend(const T &value) +{ + detach(); + if (d->start) + d->start--; + else + d->start = d->alloc-1; + d->offset--; + + if (d->count != d->alloc) + d->count++; + else + if (d->count == d->alloc) + (d->array + d->start)->~T(); + + if (QTypeInfo<T>::isComplex) + new (d->array + d->start) T(value); + else + d->array[d->start] = value; +} + +template<typename T> +void QContiguousCache<T>::insert(int pos, const T &value) +{ + Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range"); + detach(); + if (containsIndex(pos)) { + if(QTypeInfo<T>::isComplex) + new (d->array + pos % d->alloc) T(value); + else + d->array[pos % d->alloc] = value; + } else if (pos == d->offset-1) + prepend(value); + else if (pos == d->offset+d->count) + append(value); + else { + // we don't leave gaps. + clear(); + d->offset = pos; + d->start = pos % d->alloc; + d->count = 1; + if (QTypeInfo<T>::isComplex) + new (d->array + d->start) T(value); + else + d->array[d->start] = value; + } +} + +template <typename T> +inline const T &QContiguousCache<T>::at(int pos) const +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; } +template <typename T> +inline const T &QContiguousCache<T>::operator[](int pos) const +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; } + +template <typename T> +inline T &QContiguousCache<T>::operator[](int pos) +{ + detach(); + if (!containsIndex(pos)) + insert(pos, T()); + return d->array[pos % d->alloc]; +} + +template <typename T> +inline void QContiguousCache<T>::removeFirst() +{ + Q_ASSERT(d->count > 0); + detach(); + d->count--; + if (QTypeInfo<T>::isComplex) + (d->array + d->start)->~T(); + d->start = (d->start + 1) % d->alloc; + d->offset++; +} + +template <typename T> +inline void QContiguousCache<T>::removeLast() +{ + Q_ASSERT(d->count > 0); + detach(); + d->count--; + if (QTypeInfo<T>::isComplex) + (d->array + (d->start + d->count) % d->alloc)->~T(); +} + +template <typename T> +inline T QContiguousCache<T>::takeFirst() +{ T t = first(); removeFirst(); return t; } + +template <typename T> +inline T QContiguousCache<T>::takeLast() +{ T t = last(); removeLast(); return t; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index 2979a09..3a03558 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -225,7 +225,9 @@ void QTimeLinePrivate::setCurrentTime(int msecs) valueForTime() and emitting valueChanged(). By default, valueForTime() applies an interpolation algorithm to generate these value. You can choose from a set of predefined timeline algorithms by calling - setCurveShape(). By default, QTimeLine uses the EaseInOut curve shape, + setCurveShape(). + + Note that by default, QTimeLine uses the EaseInOut curve shape, which provides a value that grows slowly, then grows steadily, and finally grows slowly. For a custom timeline, you can reimplement valueForTime(), in which case QTimeLine's curveShape property is ignored. diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 1f047b8..7bdcba0 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -82,19 +82,9 @@ struct Q_CORE_EXPORT QVectorData }; template <typename T> -struct QVectorTypedData -{ - QBasicAtomicInt ref; - int alloc; - int size; -#if defined(QT_ARCH_SPARC) && defined(Q_CC_GNU) && defined(__LP64__) && defined(QT_BOOTSTRAPPED) - // workaround for bug in gcc 3.4.2 - uint sharable; - uint capacity; -#else - uint sharable : 1; - uint capacity : 1; -#endif +struct QVectorTypedData : private QVectorData +{ // private inheritance as we must not access QVectorData member thought QVectorTypedData + // as this would break strict aliasing rules. (in the case of shared_null) T array[1]; }; @@ -104,14 +94,14 @@ template <typename T> class QVector { typedef QVectorTypedData<T> Data; - union { QVectorData *p; QVectorTypedData<T> *d; }; + union { QVectorData *d; Data *p; }; public: - inline QVector() : p(&QVectorData::shared_null) { d->ref.ref(); } + inline QVector() : d(&QVectorData::shared_null) { d->ref.ref(); } explicit QVector(int size); QVector(int size, const T &t); inline QVector(const QVector<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); } - inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(d); } + inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(p); } QVector<T> &operator=(const QVector<T> &v); bool operator==(const QVector<T> &v) const; inline bool operator!=(const QVector<T> &v) const { return !(*this == v); } @@ -130,9 +120,9 @@ public: inline bool isDetached() const { return d->ref == 1; } inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } - inline T *data() { detach(); return d->array; } - inline const T *data() const { return d->array; } - inline const T *constData() const { return d->array; } + inline T *data() { detach(); return p->array; } + inline const T *data() const { return p->array; } + inline const T *constData() const { return p->array; } void clear(); const T &at(int i) const; @@ -225,12 +215,12 @@ public: typedef T* iterator; typedef const T* const_iterator; #endif - inline iterator begin() { detach(); return d->array; } - inline const_iterator begin() const { return d->array; } - inline const_iterator constBegin() const { return d->array; } - inline iterator end() { detach(); return d->array + d->size; } - inline const_iterator end() const { return d->array + d->size; } - inline const_iterator constEnd() const { return d->array + d->size; } + inline iterator begin() { detach(); return p->array; } + inline const_iterator begin() const { return p->array; } + inline const_iterator constBegin() const { return p->array; } + inline iterator end() { detach(); return p->array + d->size; } + inline const_iterator end() const { return p->array + d->size; } + inline const_iterator constEnd() const { return p->array + d->size; } iterator insert(iterator before, int n, const T &x); inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); } iterator erase(iterator begin, iterator end); @@ -327,11 +317,11 @@ inline void QVector<T>::clear() template <typename T> inline const T &QVector<T>::at(int i) const { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range"); - return d->array[i]; } + return p->array[i]; } template <typename T> inline const T &QVector<T>::operator[](int i) const { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range"); - return d->array[i]; } + return p->array[i]; } template <typename T> inline T &QVector<T>::operator[](int i) { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range"); @@ -369,7 +359,7 @@ QVector<T> &QVector<T>::operator=(const QVector<T> &v) { v.d->ref.ref(); if (!d->ref.deref()) - free(d); + free(p); d = v.d; if (!d->sharable) detach_helper(); @@ -385,31 +375,31 @@ inline QVectorData *QVector<T>::malloc(int aalloc) template <typename T> QVector<T>::QVector(int asize) { - p = malloc(asize); + d = malloc(asize); d->ref = 1; d->alloc = d->size = asize; d->sharable = true; d->capacity = false; if (QTypeInfo<T>::isComplex) { - T* b = d->array; - T* i = d->array + d->size; + T* b = p->array; + T* i = p->array + d->size; while (i != b) new (--i) T; } else { - qMemSet(d->array, 0, asize * sizeof(T)); + qMemSet(p->array, 0, asize * sizeof(T)); } } template <typename T> QVector<T>::QVector(int asize, const T &t) { - p = malloc(asize); + d = malloc(asize); d->ref = 1; d->alloc = d->size = asize; d->sharable = true; d->capacity = false; - T* i = d->array + d->size; - while (i != d->array) + T* i = p->array + d->size; + while (i != p->array) new (--i) T(t); } @@ -418,7 +408,7 @@ void QVector<T>::free(Data *x) { if (QTypeInfo<T>::isComplex) { T* b = x->array; - T* i = b + x->size; + T* i = b + reinterpret_cast<QVectorData *>(x)->size; while (i-- != b) i->~T(); } @@ -429,13 +419,13 @@ template <typename T> void QVector<T>::realloc(int asize, int aalloc) { T *j, *i, *b; - union { QVectorData *p; Data *d; } x; + union { QVectorData *d; Data *p; } x; x.d = d; if (QTypeInfo<T>::isComplex && aalloc == d->alloc && d->ref == 1) { // pure resize - i = d->array + d->size; - j = d->array + asize; + i = p->array + d->size; + j = p->array + asize; if (i > j) { while (i-- != j) i->~T(); @@ -450,22 +440,22 @@ void QVector<T>::realloc(int asize, int aalloc) if (aalloc != d->alloc || d->ref != 1) { // (re)allocate memory if (QTypeInfo<T>::isStatic) { - x.p = malloc(aalloc); + x.d = malloc(aalloc); } else if (d->ref != 1) { - x.p = QVectorData::malloc(sizeOfTypedData(), aalloc, sizeof(T), p); + x.d = QVectorData::malloc(sizeOfTypedData(), aalloc, sizeof(T), d); } else { if (QTypeInfo<T>::isComplex) { // call the destructor on all objects that need to be // destroyed when shrinking if (asize < d->size) { - j = d->array + asize; - i = d->array + d->size; + j = p->array + asize; + i = p->array + d->size; while (i-- != j) i->~T(); - i = d->array + asize; + i = p->array + asize; } } - x.p = p = static_cast<QVectorData *>(qRealloc(p, sizeOfTypedData() + (aalloc - 1) * sizeof(T))); + x.d = d = static_cast<QVectorData *>(qRealloc(d, sizeOfTypedData() + (aalloc - 1) * sizeof(T))); } x.d->ref = 1; x.d->sharable = true; @@ -474,31 +464,31 @@ void QVector<T>::realloc(int asize, int aalloc) } if (QTypeInfo<T>::isComplex) { if (asize < d->size) { - j = d->array + asize; - i = x.d->array + asize; + j = p->array + asize; + i = x.p->array + asize; } else { // construct all new objects when growing - i = x.d->array + asize; - j = x.d->array + d->size; + i = x.p->array + asize; + j = x.p->array + d->size; while (i != j) new (--i) T; - j = d->array + d->size; + j = p->array + d->size; } if (i != j) { // copy objects from the old array into the new array - b = x.d->array; + b = x.p->array; while (i != b) new (--i) T(*--j); } } else if (asize > d->size) { // initialize newly allocated memory to 0 - qMemSet(x.d->array + d->size, 0, (asize - d->size) * sizeof(T)); + qMemSet(x.p->array + d->size, 0, (asize - d->size) * sizeof(T)); } x.d->size = asize; x.d->alloc = aalloc; if (d != x.d) { if (!d->ref.deref()) - free(d); + free(p); d = x.d; } } @@ -506,15 +496,15 @@ void QVector<T>::realloc(int asize, int aalloc) template<typename T> Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const { - if (i < 0 || i >= p->size) { + if (i < 0 || i >= d->size) { return T(); } - return d->array[i]; + return p->array[i]; } template<typename T> Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const { - return ((i < 0 || i >= p->size) ? defaultValue : d->array[i]); + return ((i < 0 || i >= d->size) ? defaultValue : p->array[i]); } template <typename T> @@ -525,14 +515,14 @@ void QVector<T>::append(const T &t) realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + 1, sizeof(T), QTypeInfo<T>::isStatic)); if (QTypeInfo<T>::isComplex) - new (d->array + d->size) T(copy); + new (p->array + d->size) T(copy); else - d->array[d->size] = copy; + p->array[d->size] = copy; } else { if (QTypeInfo<T>::isComplex) - new (d->array + d->size) T(t); + new (p->array + d->size) T(t); else - d->array[d->size] = t; + p->array[d->size] = t; } ++d->size; } @@ -540,27 +530,27 @@ void QVector<T>::append(const T &t) template <typename T> Q_TYPENAME QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t) { - int offset = before - d->array; + int offset = before - p->array; if (n != 0) { const T copy(t); if (d->ref != 1 || d->size + n > d->alloc) realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + n, sizeof(T), QTypeInfo<T>::isStatic)); if (QTypeInfo<T>::isStatic) { - T *b = d->array + d->size; - T *i = d->array + d->size + n; + T *b = p->array + d->size; + T *i = p->array + d->size + n; while (i != b) new (--i) T; - i = d->array + d->size; + i = p->array + d->size; T *j = i + n; - b = d->array + offset; + b = p->array + offset; while (i != b) *--j = *--i; i = b+n; while (i != b) *--i = copy; } else { - T *b = d->array + offset; + T *b = p->array + offset; T *i = b + n; memmove(i, b, (d->size - offset) * sizeof(T)); while (i != b) @@ -568,29 +558,29 @@ Q_TYPENAME QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, } d->size += n; } - return d->array + offset; + return p->array + offset; } template <typename T> Q_TYPENAME QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend) { - int f = abegin - d->array; - int l = aend - d->array; + int f = abegin - p->array; + int l = aend - p->array; int n = l - f; detach(); if (QTypeInfo<T>::isComplex) { - qCopy(d->array+l, d->array+d->size, d->array+f); - T *i = d->array+d->size; - T* b = d->array+d->size-n; + qCopy(p->array+l, p->array+d->size, p->array+f); + T *i = p->array+d->size; + T* b = p->array+d->size-n; while (i != b) { --i; i->~T(); } } else { - memmove(d->array + f, d->array + l, (d->size-l)*sizeof(T)); + memmove(p->array + f, p->array + l, (d->size-l)*sizeof(T)); } d->size -= n; - return d->array + f; + return p->array + f; } template <typename T> @@ -600,9 +590,9 @@ bool QVector<T>::operator==(const QVector<T> &v) const return false; if (d == v.d) return true; - T* b = d->array; + T* b = p->array; T* i = b + d->size; - T* j = v.d->array + d->size; + T* j = v.p->array + d->size; while (i != b) if (!(*--i == *--j)) return false; @@ -615,8 +605,8 @@ QVector<T> &QVector<T>::fill(const T &from, int asize) const T copy(from); resize(asize < 0 ? d->size : asize); if (d->size) { - T *i = d->array + d->size; - T *b = d->array; + T *i = p->array + d->size; + T *b = p->array; while (i != b) *--i = copy; } @@ -629,9 +619,9 @@ QVector<T> &QVector<T>::operator+=(const QVector &l) int newSize = d->size + l.d->size; realloc(d->size, newSize); - T *w = d->array + newSize; - T *i = l.d->array + l.d->size; - T *b = l.d->array; + T *w = p->array + newSize; + T *i = l.p->array + l.d->size; + T *b = l.p->array; while (i != b) { if (QTypeInfo<T>::isComplex) new (--w) T(*--i); @@ -648,11 +638,11 @@ int QVector<T>::indexOf(const T &t, int from) const if (from < 0) from = qMax(from + d->size, 0); if (from < d->size) { - T* n = d->array + from - 1; - T* e = d->array + d->size; + T* n = p->array + from - 1; + T* e = p->array + d->size; while (++n != e) if (*n == t) - return n - d->array; + return n - p->array; } return -1; } @@ -665,8 +655,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const else if (from >= d->size) from = d->size-1; if (from >= 0) { - T* b = d->array; - T* n = d->array + from + 1; + T* b = p->array; + T* n = p->array + from + 1; while (n != b) { if (*--n == t) return n - b; @@ -678,8 +668,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const template <typename T> bool QVector<T>::contains(const T &t) const { - T* b = d->array; - T* i = d->array + d->size; + T* b = p->array; + T* i = p->array + d->size; while (i != b) if (*--i == t) return true; @@ -690,8 +680,8 @@ template <typename T> int QVector<T>::count(const T &t) const { int c = 0; - T* b = d->array; - T* i = d->array + d->size; + T* b = p->array; + T* i = p->array + d->size; while (i != b) if (*--i == t) ++c; diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index e5bf7e4..aaf3f21 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -19,6 +19,7 @@ HEADERS += \ tools/qlocale_p.h \ tools/qlocale_data_p.h \ tools/qmap.h \ + tools/qcontiguouscache.h \ tools/qpodlist_p.h \ tools/qpoint.h \ tools/qqueue.h \ @@ -53,6 +54,7 @@ SOURCES += \ tools/qlocale.cpp \ tools/qpoint.cpp \ tools/qmap.cpp \ + tools/qcontiguouscache.cpp \ tools/qrect.cpp \ tools/qregexp.cpp \ tools/qshareddata.cpp \ diff --git a/src/gui/dialogs/qsidebar.cpp b/src/gui/dialogs/qsidebar.cpp index 26108d7..000a06b 100644 --- a/src/gui/dialogs/qsidebar.cpp +++ b/src/gui/dialogs/qsidebar.cpp @@ -249,9 +249,9 @@ void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move) continue; for (int j = 0; move && j < rowCount(); ++j) { #if defined(Q_OS_WIN) - if (index(j, 0).data(UrlRole).toUrl().toLocalFile().toLower() == url.toLocalFile().toLower()) { + if (QDir::cleanPath(index(j, 0).data(UrlRole).toUrl().toLocalFile()).toLower() == QDir::cleanPath(url.toLocalFile()).toLower()) { #else - if (index(j, 0).data(UrlRole) == url) { + if (QDir::cleanPath(index(j, 0).data(UrlRole).toUrl().toLocalFile()) == QDir::cleanPath(url.toLocalFile())) { #endif removeRow(j); if (j <= row) diff --git a/src/gui/dialogs/qwizard.cpp b/src/gui/dialogs/qwizard.cpp index 6f2ab0a..2c29ebf 100644 --- a/src/gui/dialogs/qwizard.cpp +++ b/src/gui/dialogs/qwizard.cpp @@ -1241,8 +1241,10 @@ void QWizardPrivate::updateMinMaxSizes(const QWizardLayoutInfo &info) #endif QSize minimumSize = mainLayout->totalMinimumSize() + QSize(0, extraHeight); QSize maximumSize; + bool skipMaxSize = false; #if defined(Q_WS_WIN) - if (QSysInfo::WindowsVersion > QSysInfo::WV_Me) // ### See Tasks 164078 and 161660 + if (QSysInfo::WindowsVersion <= QSysInfo::WV_Me) // ### See Tasks 164078 and 161660 + skipMaxSize = true; #endif maximumSize = mainLayout->totalMaximumSize(); if (info.header && headerWidget->maximumWidth() != QWIDGETSIZE_MAX) { @@ -1263,11 +1265,13 @@ void QWizardPrivate::updateMinMaxSizes(const QWizardLayoutInfo &info) } if (q->maximumWidth() == maximumWidth) { maximumWidth = maximumSize.width(); - q->setMaximumWidth(maximumWidth); + if (!skipMaxSize) + q->setMaximumWidth(maximumWidth); } if (q->maximumHeight() == maximumHeight) { maximumHeight = maximumSize.height(); - q->setMaximumHeight(maximumHeight); + if (!skipMaxSize) + q->setMaximumHeight(maximumHeight); } } diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index e2b8115..747d510 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -274,6 +274,15 @@ this flag, the child will be stacked behind it. This flag is useful for drop shadow effects and for decoration objects that follow the parent item's geometry without drawing on top of it. + + \value ItemUsesExtendedStyleOption The item makes use of either + QStyleOptionGraphicsItem::exposedRect or QStyleOptionGraphicsItem::matrix. + By default, the exposedRect is initialized to the item's boundingRect and + the matrix is untransformed. Enable this flag for more fine-grained values. + Note that QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag + and is always initialized to 1. + Use QStyleOptionGraphicsItem::levelOfDetailFromTransform for a more + fine-grained value. */ /*! @@ -917,6 +926,53 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec } } +void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, + const QRegion &exposedRegion, bool allItems) const +{ + Q_ASSERT(option); + Q_Q(const QGraphicsItem); + + // Initialize standard QStyleOption values. + const QRectF brect = q->boundingRect(); + option->state = QStyle::State_None; + option->rect = brect.toRect(); + option->levelOfDetail = 1; + option->exposedRect = brect; + if (selected) + option->state |= QStyle::State_Selected; + if (enabled) + option->state |= QStyle::State_Enabled; + if (q->hasFocus()) + option->state |= QStyle::State_HasFocus; + if (scene) { + if (scene->d_func()->hoverItems.contains(q_ptr)) + option->state |= QStyle::State_MouseOver; + if (q == scene->mouseGrabberItem()) + option->state |= QStyle::State_Sunken; + } + + if (!(flags & QGraphicsItem::ItemUsesExtendedStyleOption)) + return; + + // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect). + + const QTransform itemToViewportTransform = q->deviceTransform(worldTransform); + option->matrix = itemToViewportTransform.toAffine(); //### discards perspective + + if (!allItems) { + // Determine the item's exposed area + option->exposedRect = QRectF(); + const QTransform reverseMap = itemToViewportTransform.inverted(); + const QVector<QRect> exposedRects(exposedRegion.rects()); + for (int i = 0; i < exposedRects.size(); ++i) { + option->exposedRect |= reverseMap.mapRect(exposedRects.at(i)); + if (option->exposedRect.contains(brect)) + break; + } + option->exposedRect &= brect; + } +} + /*! \internal @@ -925,6 +981,7 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec void QGraphicsItemCache::purge() { QPixmapCache::remove(key); + key = QPixmapCache::Key(); QMutableMapIterator<QPaintDevice *, DeviceData> it(deviceData); while (it.hasNext()) { DeviceData &data = it.next().value(); @@ -1373,12 +1430,6 @@ void QGraphicsItem::setCacheMode(CacheMode mode, const QSize &logicalCacheSize) cache->purge(); if (mode == ItemCoordinateCache) { - if (cache->key.isEmpty()) { - // Generate new simple pixmap cache key. - QString tmp; - tmp.sprintf("qgv-%p", this); - cache->key = tmp; - } if (lastMode == mode && cache->fixedSize == logicalCacheSize) noVisualChange = true; cache->fixedSize = logicalCacheSize; @@ -2646,6 +2697,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; + // Find the topmost item that ignores view transformations. const QGraphicsItem *untransformedAncestor = this; QList<const QGraphicsItem *> parents; @@ -3695,7 +3750,7 @@ void QGraphicsItem::setBoundingRegionGranularity(qreal granularity) All painting is done in local coordinates. - \sa setCacheMode(), QPen::width(), {Item Coordinates} + \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption */ /*! @@ -4173,7 +4228,7 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) && (d->cacheMode == ItemCoordinateCache && !c->fixedSize.isValid()); if (scrollCache) { QPixmap pix; - if (QPixmapCache::find(c->key, pix)) { + if (QPixmapCache::find(c->key, &pix)) { // Adjust with 2 pixel margin. Notice the loss of precision // when converting to QRect. int adjust = 2; @@ -4182,7 +4237,7 @@ void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect) _q_scrollPixmap(&pix, irect, dx, dy); - QPixmapCache::insert(c->key, pix); + QPixmapCache::replace(c->key, pix); // Translate the existing expose. foreach (QRectF exposedRect, c->exposed) @@ -7736,9 +7791,7 @@ void QGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsIte painter->setRenderHint(QPainter::SmoothPixmapTransform, (d->transformationMode == Qt::SmoothTransformation)); - QRectF exposed = option->exposedRect.adjusted(-1, -1, 1, 1); - exposed &= QRectF(d->offset.x(), d->offset.y(), d->pixmap.width(), d->pixmap.height()); - painter->drawPixmap(exposed, d->pixmap, exposed.translated(-d->offset)); + painter->drawPixmap(d->offset, d->pixmap); if (option->state & QStyle::State_Selected) qt_graphicsItem_highlightSelected(this, painter, option); @@ -7904,6 +7957,7 @@ QGraphicsTextItem::QGraphicsTextItem(const QString &text, QGraphicsItem *parent setPlainText(text); setAcceptDrops(true); setAcceptHoverEvents(true); + setFlags(ItemUsesExtendedStyleOption); } /*! @@ -7923,6 +7977,7 @@ QGraphicsTextItem::QGraphicsTextItem(QGraphicsItem *parent dd->qq = this; setAcceptDrops(true); setAcceptHoverEvents(true); + setFlag(ItemUsesExtendedStyleOption); } /*! @@ -9268,6 +9323,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) case QGraphicsItem::ItemStacksBehindParent: str = "ItemStacksBehindParent"; break; + case QGraphicsItem::ItemUsesExtendedStyleOption: + str = "ItemUsesExtendedStyleOption"; + break; } debug << str; return debug; diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 37d8f78..e5779f7 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -94,7 +94,9 @@ public: ItemIgnoresTransformations = 0x20, ItemIgnoresParentOpacity = 0x40, ItemDoesntPropagateOpacityToChildren = 0x80, - ItemStacksBehindParent = 0x100 + ItemStacksBehindParent = 0x100, + ItemUsesExtendedStyleOption = 0x200 + // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag. }; Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 1d3a316..b6daa85 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -55,6 +55,7 @@ #include "qgraphicsitem.h" #include "qset.h" +#include "qpixmapcache.h" #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW @@ -70,13 +71,14 @@ public: // ItemCoordinateCache only QRect boundingRect; QSize fixedSize; - QString key; + QPixmapCache::Key key; // DeviceCoordinateCache only struct DeviceData { + DeviceData() {} QTransform lastTransform; QPoint cacheIndent; - QString key; + QPixmapCache::Key key; }; QMap<QPaintDevice *, DeviceData> deviceData; @@ -133,7 +135,6 @@ public: ancestorFlags(0), cacheMode(0), hasBoundingRegionGranularity(0), - flags(0), hasOpacity(0), hasEffectiveOpacity(0), isWidget(0), @@ -143,8 +144,10 @@ public: dirtyClipPath(1), emptyClipPath(0), inSetPosHelper(0), + flags(0), allChildrenCombineOpacity(1), acceptTouchEvents(0), + acceptedTouchBeginEvent(0), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -180,6 +183,8 @@ public: void removeChild(QGraphicsItem *child); void setParentItemHelper(QGraphicsItem *parent, bool deleting); void childrenBoundingRectHelper(QTransform *x, QRectF *rect); + void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, + const QRegion &exposedRegion, bool allItems = false) const; virtual void resolveFont(uint inheritedMask) { @@ -300,7 +305,7 @@ public: int depth; QSet<int> gestures; - // Packed 32 bytes + // Packed 32 bits quint32 acceptedMouseButtons : 5; quint32 visible : 1; quint32 explicitlyHidden : 1; @@ -317,9 +322,6 @@ public: quint32 ancestorFlags : 3; quint32 cacheMode : 2; quint32 hasBoundingRegionGranularity : 1; - quint32 flags : 9; - - // New 32 bytes quint32 hasOpacity : 1; quint32 hasEffectiveOpacity : 1; quint32 isWidget : 1; @@ -329,9 +331,13 @@ public: quint32 dirtyClipPath : 1; quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; + + // New 32 bits + quint32 flags : 10; quint32 allChildrenCombineOpacity : 1; quint32 acceptTouchEvents : 1; quint32 acceptedTouchBeginEvent : 1; + quint32 padding : 19; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 3d4bb5c..4d0d991 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1330,7 +1330,8 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou // check if the item we are sending to are disabled (before we send the event) bool disabled = !item->isEnabled(); bool isWindow = item->isWindow(); - if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick && item != lastMouseGrabberItem) { + if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick + && item != lastMouseGrabberItem && lastMouseGrabberItem) { // If this item is different from the item that received the last // mouse event, and mouseEvent is a doubleclick event, then the // event is converted to a press. Known limitation: @@ -2248,8 +2249,6 @@ void QGraphicsScene::setSceneRect(const QRectF &rect) void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source, Qt::AspectRatioMode aspectRatioMode) { - Q_D(QGraphicsScene); - // Default source rect = scene rect QRectF sourceRect = source; if (sourceRect.isNull()) @@ -2306,41 +2305,8 @@ void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRect // Generate the style options QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems]; - for (int i = 0; i < numItems; ++i) { - QGraphicsItem *item = itemArray[i]; - - QStyleOptionGraphicsItem option; - option.state = QStyle::State_None; - option.rect = item->boundingRect().toRect(); - if (item->isSelected()) - option.state |= QStyle::State_Selected; - if (item->isEnabled()) - option.state |= QStyle::State_Enabled; - if (item->hasFocus()) - option.state |= QStyle::State_HasFocus; - if (d->hoverItems.contains(item)) - option.state |= QStyle::State_MouseOver; - if (item == mouseGrabberItem()) - option.state |= QStyle::State_Sunken; - - // Calculate a simple level-of-detail metric. - // ### almost identical code in QGraphicsView::paintEvent() - // and QGraphicsView::render() - consider refactoring - QTransform itemToDeviceTransform; - if (item->d_ptr->itemIsUntransformable()) { - itemToDeviceTransform = item->deviceTransform(painterTransform); - } else { - itemToDeviceTransform = item->sceneTransform() * painterTransform; - } - - option.levelOfDetail = qSqrt(itemToDeviceTransform.map(v1).length() * itemToDeviceTransform.map(v2).length()); - option.matrix = itemToDeviceTransform.toAffine(); //### discards perspective - - option.exposedRect = item->boundingRect(); - option.exposedRect &= itemToDeviceTransform.inverted().mapRect(targetRect); - - styleOptionArray[i] = option; - } + for (int i = 0; i < numItems; ++i) + itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect()); // Render the scene. drawBackground(painter, sourceRect); @@ -4824,8 +4790,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte return; // Fetch the off-screen transparent buffer and exposed area info. - QString pixmapKey; + QPixmapCache::Key pixmapKey; QPixmap pix; + bool pixmapFound; QGraphicsItemCache *itemCache = itemd->extraItemCache(); if (cacheMode == QGraphicsItem::ItemCoordinateCache) { if (itemCache->boundingRect != brect.toRect()) { @@ -4835,17 +4802,14 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } pixmapKey = itemCache->key; } else { - if ((pixmapKey = itemCache->deviceData.value(widget).key).isEmpty()) { - pixmapKey.sprintf("qgv-%p-%p", item, widget); - QGraphicsItemCache::DeviceData data; - data.key = pixmapKey; - itemCache->deviceData.insert(widget, data); - } + pixmapKey = itemCache->deviceData.value(widget).key; } // Find pixmap in cache. if (!itemCache->allExposed) - QPixmapCache::find(pixmapKey, pix); + pixmapFound = QPixmapCache::find(pixmapKey, &pix); + else + pixmapFound = false; // Render using item coordinate cache mode. if (cacheMode == QGraphicsItem::ItemCoordinateCache) { @@ -4898,8 +4862,12 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(), &cacheOption, painterStateProtection); - // Reinsert this pixmap into the cache. - QPixmapCache::insert(pixmapKey, pix); + if (!pixmapFound) { + // insert this pixmap into the cache. + itemCache->key = QPixmapCache::insert(pix); + } else { + QPixmapCache::replace(pixmapKey, pix); + } // Reset expose data. itemCache->allExposed = false; @@ -5066,8 +5034,13 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte } if (pixModified) { - // Reinsert this pixmap into the cache - QPixmapCache::insert(pixmapKey, pix); + if (!pixmapFound) { + // Insert this pixmap into the cache. + deviceData->key = QPixmapCache::insert(pix); + } else { + //otherwise we replace the pixmap in the cache + QPixmapCache::replace(pixmapKey, pix); + } } // Redraw the exposed area using an untransformed painter. This @@ -5180,11 +5153,7 @@ void QGraphicsScene::drawItems(QPainter *painter, // optimization, but it's hit very rarely. for (int i = clippers.size() - 1; i >= 0; --i) { QGraphicsItem *clipper = clippers[i]; - if (clipper->d_ptr->itemIsUntransformable()) { - painter->setWorldTransform(clipper->deviceTransform(viewTransform), false); - } else { - painter->setWorldTransform(clipper->sceneTransform() * viewTransform, false); - } + painter->setWorldTransform(clipper->deviceTransform(viewTransform), false); childClippers.append(clipper); painter->save(); @@ -5195,12 +5164,8 @@ void QGraphicsScene::drawItems(QPainter *painter, } // Set up the painter transform - if (item->d_ptr->itemIsUntransformable()) { - painter->setWorldTransform(item->deviceTransform(viewTransform), false); - } else { - painter->setWorldTransform(item->sceneTransform() * viewTransform, false); - } - + painter->setWorldTransform(item->deviceTransform(viewTransform), false); + // Save painter bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape)); if (saveState) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 2d2113c..b75619c 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1153,73 +1153,6 @@ QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedReg return itemsInArea(exposedPath, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder); } -void QGraphicsViewPrivate::generateStyleOptions(const QList<QGraphicsItem *> &itemList, - QGraphicsItem **itemArray, - QStyleOptionGraphicsItem *styleOptionArray, - const QTransform &worldTransform, - bool allItems, - const QRegion &exposedRegion) const -{ - // Two unit vectors. - QLineF v1(0, 0, 1, 0); - QLineF v2(0, 0, 0, 1); - QTransform itemToViewportTransform; - QRectF brect; - QTransform reverseMap; - - for (int i = 0; i < itemList.size(); ++i) { - QGraphicsItem *item = itemArray[i] = itemList[i]; - - QStyleOptionGraphicsItem &option = styleOptionArray[i]; - brect = item->boundingRect(); - option.state = QStyle::State_None; - option.rect = brect.toRect(); - option.exposedRect = QRectF(); - if (item->d_ptr->selected) - option.state |= QStyle::State_Selected; - if (item->d_ptr->enabled) - option.state |= QStyle::State_Enabled; - if (item->hasFocus()) - option.state |= QStyle::State_HasFocus; - if (scene->d_func()->hoverItems.contains(item)) - option.state |= QStyle::State_MouseOver; - if (item == scene->mouseGrabberItem()) - option.state |= QStyle::State_Sunken; - - // Calculate a simple level-of-detail metric. - // ### almost identical code in QGraphicsScene::render() - // and QGraphicsView::render() - consider refactoring - if (item->d_ptr->itemIsUntransformable()) { - itemToViewportTransform = item->deviceTransform(worldTransform); - } else { - itemToViewportTransform = item->sceneTransform() * worldTransform; - } - - if (itemToViewportTransform.type() <= QTransform::TxTranslate) { - // Translation and rotation only? The LOD is 1. - option.levelOfDetail = 1; - } else { - // LOD is the transformed area of a 1x1 rectangle. - option.levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length()); - } - option.matrix = itemToViewportTransform.toAffine(); //### discards perspective - - if (!allItems) { - // Determine the item's exposed area - reverseMap = itemToViewportTransform.inverted(); - foreach (const QRect &rect, exposedRegion.rects()) { - option.exposedRect |= reverseMap.mapRect(QRectF(rect.adjusted(-1, -1, 1, 1))); - if (option.exposedRect.contains(brect)) - break; - } - option.exposedRect &= brect; - } else { - // The whole item is exposed - option.exposedRect = brect; - } - } -} - /*! Constructs a QGraphicsView. \a parent is passed to QWidget's constructor. */ @@ -2176,45 +2109,10 @@ void QGraphicsView::render(QPainter *painter, const QRectF &target, const QRect .scale(xratio, yratio) .translate(-sourceRect.left(), -sourceRect.top()); - // Two unit vectors. - QLineF v1(0, 0, 1, 0); - QLineF v2(0, 0, 0, 1); - // Generate the style options QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems); - QStyleOptionGraphicsItem* option = styleOptionArray; - for (int i = 0; i < numItems; ++i, ++option) { - QGraphicsItem *item = itemArray[i]; - - option->state = QStyle::State_None; - option->rect = item->boundingRect().toRect(); - if (item->isSelected()) - option->state |= QStyle::State_Selected; - if (item->isEnabled()) - option->state |= QStyle::State_Enabled; - if (item->hasFocus()) - option->state |= QStyle::State_HasFocus; - if (d->scene->d_func()->hoverItems.contains(item)) - option->state |= QStyle::State_MouseOver; - if (item == d->scene->mouseGrabberItem()) - option->state |= QStyle::State_Sunken; - - // Calculate a simple level-of-detail metric. - // ### almost identical code in QGraphicsScene::render() - // and QGraphicsView::paintEvent() - consider refactoring - QTransform itemToViewportTransform; - if (item->d_ptr->itemIsUntransformable()) { - itemToViewportTransform = item->deviceTransform(painterMatrix); - } else { - itemToViewportTransform = item->sceneTransform() * painterMatrix; - } - - option->levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length()); - option->matrix = itemToViewportTransform.toAffine(); - - option->exposedRect = item->boundingRect(); - option->exposedRect &= itemToViewportTransform.inverted().mapRect(targetRect); - } + for (int i = 0; i < numItems; ++i) + itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterMatrix, targetRect.toRect()); painter->save(); @@ -3613,15 +3511,17 @@ void QGraphicsView::paintEvent(QPaintEvent *event) int backgroundTime = stopWatch.elapsed() - exposedTime; #endif - // Generate the style options - QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()]; - QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(itemList.size()); - - d->generateStyleOptions(itemList, itemArray, styleOptionArray, viewTransform, - allItems, exposedRegion); - - // Items - drawItems(&painter, itemList.size(), itemArray, styleOptionArray); + if (!itemList.isEmpty()) { + // Generate the style options. + const int numItems = itemList.size(); + QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid. + QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems); + for (int i = 0; i < numItems; ++i) + itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, exposedRegion, allItems); + // Draw the items. + drawItems(&painter, numItems, itemArray, styleOptionArray); + d->freeStyleOptionsArray(styleOptionArray); + } #ifdef QGRAPHICSVIEW_DEBUG int itemsTime = stopWatch.elapsed() - exposedTime - backgroundTime; @@ -3630,9 +3530,6 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // Foreground drawForeground(&painter, exposedSceneRect); - delete [] itemArray; - d->freeStyleOptionsArray(styleOptionArray); - #ifdef QGRAPHICSVIEW_DEBUG int foregroundTime = stopWatch.elapsed() - exposedTime - backgroundTime - itemsTime; #endif diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp index 8ced47a..a435758 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.cpp +++ b/src/gui/graphicsview/qgraphicswidget_p.cpp @@ -76,6 +76,7 @@ void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFl resolveLayoutDirection(); q->unsetWindowFrameMargins(); + q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); } qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const { diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index ca52974..bf348af 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -22,6 +22,7 @@ HEADERS += \ image/qpixmap.h \ image/qpixmap_raster_p.h \ image/qpixmapcache.h \ + image/qpixmapcache_p.h \ image/qpixmapdata_p.h \ image/qpixmapdatafactory_p.h \ image/qpixmapfilter_p.h diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 4916489..810ce65 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -40,13 +40,9 @@ ****************************************************************************/ #include "qpixmapcache.h" -#include "qcache.h" #include "qobject.h" #include "qdebug.h" - -#include "qpaintengine.h" -#include <private/qimage_p.h> -#include <private/qpixmap_raster_p.h> +#include "qpixmapcache_p.h" QT_BEGIN_NAMESPACE @@ -68,15 +64,17 @@ QT_BEGIN_NAMESPACE access the global pixmap cache. It creates an internal QCache object for caching the pixmaps. - The cache associates a pixmap with a string (key). If two pixmaps - are inserted into the cache using equal keys, then the last pixmap - will hide the first pixmap. The QHash and QCache classes do + The cache associates a pixmap with a string as a key or with a QPixmapCache::Key. + The QPixmapCache::Key is faster than using strings as key. + If two pixmaps are inserted into the cache using equal keys, then the + last pixmap will hide the first pixmap. The QHash and QCache classes do exactly the same. The cache becomes full when the total size of all pixmaps in the - cache exceeds cacheLimit(). The initial cache limit is 1024 KB (1 - MB); it is changed with setCacheLimit(). A pixmap takes roughly - (\e{width} * \e{height} * \e{depth})/8 bytes of memory. + cache exceeds cacheLimit(). The initial cache limit is + 2048 KB(2 MB) for Embedded, 10240 KB (10 + MB) for Desktops; it is changed with setCacheLimit(). + A pixmap takes roughly (\e{width} * \e{height} * \e{depth})/8 bytes of memory. The \e{Qt Quarterly} article \l{http://doc.trolltech.com/qq/qq12-qpixmapcache.html}{Optimizing @@ -92,52 +90,117 @@ static int cache_limit = 2048; // 2048 KB cache limit for embedded static int cache_limit = 10240; // 10 MB cache limit for desktop #endif -// XXX: hw: is this a general concept we need to abstract? -class QDetachedPixmap : public QPixmap +/*! + Constructs an empty Key object. +*/ +QPixmapCache::Key::Key() : d(0) { -public: - QDetachedPixmap(const QPixmap &pix) : QPixmap(pix) - { - if (data && data->classId() == QPixmapData::RasterClass) { - QRasterPixmapData *d = static_cast<QRasterPixmapData*>(data); - if (!d->image.isNull() && d->image.d->paintEngine - && !d->image.d->paintEngine->isActive()) - { - delete d->image.d->paintEngine; - d->image.d->paintEngine = 0; - } - } +} + +/*! + \internal + Constructs a copy of \a other. +*/ +QPixmapCache::Key::Key(const Key &other) +{ + if (other.d) + ++(other.d->ref); + d = other.d; +} + +/*! + Destructor; called immediately before the object is deleted. +*/ +QPixmapCache::Key::~Key() +{ + if (d && --(d->ref) == 0) + delete d; +} + +/*! + \internal + + Returns true if this key is the same as the given \a key. +*/ +bool QPixmapCache::Key::operator ==(const Key &key) const +{ + return (d == key.d); +} + +/*! + \internal +*/ +QPixmapCache::Key &QPixmapCache::Key::operator =(const Key &other) +{ + if (d != other.d) { + if (other.d) + ++(other.d->ref); + if (d && --(d->ref) == 0) + delete d; + d = other.d; } -}; + return *this; +} -class QPMCache : public QObject, public QCache<qint64, QDetachedPixmap> +class QPMCache : public QObject, public QCache<QPixmapCache::Key, QDetachedPixmap> { Q_OBJECT public: - QPMCache() - : QObject(0), - QCache<qint64, QDetachedPixmap>(cache_limit * 1024), - theid(0), ps(0), t(false) { } - ~QPMCache() { } + QPMCache(); + ~QPMCache(); void timerEvent(QTimerEvent *); bool insert(const QString& key, const QPixmap &pixmap, int cost); + QPixmapCache::Key insert(const QPixmap &pixmap, int cost); + bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost); bool remove(const QString &key); + bool remove(const QPixmapCache::Key &key); + + void resizeKeyArray(int size); + QPixmapCache::Key createKey(); + void releaseKey(const QPixmapCache::Key &key); + void clear(); QPixmap *object(const QString &key) const; + QPixmap *object(const QPixmapCache::Key &key) const; + + static inline QPixmapCache::KeyData *get(const QPixmapCache::Key &key) + {return key.d;} + + static QPixmapCache::KeyData* getKeyData(QPixmapCache::Key *key); private: - QHash<QString, qint64> cacheKeys; + int *keyArray; int theid; int ps; + int keyArraySize; + int freeKey; + QHash<QString, QPixmapCache::Key> cacheKeys; bool t; }; + QT_BEGIN_INCLUDE_NAMESPACE #include "qpixmapcache.moc" QT_END_INCLUDE_NAMESPACE +static uint qHash(const QPixmapCache::Key &k) +{ + return qHash(QPMCache::get(k)->key); +} + +QPMCache::QPMCache() + : QObject(0), + QCache<QPixmapCache::Key, QDetachedPixmap>(cache_limit * 1024), + keyArray(0), theid(0), ps(0), keyArraySize(0), freeKey(0), t(false) +{ +} +QPMCache::~QPMCache() +{ + free(keyArray); +} + /* - This is supposed to cut the cache size down by about 80-90% in a + This is supposed to cut the cache size down by about 25% in a minute once the application becomes idle, to let any inserted pixmap remain in the cache for some time before it becomes a candidate for cleaning-up, and to not cut down the size of the cache while the @@ -146,23 +209,28 @@ QT_END_INCLUDE_NAMESPACE When the last pixmap has been deleted from the cache, kill the timer so Qt won't keep the CPU from going into sleep mode. */ - void QPMCache::timerEvent(QTimerEvent *) { int mc = maxCost(); bool nt = totalCost() == ps; + QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QDetachedPixmap>::keys(); setMaxCost(nt ? totalCost() * 3 / 4 : totalCost() -1); setMaxCost(mc); ps = totalCost(); - QHash<QString, qint64>::iterator it = cacheKeys.begin(); + QHash<QString, QPixmapCache::Key>::iterator it = cacheKeys.begin(); while (it != cacheKeys.end()) { if (!contains(it.value())) { + releaseKey(it.value()); it = cacheKeys.erase(it); } else { ++it; } } + for (int i = 0; i < keys.size(); ++i) { + if (!contains(keys.at(i))) + releaseKey(keys.at(i)); + } if (!size()) { killTimer(theid); @@ -176,38 +244,154 @@ void QPMCache::timerEvent(QTimerEvent *) QPixmap *QPMCache::object(const QString &key) const { - return QCache<qint64, QDetachedPixmap>::object(cacheKeys.value(key, -1)); + QPixmapCache::Key cacheKey = cacheKeys.value(key); + if (!cacheKey.d || !cacheKey.d->isValid) { + const_cast<QPMCache *>(this)->cacheKeys.remove(key); + return 0; + } + QPixmap *ptr = QCache<QPixmapCache::Key, QDetachedPixmap>::object(cacheKey); + //We didn't find the pixmap in the cache, the key is not valid anymore + if (!ptr) { + const_cast<QPMCache *>(this)->cacheKeys.remove(key); + const_cast<QPMCache *>(this)->releaseKey(cacheKey); + } + return ptr; } +QPixmap *QPMCache::object(const QPixmapCache::Key &key) const +{ + Q_ASSERT(key.d->isValid); + QPixmap *ptr = QCache<QPixmapCache::Key, QDetachedPixmap>::object(key); + //We didn't find the pixmap in the cache, the key is not valid anymore + if (!ptr) + const_cast<QPMCache *>(this)->releaseKey(key); + return ptr; +} bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost) { - qint64 cacheKey = pixmap.cacheKey(); - if (QCache<qint64, QDetachedPixmap>::object(cacheKey)) { + QPixmapCache::Key cacheKey; + QPixmapCache::Key oldCacheKey = cacheKeys.value(key); + //If for the same key we add already a pixmap we should delete it + if (oldCacheKey.d) { + QCache<QPixmapCache::Key, QDetachedPixmap>::remove(oldCacheKey); + cacheKey = oldCacheKey; + } else { + cacheKey = createKey(); + } + + bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); + if (success) { cacheKeys.insert(key, cacheKey); - return true; + if (!theid) { + theid = startTimer(30000); + t = false; + } + } else { + //Insertion failed we released the new allocated key + releaseKey(cacheKey); } - qint64 oldCacheKey = cacheKeys.value(key, -1); - //If for the same key we add already a pixmap we should delete it - if (oldCacheKey != -1) - QCache<qint64, QDetachedPixmap>::remove(oldCacheKey); + return success; +} - bool success = QCache<qint64, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); +QPixmapCache::Key QPMCache::insert(const QPixmap &pixmap, int cost) +{ + QPixmapCache::Key cacheKey = createKey(); + bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); if (success) { - cacheKeys.insert(key, cacheKey); if (!theid) { theid = startTimer(30000); t = false; } + } else { + //Insertion failed we released the key and return an invalid one + releaseKey(cacheKey); + } + return cacheKey; +} + +bool QPMCache::replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost) +{ + Q_ASSERT(key.d->isValid); + //If for the same key we add already a pixmap we should delete it + QCache<QPixmapCache::Key, QDetachedPixmap>::remove(key); + + bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(key, new QDetachedPixmap(pixmap), cost); + if (success && !theid) { + theid = startTimer(30000); + t = false; } return success; } bool QPMCache::remove(const QString &key) { - qint64 cacheKey = cacheKeys.value(key, -1); + QPixmapCache::Key cacheKey = cacheKeys.value(key); + //The key was not in the cache + if (!cacheKey.d) + return false; cacheKeys.remove(key); - return QCache<qint64, QDetachedPixmap>::remove(cacheKey); + releaseKey(cacheKey); + return QCache<QPixmapCache::Key, QDetachedPixmap>::remove(cacheKey); +} + +bool QPMCache::remove(const QPixmapCache::Key &key) +{ + releaseKey(key); + return QCache<QPixmapCache::Key, QDetachedPixmap>::remove(key); +} + +void QPMCache::resizeKeyArray(int size) +{ + if (size <= keyArraySize || size == 0) + return; + keyArray = reinterpret_cast<int *>(realloc(keyArray, size * sizeof(int))); + for (int i = keyArraySize; i != size; ++i) + keyArray[i] = i + 1; + keyArraySize = size; +} + +QPixmapCache::Key QPMCache::createKey() +{ + if (freeKey == keyArraySize) + resizeKeyArray(keyArraySize ? keyArraySize << 1 : 2); + int id = freeKey; + freeKey = keyArray[id]; + QPixmapCache::Key key; + QPixmapCache::KeyData *d = QPMCache::getKeyData(&key); + d->key = ++id; + return key; +} + +void QPMCache::releaseKey(const QPixmapCache::Key &key) +{ + if (key.d->key > keyArraySize || key.d->key <= 0) + return; + key.d->key--; + keyArray[key.d->key] = freeKey; + freeKey = key.d->key; + key.d->isValid = false; + key.d->key = 0; +} + +void QPMCache::clear() +{ + free(keyArray); + keyArray = 0; + freeKey = 0; + keyArraySize = 0; + //Mark all keys as invalid + QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QDetachedPixmap>::keys(); + for (int i = 0; i < keys.size(); ++i) + keys.at(i).d->isValid = false; + QCache<QPixmapCache::Key, QDetachedPixmap>::clear(); +} + +QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key) +{ + if (!key->d) + key->d = new QPixmapCache::KeyData; + return key->d; } Q_GLOBAL_STATIC(QPMCache, pm_cache) @@ -222,7 +406,7 @@ Q_GLOBAL_STATIC(QPMCache, pm_cache) \warning If valid, you should copy the pixmap immediately (this is fast). Subsequent insertions into the cache could cause the pointer to become invalid. For this reason, we recommend you use - find(const QString&, QPixmap&) instead. + bool find(const QString&, QPixmap*) instead. Example: \snippet doc/src/snippets/code/src_gui_image_qpixmapcache.cpp 0 @@ -235,6 +419,17 @@ QPixmap *QPixmapCache::find(const QString &key) /*! + \obsolete + + Use bool find(const QString&, QPixmap*) instead. +*/ + +bool QPixmapCache::find(const QString &key, QPixmap& pixmap) +{ + return find(key, &pixmap); +} + +/*! Looks for a cached pixmap associated with the \a key in the cache. If the pixmap is found, the function sets \a pm to that pixmap and returns true; otherwise it leaves \a pm alone and returns false. @@ -243,14 +438,31 @@ QPixmap *QPixmapCache::find(const QString &key) \snippet doc/src/snippets/code/src_gui_image_qpixmapcache.cpp 1 */ -bool QPixmapCache::find(const QString &key, QPixmap& pm) +bool QPixmapCache::find(const QString &key, QPixmap* pixmap) { QPixmap *ptr = pm_cache()->object(key); - if (ptr) - pm = *ptr; + if (ptr && pixmap) + *pixmap = *ptr; return ptr != 0; } +/*! + Looks for a cached pixmap associated with the \a key in the cache. + If the pixmap is found, the function sets \a pm to that pixmap and + returns true; otherwise it leaves \a pm alone and returns false. If + the pixmap is not found, it means that the \a key is not valid anymore, + so it will be released for the next insertion. +*/ +bool QPixmapCache::find(const Key &key, QPixmap* pixmap) +{ + //The key is not valid anymore, a flush happened before probably + if (!key.d || !key.d->isValid) + return false; + QPixmap *ptr = pm_cache()->object(key); + if (ptr && pixmap) + *pixmap = *ptr; + return ptr != 0; +} /*! Inserts a copy of the pixmap \a pm associated with the \a key into @@ -272,9 +484,43 @@ bool QPixmapCache::find(const QString &key, QPixmap& pm) \sa setCacheLimit() */ -bool QPixmapCache::insert(const QString &key, const QPixmap &pm) +bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap) +{ + return pm_cache()->insert(key, pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); +} + +/*! + Inserts a copy of the pixmap \a pm into + the cache and return you the key. The key is always greater than 0. + If the key is equals 0 then the insertion failed. + + When a pixmap is inserted and the cache is about to exceed its + limit, it removes pixmaps until there is enough room for the + pixmap to be inserted. + + The oldest pixmaps (least recently accessed in the cache) are + deleted when more space is needed. + + \sa setCacheLimit(), replace() +*/ +QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap) +{ + return pm_cache()->insert(pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); +} + +/*! + Replace the pixmap associated to the \a key into + the cache. It return true if the pixmap \a pm has been correctly + inserted into the cache false otherwise. + + \sa setCacheLimit(), insert() +*/ +bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap) { - return pm_cache()->insert(key, pm, pm.width() * pm.height() * pm.depth() / 8); + //The key is not valid anymore, a flush happened before probably + if (!key.d || !key.d->isValid) + return false; + return pm_cache()->replace(key, pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); } /*! @@ -314,6 +560,17 @@ void QPixmapCache::remove(const QString &key) pm_cache()->remove(key); } +/*! + Removes the pixmap associated with \a key from the cache and release + the key for a future insertion. +*/ +void QPixmapCache::remove(const Key &key) +{ + //The key is not valid anymore, a flush happened before probably + if (!key.d || !key.d->isValid) + return; + pm_cache()->remove(key); +} /*! Removes all pixmaps from the cache. diff --git a/src/gui/image/qpixmapcache.h b/src/gui/image/qpixmapcache.h index 2750a88..ae64310 100644 --- a/src/gui/image/qpixmapcache.h +++ b/src/gui/image/qpixmapcache.h @@ -53,12 +53,35 @@ QT_MODULE(Gui) class Q_GUI_EXPORT QPixmapCache { public: + class KeyData; + class Key + { + public: + Key(); + Key(const Key &other); + ~Key(); + bool operator ==(const Key &key) const; + inline bool operator !=(const Key &key) const + { return !operator==(key); } + Key &operator =(const Key &other); + + private: + KeyData *d; + friend class QPMCache; + friend class QPixmapCache; + }; + static int cacheLimit(); static void setCacheLimit(int); static QPixmap *find(const QString &key); - static bool find(const QString &key, QPixmap&); - static bool insert(const QString &key, const QPixmap&); + static bool find(const QString &key, QPixmap &pixmap); + static bool find(const QString &key, QPixmap *pixmap); + static bool find(const Key &key, QPixmap *pixmap); + static bool insert(const QString &key, const QPixmap &pixmap); + static Key insert(const QPixmap &pixmap); + static bool replace(const Key &key, const QPixmap &pixmap); static void remove(const QString &key); + static void remove(const Key &key); static void clear(); }; diff --git a/src/gui/image/qpixmapcache_p.h b/src/gui/image/qpixmapcache_p.h new file mode 100644 index 0000000..66b30d2 --- /dev/null +++ b/src/gui/image/qpixmapcache_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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 QPIXMAPCACHE_P_H +#define QPIXMAPCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qpixmapcache.h" +#include "qpaintengine.h" +#include <private/qimage_p.h> +#include <private/qpixmap_raster_p.h> +#include "qcache.h" + +class QPixmapCache::KeyData +{ +public: + KeyData() : isValid(true), key(0), ref(1) {} + KeyData(const KeyData &other) + : isValid(other.isValid), key(other.key), ref(1) {} + ~KeyData() {} + + bool isValid; + int key; + int ref; +}; + +// XXX: hw: is this a general concept we need to abstract? +class QDetachedPixmap : public QPixmap +{ +public: + QDetachedPixmap(const QPixmap &pix) : QPixmap(pix) + { + if (data && data->classId() == QPixmapData::RasterClass) { + QRasterPixmapData *d = static_cast<QRasterPixmapData*>(data); + if (!d->image.isNull() && d->image.d->paintEngine + && !d->image.d->paintEngine->isActive()) + { + delete d->image.d->paintEngine; + d->image.d->paintEngine = 0; + } + } + } +}; + +#endif // QPIXMAPCACHE_P_H diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index 9f33af3..054f4cf 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -416,26 +416,22 @@ QString QFileIconProvider::type(const QFileInfo &info) const } if (info.isDir()) - return QApplication::translate("QFileDialog", #ifdef Q_WS_WIN - "File Folder", "Match Windows Explorer" + return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer"); #else - "Folder", "All other platforms" + return QApplication::translate("QFileDialog", "Folder", "All other platforms"); #endif - ); // Windows - "File Folder" // OS X - "Folder" // Konqueror - "Folder" // Nautilus - "folder" if (info.isSymLink()) - return QApplication::translate("QFileDialog", #ifdef Q_OS_MAC - "Alias", "Mac OS X Finder" + return QApplication::translate("QFileDialog", "Alias", "Mac OS X Finder"); #else - "Shortcut", "All other platforms" + return QApplication::translate("QFileDialog", "Shortcut", "All other platforms"); #endif - ); // OS X - "Alias" // Windows - "Shortcut" // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index f6c5cf0..d742698 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -3086,10 +3086,6 @@ void QTreeViewPrivate::layout(int i) Q_Q(QTreeView); QModelIndex current; QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i); - // modelIndex() will return an index that don't have a parent if column 0 is hidden, - // so we must make sure that parent points to the actual parent that has children. - if (parent != root) - parent = model->index(parent.row(), 0, parent.parent()); if (i>=0 && !parent.isValid()) { //modelIndex() should never return something invalid for the real items. diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index e46ccf1..204cff6 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -2037,12 +2037,10 @@ QWidget *QApplication::focusWidget() void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) { - if (focus && focus->window() #ifndef QT_NO_GRAPHICSVIEW - && focus->window()->graphicsProxyWidget() -#endif - ) + if (focus && focus->window()->graphicsProxyWidget()) return; +#endif hidden_focus_widget = 0; diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 6524bc9..cc291e3 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -781,16 +781,6 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, // By also setting the current modal window back into the event, we // help Carbon determining which window is supposed to be raised. handled_event = qApp->activePopupWidget() ? true : false; - QWidget *top = 0; - if (!QApplicationPrivate::tryModalHelper(widget, &top) && top && top != widget){ - if(!qt_mac_is_macsheet(top) || top->parentWidget() != widget) { - handled_event = true; - WindowPtr topWindowRef = qt_mac_window_for(top); - SetEventParameter(event, kEventParamModalWindow, typeWindowRef, sizeof(topWindowRef), &topWindowRef); - HIModalClickResult clickResult = kHIModalClickIsModal; - SetEventParameter(event, kEventParamModalClickResult, typeModalClickResult, sizeof(clickResult), &clickResult); - } - } #endif } else if(ekind == kEventWindowClose) { widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent); diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 24d167e..534a425 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -1369,7 +1369,7 @@ QColor QColor::toRgb() const */ QColor QColor::toHsv() const { - if (!isValid()) + if (!isValid() || cspec == Hsv) return *this; if (cspec != Rgb) @@ -1421,7 +1421,7 @@ QColor QColor::toHsv() const */ QColor QColor::toCmyk() const { - if (!isValid()) + if (!isValid() || cspec == Cmyk) return *this; if (cspec != Rgb) return toRgb().toCmyk(); diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 1ea40ba..3fd1ffb 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -88,11 +88,12 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, ti.ascent.toReal(), ti.descent.toReal()); #endif - int glyph_width = metrics.width.ceil().toInt() + margin * 2; - int glyph_height = metrics.height.ceil().toInt() + margin * 2; + int glyph_width = metrics.width.ceil().toInt(); + int glyph_height = metrics.height.ceil().toInt(); if (glyph_height == 0 || glyph_width == 0) continue; - + glyph_width += margin * 2 + 2; + glyph_height += margin * 2 + 2; // align to 8-bit boundary if (m_type == QFontEngineGlyphCache::Raster_Mono) glyph_width = (glyph_width+7)&~7; @@ -188,11 +189,7 @@ void QImageTextureGlyphCache::createTextureData(int width, int height) int QImageTextureGlyphCache::glyphMargin() const { -#ifdef Q_WS_MAC return 2; -#else - return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; -#endif } void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g) diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index c0899f8..6972803 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -1664,6 +1664,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (!styleHint(SH_UnderlineShortcut, opt, widget)) alignment |= Qt::TextHideMnemonic; rect.translate(shiftX, shiftY); + p->setFont(toolbutton->font); drawItemText(p, rect, alignment, toolbutton->palette, opt->state & State_Enabled, toolbutton->text, QPalette::ButtonText); diff --git a/src/gui/styles/qmotifstyle.cpp b/src/gui/styles/qmotifstyle.cpp index 7d4fab8..be0e3eb 100644 --- a/src/gui/styles/qmotifstyle.cpp +++ b/src/gui/styles/qmotifstyle.cpp @@ -2026,10 +2026,6 @@ QMotifStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, QSize sz(contentsSize); switch(ct) { - case CT_Splitter: - sz = QSize(10, 10); - break; - case CT_RadioButton: case CT_CheckBox: sz = QCommonStyle::sizeFromContents(ct, opt, contentsSize, widget); diff --git a/src/gui/styles/qstyle.cpp b/src/gui/styles/qstyle.cpp index b73332f..514f67b 100644 --- a/src/gui/styles/qstyle.cpp +++ b/src/gui/styles/qstyle.cpp @@ -1332,7 +1332,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value PM_LayoutVerticalSpacing Default \l{QLayout::spacing}{vertical spacing} for a QLayout. \value PM_MaximumDragDistance The maximum allowed distance between - the mouse and a slider when dragging. Exceeding the specified + the mouse and a scrollbar when dragging. Exceeding the specified distance will cause the slider to jump back to the original position; a value of -1 disables this behavior. diff --git a/src/gui/styles/qstyleoption.cpp b/src/gui/styles/qstyleoption.cpp index ce053ae..5b1bc61 100644 --- a/src/gui/styles/qstyleoption.cpp +++ b/src/gui/styles/qstyleoption.cpp @@ -48,6 +48,7 @@ #ifndef QT_NO_DEBUG #include <qdebug.h> #endif +#include <QtCore/qmath.h> QT_BEGIN_NAMESPACE @@ -4998,6 +4999,34 @@ QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(int version) } /*! + \since 4.6 + + Returns the level of detail from the \a worldTransform. + + Its value represents the maximum value of the height and + width of a unity rectangle, mapped using the \a worldTransform + of the painter used to draw the item. By default, if no + transformations are applied, its value is 1. If zoomed out 1:2, the level + of detail will be 0.5, and if zoomed in 2:1, its value is 2. + + For more advanced level-of-detail metrics, use + QStyleOptionGraphicsItem::matrix directly. + + \sa QStyleOptionGraphicsItem::matrix +*/ +qreal QStyleOptionGraphicsItem::levelOfDetailFromTransform(const QTransform &worldTransform) +{ + if (worldTransform.type() <= QTransform::TxTranslate) + return 1; // Translation only? The LOD is 1. + + // Two unit vectors. + QLineF v1(0, 0, 1, 0); + QLineF v2(0, 0, 0, 1); + // LOD is the transformed area of a 1x1 rectangle. + return qSqrt(worldTransform.map(v1).length() * worldTransform.map(v2).length()); +} + +/*! \fn QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(const QStyleOptionGraphicsItem &other) Constructs a copy of \a other. @@ -5029,19 +5058,10 @@ QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(int version) /*! \variable QStyleOptionGraphicsItem::levelOfDetail - \brief a simple metric for determining an item's level of detail - - This simple metric provides an easy way to determine the level of detail - for an item. Its value represents the maximum value of the height and - width of a unity rectangle, mapped using the complete transformation - matrix of the painter used to draw the item. By default, if no - transformations are applied, its value is 1. If zoomed out 1:2, the level - of detail will be 0.5, and if zoomed in 2:1, its value is 2. - - For more advanced level-of-detail metrics, use - QStyleOptionGraphicsItem::matrix directly. + \obsolete - \sa QStyleOptionGraphicsItem::matrix + Use QStyleOptionGraphicsItem::levelOfDetailFromTransform + together with QPainter::worldTransform() instead. */ /*! diff --git a/src/gui/styles/qstyleoption.h b/src/gui/styles/qstyleoption.h index 5759a05..eb05324 100644 --- a/src/gui/styles/qstyleoption.h +++ b/src/gui/styles/qstyleoption.h @@ -856,6 +856,7 @@ public: QStyleOptionGraphicsItem(); QStyleOptionGraphicsItem(const QStyleOptionGraphicsItem &other) : QStyleOption(Version, Type) { *this = other; } + static qreal levelOfDetailFromTransform(const QTransform &worldTransform); protected: QStyleOptionGraphicsItem(int version); }; diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index dcc11b8..fdd51c3 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -3030,6 +3030,7 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC if (const QStyleOptionToolButton *tool = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) { QStyleOptionToolButton toolOpt(*tool); rule.configurePalette(&toolOpt.palette, QPalette::ButtonText, QPalette::Button); + toolOpt.font = rule.font.resolve(toolOpt.font); toolOpt.rect = rule.borderRect(opt->rect); bool customArrow = (tool->features & (QStyleOptionToolButton::HasMenu | QStyleOptionToolButton::MenuButtonPopup)); bool customDropDown = tool->features & QStyleOptionToolButton::MenuButtonPopup; @@ -4805,13 +4806,10 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op if ((pe == PseudoElement_MenuSeparator) && subRule.hasContentsSize()) { return QSize(sz.width(), subRule.size().height()); } else if ((pe == PseudoElement_Item) && (subRule.hasBox() || subRule.hasBorder())) { - int width = csz.width(), height = qMax(csz.height(), mi->fontMetrics.height()); - if (!mi->icon.isNull()) { - int iconExtent = pixelMetric(PM_SmallIconSize); - height = qMax(height, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height()); - } - width += mi->tabWidth; - return subRule.boxSize(csz.expandedTo(subRule.minimumContentsSize())); + int width = csz.width(); + if (mi->text.contains(QLatin1Char('\t'))) + width += 12; //as in QCommonStyle + return subRule.boxSize(subRule.adjustSize(QSize(width, csz.height()))); } } break; diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp index 639eff0..3dac9f5 100644 --- a/src/gui/styles/qwindowsxpstyle.cpp +++ b/src/gui/styles/qwindowsxpstyle.cpp @@ -1792,7 +1792,12 @@ case PE_Frame: return; case PE_IndicatorToolBarSeparator: - + if (option->rect.height() < 3) { + // XP style requires a few pixels for the separator + // to be visible. + QWindowsStyle::drawPrimitive(pe, option, p, widget); + return; + } name = QLatin1String("TOOLBAR"); partId = TP_SEPARATOR; diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index fbd6c16..72bd637 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -403,7 +403,7 @@ struct BorderData { // 4. QVector<Declaration> - { prop1: value1; prop2: value2; } // 5. Declaration - prop1: value1; -struct Declaration +struct Q_AUTOTEST_EXPORT Declaration { struct DeclarationData : public QSharedData { @@ -539,7 +539,7 @@ struct BasicSelector Relation relationToNext; }; -struct Selector +struct Q_AUTOTEST_EXPORT Selector { QVector<BasicSelector> basicSelectors; int specificity() const; @@ -552,7 +552,7 @@ struct MediaRule; struct PageRule; struct ImportRule; -struct ValueExtractor +struct Q_AUTOTEST_EXPORT ValueExtractor { ValueExtractor(const QVector<Declaration> &declarations, const QPalette & = QPalette()); diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp index 6551e87..feea1f2 100644 --- a/src/gui/text/qfontengine_win.cpp +++ b/src/gui/text/qfontengine_win.cpp @@ -1406,8 +1406,8 @@ QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin #endif #endif - QNativeImage *ni = new QNativeImage(iw + 2 * margin, - ih + 2 * margin, + QNativeImage *ni = new QNativeImage(iw + 2 * margin + 2, + ih + 2 * margin + 2, QNativeImage::systemFormat(), true); ni->image.fill(0xffffffff); @@ -1449,7 +1449,7 @@ QImage QFontEngineWin::alphaMapForGlyph(glyph_t glyph, const QTransform &xform) font = CreateFontIndirectW(&lf); } - QNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform); + QNativeImage *mask = drawGDIGlyph(font, glyph, 2, xform); if (mask == 0) return QImage(); diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index 190dbb5..b91e3dd 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -873,21 +873,22 @@ bool QAbstractScrollArea::event(QEvent *e) case QEvent::Resize: d->layoutChildren(); break; - case QEvent::Paint: + case QEvent::Paint: { + QStyleOption option; + option.initFrom(this); if (d->cornerPaintingRect.isValid()) { - QStyleOption option; option.rect = d->cornerPaintingRect; QPainter p(this); style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this); } #ifdef Q_WS_MAC if (d->reverseCornerPaintingRect.isValid()) { - QStyleOption option; option.rect = d->reverseCornerPaintingRect; QPainter p(this); style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &option, &p, this); } #endif + } QFrame::paintEvent((QPaintEvent*)e); break; #ifndef QT_NO_CONTEXTMENU diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp index 347f89a..d640c70 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -193,6 +193,7 @@ void QAbstractSpinBox::setButtonSymbols(ButtonSymbols buttonSymbols) Q_D(QAbstractSpinBox); if (d->buttonSymbols != buttonSymbols) { d->buttonSymbols = buttonSymbols; + d->updateEditFieldGeometry(); update(); } } diff --git a/src/gui/widgets/qmenu_wince.cpp b/src/gui/widgets/qmenu_wince.cpp index 0befa6d..2ce89f9 100644 --- a/src/gui/widgets/qmenu_wince.cpp +++ b/src/gui/widgets/qmenu_wince.cpp @@ -214,7 +214,7 @@ static HWND qt_wce_create_menubar(HWND parentHandle, HINSTANCE resourceHandle, i mbi.nToolBarId = toolbarID; if (ptrCreateMenuBar(&mbi)) { -#ifdef Q_WS_WINCE_WM +#ifdef Q_OS_WINCE_WM // Tell the menu bar that we want to override hot key behaviour. LPARAM lparam = MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY); diff --git a/src/gui/widgets/qslider.cpp b/src/gui/widgets/qslider.cpp index 32b9021..5b9c8a4 100644 --- a/src/gui/widgets/qslider.cpp +++ b/src/gui/widgets/qslider.cpp @@ -62,7 +62,6 @@ public: int tickInterval; QSlider::TickPosition tickPosition; int clickOffset; - int snapBackPosition; void init(); void resetLayoutItemMargins(); int pixelPosToRangeValue(int pos) const; @@ -493,7 +492,6 @@ void QSlider::mousePressEvent(QMouseEvent *ev) setRepeatAction(SliderNoAction); QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); d->clickOffset = d->pick(ev->pos() - sr.topLeft()); - d->snapBackPosition = d->position; update(sr); setSliderDown(true); } @@ -513,14 +511,6 @@ void QSlider::mouseMoveEvent(QMouseEvent *ev) int newPosition = d->pixelPosToRangeValue(d->pick(ev->pos()) - d->clickOffset); QStyleOptionSlider opt; initStyleOption(&opt); - int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this); - if (m >= 0) { - QRect r = rect(); - r.adjust(-m, -m, m, m); - if (!r.contains(ev->pos())) { - newPosition = d->snapBackPosition; - } - } setSliderPosition(newPosition); } diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index 7d0438e..bd364cb 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -973,21 +973,39 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo if (it != cacheHeaders.rawHeaders.constEnd()) metaData.setLastModified(QNetworkHeadersPrivate::fromHttpDate(it->second)); - bool canDiskCache = true; // Everything defaults to being cacheable on disk - - // 14.32 - // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client - // had sent "Cache-Control: no-cache". - it = cacheHeaders.findRawHeader("pragma"); - if (it != cacheHeaders.rawHeaders.constEnd() - && it->second == "no-cache") - canDiskCache = false; + bool canDiskCache; + // only cache GET replies by default, all other replies (POST, PUT, DELETE) + // are not cacheable by default (according to RFC 2616 section 9) + if (httpReply->request().operation() == QHttpNetworkRequest::Get) { + + canDiskCache = true; + // 14.32 + // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client + // had sent "Cache-Control: no-cache". + it = cacheHeaders.findRawHeader("pragma"); + if (it != cacheHeaders.rawHeaders.constEnd() + && it->second == "no-cache") + canDiskCache = false; + + // HTTP/1.1. Check the Cache-Control header + if (cacheControl.contains("no-cache")) + canDiskCache = false; + else if (cacheControl.contains("no-store")) + canDiskCache = false; + + // responses to POST might be cacheable + } else if (httpReply->request().operation() == QHttpNetworkRequest::Post) { - // HTTP/1.1. Check the Cache-Control header - if (cacheControl.contains("no-cache")) canDiskCache = false; - else if (cacheControl.contains("no-store")) + // some pages contain "expires:" and "cache-control: no-cache" field, + // so we only might cache POST requests if we get "cache-control: max-age ..." + if (cacheControl.contains("max-age")) + canDiskCache = true; + + // responses to PUT and DELETE are not cacheable + } else { canDiskCache = false; + } metaData.setSaveToDisk(canDiskCache); int statusCode = httpReply->statusCode(); diff --git a/src/sql/drivers/ibase/qsql_ibase.cpp b/src/sql/drivers/ibase/qsql_ibase.cpp index 6834d9a..4f3d79d 100644 --- a/src/sql/drivers/ibase/qsql_ibase.cpp +++ b/src/sql/drivers/ibase/qsql_ibase.cpp @@ -66,8 +66,11 @@ QT_BEGIN_NAMESPACE enum { QIBaseChunkSize = SHRT_MAX / 2 }; -static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, - QTextCodec *tc) +#if defined(FB_API_VER) && FB_API_VER >= 20 +static bool getIBaseError(QString& msg, const ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc) +#else +static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc) +#endif { if (status[0] != 1 || status[1] <= 0) return false; @@ -75,7 +78,11 @@ static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, msg.clear(); sqlcode = isc_sqlcode(status); char buf[512]; +#if defined(FB_API_VER) && FB_API_VER >= 20 + while(fb_interpret(buf, 512, &status)) { +#else while(isc_interprete(buf, &status)) { +#endif if(!msg.isEmpty()) msg += QLatin1String(" - "); if (tc) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 8c76c5d..041f2db 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1465,8 +1465,12 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) #if !defined(QT_NO_PROCESS) || !defined(QT_NO_SETTINGS) if (QBenchmarkGlobalData::current->createChart) { - QString chartLocation = QLibraryInfo::location(QLibraryInfo::BinariesPath) - + QLatin1String("/../tools/qtestlib/chart/chart"); + QString chartLocation = QLibraryInfo::location(QLibraryInfo::BinariesPath); +#ifdef Q_OS_WIN + chartLocation += QLatin1String("/../tools/qtestlib/chart/release/chart.exe"); +#else + chartLocation += QLatin1String("/../tools/qtestlib/chart/chart"); +#endif if (QFile::exists(chartLocation)) { QProcess p; p.setProcessChannelMode(QProcess::ForwardedChannels); |