diff options
47 files changed, 1738 insertions, 440 deletions
diff --git a/doc/src/frameworks-technologies/model-view-programming.qdoc b/doc/src/frameworks-technologies/model-view-programming.qdoc index 58b51e5..2345990 100644 --- a/doc/src/frameworks-technologies/model-view-programming.qdoc +++ b/doc/src/frameworks-technologies/model-view-programming.qdoc @@ -1934,6 +1934,13 @@ \l{QSortFilterProxyModel::lessThan()}{lessThan()} function to perform custom comparisons. + \section3 Custom data models + + QIdentityProxyModel instances do not sort or filter the structure of the source model, + but provide a base class for creating a data proxy. This could be useful on top of a + QFileSystemModel for example to provide different colours for the BackgroundRole for + different types of files. + \section1 Model subclassing reference Model subclasses need to provide implementations of many of the virtual functions diff --git a/doc/src/platforms/platform-notes.qdoc b/doc/src/platforms/platform-notes.qdoc index 310ef06..24b297f 100644 --- a/doc/src/platforms/platform-notes.qdoc +++ b/doc/src/platforms/platform-notes.qdoc @@ -630,7 +630,7 @@ we need to do special bookkeeping in Qt to handle this correctly, which unfortunately make mixing in native panels hard. The best way at the moment to do this, is to follow the pattern below, where we post the call to the - function with native code rather than calling it directly. Then we now that + function with native code rather than calling it directly. Then we know that Qt has cleanly updated any pending event loop recursions before the native panel is shown: diff --git a/doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp b/doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp index cf40f9a..5919c01 100644 --- a/doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp +++ b/doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp @@ -86,38 +86,3 @@ beginMoveRows(parent, 2, 2, parent, 0); //! [9] beginMoveRows(parent, 2, 2, parent, 4); //! [9] - - -//! [10] -class CustomDataProxy : public QSortFilterProxyModel -{ - Q_OBJECT -public: - CustomDataProxy(QObject *parent) - : QSortFilterProxyModel(parent) - { - } - - ... - - QVariant data(const QModelIndex &index, int role) - { - if (role != Qt::BackgroundRole) - return QSortFilterProxyModel::data(index, role); - - if (m_customData.contains(index.row())) - return m_customData.value(index.row()); - return QSortFilterProxyModel::data(index, role); - } - -private slots: - void resetInternalData() - { - m_customData.clear(); - } - -private: - QHash<int, QVariant> m_customData; -}; -//! [10] - diff --git a/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp b/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp new file mode 100644 index 0000000..6bf6c89 --- /dev/null +++ b/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +class DateFormatProxyModel : public QIdentityProxyModel +{ + // ... + + void setDateFormatString(const QString &formatString) + { + m_formatString = formatString; + } + + QVariant data(const QModelIndex &index, int role) + { + if (role != Qt::DisplayRole) + return QIdentityProxyModel::data(index, role); + + const QDateTime dateTime = sourceModel()->data(SourceClass::DateRole).toDateTime(); + + return dateTime.toString(m_formatString); + } + +private: + QString m_formatString; +}; +//! [0] diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h index 6de3bf5..7bed3a2 100644 --- a/src/corelib/kernel/qabstractitemmodel.h +++ b/src/corelib/kernel/qabstractitemmodel.h @@ -162,6 +162,7 @@ class Q_CORE_EXPORT QAbstractItemModel : public QObject friend class QPersistentModelIndexData; friend class QAbstractItemViewPrivate; + friend class QIdentityProxyModel; public: explicit QAbstractItemModel(QObject *parent = 0); diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index bab6cf8..bdade1d 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -300,7 +300,7 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) #ifndef QT_NO_THREAD -unsigned int __stdcall QThreadPrivate::start(void *arg) +unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg) { QThread *thr = reinterpret_cast<QThread *>(arg); QThreadData *data = QThreadData::get2(thr); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 9a91769..4500a87 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -1876,6 +1876,7 @@ bool QDeclarativeTextInput::isInputMethodComposing() const void QDeclarativeTextInputPrivate::init() { Q_Q(QDeclarativeTextInput); + control->setParent(q); control->setCursorWidth(1); control->setPasswordCharacter(QLatin1Char('*')); q->setSmooth(smooth); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h index f6f6bd8..7595b36 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h @@ -70,7 +70,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInputPrivate : public QDeclarativeImplic { Q_DECLARE_PUBLIC(QDeclarativeTextInput) public: - QDeclarativeTextInputPrivate() : control(new QLineControl(QString())), + QDeclarativeTextInputPrivate() : control(new QLineControl), color((QRgb)0), style(QDeclarativeText::Normal), styleColor((QRgb)0), hAlign(QDeclarativeTextInput::AlignLeft), mouseSelectionMode(QDeclarativeTextInput::SelectCharacters), inputMethodHints(Qt::ImhNone), @@ -89,7 +89,6 @@ public: ~QDeclarativeTextInputPrivate() { - delete control; } int xToPos(int x, QTextLine::CursorPosition betweenOrOn = QTextLine::CursorBetweenCharacters) const diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index c714173..1e9e55e 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -83,6 +83,42 @@ public: MenuCommand = 0x0018, + // Values from IAccessible2 + ActionChanged = 0x0101, + ActiveDescendantChanged, + AttributeChanged, + DocumentContentChanged, + DocumentLoadComplete, + DocumentLoadStopped, + DocumentReload, + HyperlinkEndIndexChanged, + HyperlinkNumberOfAnchorsChanged, + HyperlinkSelectedLinkChanged, + HypertextLinkActivated, + HypertextLinkSelected, + HyperlinkStartIndexChanged, + HypertextChanged, + HypertextNLinksChanged, + ObjectAttributeChanged, + PageChanged, + SectionChanged, + TableCaptionChanged, + TableColumnDescriptionChanged, + TableColumnHeaderChanged, + TableModelChanged, + TableRowDescriptionChanged, + TableRowHeaderChanged, + TableSummaryChanged, + TextAttributeChanged, + TextCaretMoved, + // TextChanged, deprecated, use TextUpdated + TextColumnChanged = TextCaretMoved + 2, + TextInserted, + TextRemoved, + TextUpdated, + TextSelectionChanged, + VisibleDataChanged, + ObjectCreated = 0x8000, ObjectDestroyed = 0x8001, ObjectShow = 0x8002, diff --git a/src/gui/accessible/qaccessibleobject.cpp b/src/gui/accessible/qaccessibleobject.cpp index 1d2d1da..0cb2c08 100644 --- a/src/gui/accessible/qaccessibleobject.cpp +++ b/src/gui/accessible/qaccessibleobject.cpp @@ -322,9 +322,7 @@ QString QAccessibleApplication::text(Text t, int) const { switch (t) { case Name: - if (QApplication::activeWindow()) - return QApplication::activeWindow()->windowTitle(); - break; + return QApplication::applicationName(); case Description: return QApplication::applicationFilePath(); default: diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index ee9b19a..9daf595 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -343,6 +343,7 @@ QT_USE_NAMESPACE mDialogIsExecuting = true; bool modalEnded = false; while (!modalEnded) { +#ifndef QT_NO_EXCEPTIONS @try { [NSApp runModalForWindow:mColorPanel]; modalEnded = true; @@ -351,6 +352,10 @@ QT_USE_NAMESPACE // clicking on 'SelectedMenuItemColor' from the 'Developer' // palette (tab three). } +#else + [NSApp runModalForWindow:mColorPanel]; + modalEnded = true; +#endif } QAbstractEventDispatcher::instance()->interrupt(); diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index cb8eb6a..ff4410d 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -1977,13 +1977,14 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co const bool hideHidden = !(filters & QDir::Hidden); const bool hideSystem = !(filters & QDir::System); const bool hideSymlinks = (filters & QDir::NoSymLinks); - const bool hideDotAndDotDot = (filters & QDir::NoDotAndDotDot); + const bool hideDot = (filters & QDir::NoDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot) + const bool hideDotDot = (filters & QDir::NoDotDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot) // Note that we match the behavior of entryList and not QFileInfo on this and this // incompatibility won't be fixed until Qt 5 at least - bool isDotOrDot = ( (node->fileName == QLatin1String(".") - || node->fileName == QLatin1String(".."))); - if ( (hideHidden && (!isDotOrDot && node->isHidden())) + bool isDot = (node->fileName == QLatin1String(".")); + bool isDotDot = (node->fileName == QLatin1String("..")); + if ( (hideHidden && !(isDot || isDotDot) && node->isHidden()) || (hideSystem && node->isSystem()) || (hideDirs && node->isDir()) || (hideFiles && node->isFile()) @@ -1991,7 +1992,8 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co || (hideReadable && node->isReadable()) || (hideWritable && node->isWritable()) || (hideExecutable && node->isExecutable()) - || (hideDotAndDotDot && isDotOrDot)) + || (hideDot && isDot) + || (hideDotDot && isDotDot)) return false; return nameFilterDisables || passNameFilters(node); diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp index 92e4a55..4688fa0 100644 --- a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp +++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp @@ -50,14 +50,14 @@ QGraphicsSceneBspTreeIndex index use a BSP(Binary Space Partitioning) implementation to discover items quickly. This implementation is - very efficient for static scene. It has a depth that you can set. + very efficient for static scenes. It has a depth that you can set. The depth directly affects performance and memory usage; the latter growing exponentially with the depth of the tree. With an optimal tree depth, the index can instantly determine the locality of items, even for scenes with thousands or millions of items. This also greatly improves rendering performance. - By default, the value is 0, in which case Qt will guess a reasonable + By default, the depth value is 0, in which case Qt will guess a reasonable default depth based on the size, location and number of items in the scene. If these parameters change frequently, however, you may experience slowdowns as the index retunes the depth internally. You can avoid diff --git a/src/gui/itemviews/itemviews.pri b/src/gui/itemviews/itemviews.pri index bbc1e98..149bfd6 100644 --- a/src/gui/itemviews/itemviews.pri +++ b/src/gui/itemviews/itemviews.pri @@ -4,6 +4,7 @@ HEADERS += \ itemviews/qabstractitemview.h \ itemviews/qabstractitemview_p.h \ itemviews/qheaderview.h \ + itemviews/qidentityproxymodel.h \ itemviews/qlistview.h \ itemviews/qlistview_p.h \ itemviews/qbsptree_p.h \ @@ -44,6 +45,7 @@ HEADERS += \ SOURCES += \ itemviews/qabstractitemview.cpp \ itemviews/qheaderview.cpp \ + itemviews/qidentityproxymodel.cpp \ itemviews/qlistview.cpp \ itemviews/qbsptree.cpp \ itemviews/qtableview.cpp \ diff --git a/src/gui/itemviews/qabstractproxymodel.cpp b/src/gui/itemviews/qabstractproxymodel.cpp index 34ca7df..82b6c8d 100644 --- a/src/gui/itemviews/qabstractproxymodel.cpp +++ b/src/gui/itemviews/qabstractproxymodel.cpp @@ -121,15 +121,12 @@ QAbstractProxyModel::~QAbstractProxyModel() void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel) { Q_D(QAbstractProxyModel); - if (d->model) { + if (d->model) disconnect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed())); - disconnect(d->model, SIGNAL(modelReset()), this, SLOT(resetInternalData())); - } if (sourceModel) { d->model = sourceModel; connect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed())); - connect(d->model, SIGNAL(modelReset()), this, SLOT(resetInternalData())); } else { d->model = QAbstractItemModelPrivate::staticEmptyModel(); } @@ -383,25 +380,6 @@ Qt::DropActions QAbstractProxyModel::supportedDropActions() const return d->model->supportedDropActions(); } -/* - \since 4.8 - - This slot is called just after the internal data of a model is cleared - while it is being reset. - - This slot is provided the convenience of subclasses of concrete proxy - models, such as subclasses of QSortFilterProxyModel which maintain extra - data. - - \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 10 - - \sa modelAboutToBeReset(), modelReset() -*/ -void QAbstractProxyModel::resetInternalData() -{ - -} - QT_END_NAMESPACE #include "moc_qabstractproxymodel.cpp" diff --git a/src/gui/itemviews/qabstractproxymodel.h b/src/gui/itemviews/qabstractproxymodel.h index 6e485ae..4f3bc18 100644 --- a/src/gui/itemviews/qabstractproxymodel.h +++ b/src/gui/itemviews/qabstractproxymodel.h @@ -95,9 +95,6 @@ public: QStringList mimeTypes() const; Qt::DropActions supportedDropActions() const; -protected Q_SLOTS: - void resetInternalData(); - protected: QAbstractProxyModel(QAbstractProxyModelPrivate &, QObject *parent); diff --git a/src/gui/itemviews/qidentityproxymodel.cpp b/src/gui/itemviews/qidentityproxymodel.cpp new file mode 100644 index 0000000..60f7d98 --- /dev/null +++ b/src/gui/itemviews/qidentityproxymodel.cpp @@ -0,0 +1,587 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qidentityproxymodel.h" + +#ifndef QT_NO_IDENTITYPROXYMODEL + +#include "qitemselectionmodel.h" +#include <private/qabstractproxymodel_p.h> + +QT_BEGIN_NAMESPACE + +class QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate +{ + QIdentityProxyModelPrivate() + : ignoreNextLayoutAboutToBeChanged(false), + ignoreNextLayoutChanged(false) + { + + } + + Q_DECLARE_PUBLIC(QIdentityProxyModel) + + bool ignoreNextLayoutAboutToBeChanged; + bool ignoreNextLayoutChanged; + QList<QPersistentModelIndex> layoutChangePersistentIndexes; + QModelIndexList proxyIndexes; + + void _q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void _q_sourceRowsInserted(const QModelIndex &parent, int start, int end); + void _q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceRowsRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + void _q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + + void _q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsInserted(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + void _q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + + void _q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last); + + void _q_sourceLayoutAboutToBeChanged(); + void _q_sourceLayoutChanged(); + void _q_sourceModelAboutToBeReset(); + void _q_sourceModelReset(); + +}; + +/*! + \since 4.8 + \class QIdentityProxyModel + \brief The QIdentityProxyModel class proxies its source model unmodified + + \ingroup model-view + + QIdentityProxyModel can be used to forward the structure of a source model exactly, with no sorting, filtering or other transformation. + This is similar in concept to an identity matrix where A.I = A. + + Because it does no sorting or filtering, this class is most suitable to proxy models which transform the data() of the source model. + For example, a proxy model could be created to define the font used, or the background colour, or the tooltip etc. This removes the + need to implement all data handling in the same class that creates the structure of the model, and can also be used to create + re-usable components. + + This also provides a way to change the data in the case where a source model is supplied by a third party which can not be modified. + + \snippet doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp 0 + + \sa QAbstractProxyModel, {Model/View Programming}, QAbstractItemModel + +*/ + +/*! + Constructs an identity model with the given \a parent. +*/ +QIdentityProxyModel::QIdentityProxyModel(QObject* parent) + : QAbstractProxyModel(*new QIdentityProxyModelPrivate, parent) +{ + +} + +/*! \internal + */ +QIdentityProxyModel::QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent) + : QAbstractProxyModel(dd, parent) +{ + +} + +/*! + Destroys this identity model. +*/ +QIdentityProxyModel::~QIdentityProxyModel() +{ +} + +/*! + \reimp + */ +int QIdentityProxyModel::columnCount(const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + return d->model->columnCount(mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->dropMimeData(data, action, row, column, mapToSource(parent)); +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::index(int row, int column, const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + if (!hasIndex(row, column, parent)) + return QModelIndex(); + const QModelIndex sourceParent = mapToSource(parent); + const QModelIndex sourceIndex = d->model->index(row, column, sourceParent); + Q_ASSERT(sourceIndex.isValid()); + return mapFromSource(sourceIndex); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::insertColumns(int column, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->insertColumns(column, count, mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::insertRows(int row, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->insertRows(row, count, mapToSource(parent)); +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::mapFromSource(const QModelIndex& sourceIndex) const +{ + Q_D(const QIdentityProxyModel); + if (!d->model || !sourceIndex.isValid()) + return QModelIndex(); + + Q_ASSERT(sourceIndex.model() == d->model); + return createIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer()); +} + +/*! + \reimp + */ +QItemSelection QIdentityProxyModel::mapSelectionFromSource(const QItemSelection& selection) const +{ + Q_D(const QIdentityProxyModel); + QItemSelection proxySelection; + + if (!d->model) + return proxySelection; + + QItemSelection::const_iterator it = selection.constBegin(); + const QItemSelection::const_iterator end = selection.constEnd(); + for ( ; it != end; ++it) { + Q_ASSERT(it->model() == d->model); + const QItemSelectionRange range(mapFromSource(it->topLeft()), mapFromSource(it->bottomRight())); + proxySelection.append(range); + } + + return proxySelection; +} + +/*! + \reimp + */ +QItemSelection QIdentityProxyModel::mapSelectionToSource(const QItemSelection& selection) const +{ + Q_D(const QIdentityProxyModel); + QItemSelection sourceSelection; + + if (!d->model) + return sourceSelection; + + QItemSelection::const_iterator it = selection.constBegin(); + const QItemSelection::const_iterator end = selection.constEnd(); + for ( ; it != end; ++it) { + Q_ASSERT(it->model() == this); + const QItemSelectionRange range(mapToSource(it->topLeft()), mapToSource(it->bottomRight())); + sourceSelection.append(range); + } + + return sourceSelection; +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::mapToSource(const QModelIndex& proxyIndex) const +{ + Q_D(const QIdentityProxyModel); + if (!d->model || !proxyIndex.isValid()) + return QModelIndex(); + Q_ASSERT(proxyIndex.model() == this); + return d->model->createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer()); +} + +/*! + \reimp + */ +QModelIndexList QIdentityProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const +{ + Q_D(const QIdentityProxyModel); + Q_ASSERT(start.isValid() ? start.model() == this : true); + if (!d->model) + return QModelIndexList(); + + const QModelIndexList sourceList = d->model->match(mapToSource(start), role, value, hits, flags); + QModelIndexList::const_iterator it = sourceList.constBegin(); + const QModelIndexList::const_iterator end = sourceList.constEnd(); + QModelIndexList proxyList; + for ( ; it != end; ++it) + proxyList.append(mapFromSource(*it)); + return proxyList; +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::parent(const QModelIndex& child) const +{ + Q_ASSERT(child.isValid() ? child.model() == this : true); + const QModelIndex sourceIndex = mapToSource(child); + const QModelIndex sourceParent = sourceIndex.parent(); + return mapFromSource(sourceParent); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::removeColumns(int column, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->removeColumns(column, count, mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::removeRows(int row, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->removeRows(row, count, mapToSource(parent)); +} + +/*! + \reimp + */ +int QIdentityProxyModel::rowCount(const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + return d->model->rowCount(mapToSource(parent)); +} + +/*! + \reimp + */ +void QIdentityProxyModel::setSourceModel(QAbstractItemModel* sourceModel) +{ + beginResetModel(); + + if (sourceModel) { + disconnect(sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsAboutToBeInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsAboutToBeRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceColumnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceColumnsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(modelAboutToBeReset()), + this, SLOT(_q_sourceModelAboutToBeReset())); + disconnect(sourceModel, SIGNAL(modelReset()), + this, SLOT(_q_sourceModelReset())); + disconnect(sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(_q_sourceDataChanged(const QModelIndex &, const QModelIndex &))); + disconnect(sourceModel, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), + this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); + disconnect(sourceModel, SIGNAL(layoutAboutToBeChanged()), + this, SLOT(_q_sourceLayoutAboutToBeChanged())); + disconnect(sourceModel, SIGNAL(layoutChanged()), + this, SLOT(_q_sourceLayoutChanged())); + } + + QAbstractProxyModel::setSourceModel(sourceModel); + + if (sourceModel) { + connect(sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsAboutToBeInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceColumnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceColumnsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(modelAboutToBeReset()), + SLOT(_q_sourceModelAboutToBeReset())); + connect(sourceModel, SIGNAL(modelReset()), + SLOT(_q_sourceModelReset())); + connect(sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + SLOT(_q_sourceDataChanged(const QModelIndex &, const QModelIndex &))); + connect(sourceModel, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), + SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); + connect(sourceModel, SIGNAL(layoutAboutToBeChanged()), + SLOT(_q_sourceLayoutAboutToBeChanged())); + connect(sourceModel, SIGNAL(layoutChanged()), + SLOT(_q_sourceLayoutChanged())); + } + + endResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginInsertColumns(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginMoveColumns(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginRemoveColumns(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endInsertColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(sourceParent) + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destParent) + Q_UNUSED(dest) + q->endMoveColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endRemoveColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + Q_ASSERT(topLeft.isValid() ? topLeft.model() == model : true); + Q_ASSERT(bottomRight.isValid() ? bottomRight.model() == model : true); + Q_Q(QIdentityProxyModel); + q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight)); +} + +void QIdentityProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last) +{ + Q_Q(QIdentityProxyModel); + q->headerDataChanged(orientation, first, last); +} + +void QIdentityProxyModelPrivate::_q_sourceLayoutAboutToBeChanged() +{ + if (ignoreNextLayoutAboutToBeChanged) + return; + + Q_Q(QIdentityProxyModel); + + foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) { + proxyIndexes << proxyPersistentIndex; + Q_ASSERT(proxyPersistentIndex.isValid()); + const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex); + Q_ASSERT(srcPersistentIndex.isValid()); + layoutChangePersistentIndexes << srcPersistentIndex; + } + + q->layoutAboutToBeChanged(); +} + +void QIdentityProxyModelPrivate::_q_sourceLayoutChanged() +{ + if (ignoreNextLayoutChanged) + return; + + Q_Q(QIdentityProxyModel); + + for (int i = 0; i < proxyIndexes.size(); ++i) { + q->changePersistentIndex(proxyIndexes.at(i), q->mapFromSource(layoutChangePersistentIndexes.at(i))); + } + + layoutChangePersistentIndexes.clear(); + proxyIndexes.clear(); + + q->layoutChanged(); +} + +void QIdentityProxyModelPrivate::_q_sourceModelAboutToBeReset() +{ + Q_Q(QIdentityProxyModel); + q->beginResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceModelReset() +{ + Q_Q(QIdentityProxyModel); + q->endResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginInsertRows(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginMoveRows(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginRemoveRows(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endInsertRows(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(sourceParent) + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destParent) + Q_UNUSED(dest) + q->endMoveRows(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endRemoveRows(); +} + +QT_END_NAMESPACE + +#include "moc_qidentityproxymodel.cpp" + +#endif // QT_NO_IDENTITYPROXYMODEL diff --git a/src/gui/itemviews/qidentityproxymodel.h b/src/gui/itemviews/qidentityproxymodel.h new file mode 100644 index 0000000..4b3176a --- /dev/null +++ b/src/gui/itemviews/qidentityproxymodel.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QIDENTITYPROXYMODEL_H +#define QIDENTITYPROXYMODEL_H + +#include <QtGui/qabstractproxymodel.h> + +#ifndef QT_NO_IDENTITYPROXYMODEL + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QIdentityProxyModelPrivate; + +class Q_GUI_EXPORT QIdentityProxyModel : public QAbstractProxyModel +{ + Q_OBJECT +public: + explicit QIdentityProxyModel(QObject* parent = 0); + ~QIdentityProxyModel(); + + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; + QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; + QModelIndex mapToSource(const QModelIndex& proxyIndex) const; + QModelIndex parent(const QModelIndex& child) const; + int rowCount(const QModelIndex& parent = QModelIndex()) const; + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); + + QItemSelection mapSelectionFromSource(const QItemSelection& selection) const; + QItemSelection mapSelectionToSource(const QItemSelection& selection) const; + QModelIndexList match(const QModelIndex& start, int role, const QVariant& value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const; + void setSourceModel(QAbstractItemModel* sourceModel); + + bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()); + bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()); + bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()); + bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()); + +protected: + QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent); + +private: + Q_DECLARE_PRIVATE(QIdentityProxyModel) + Q_DISABLE_COPY(QIdentityProxyModel) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceDataChanged(QModelIndex,QModelIndex)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceModelAboutToBeReset()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceModelReset()) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_IDENTITYPROXYMODEL + +#endif // QIDENTITYPROXYMODEL_H + diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp index 27a4a40..0b64452 100644 --- a/src/gui/itemviews/qitemselectionmodel.cpp +++ b/src/gui/itemviews/qitemselectionmodel.cpp @@ -1145,11 +1145,8 @@ void QItemSelectionModel::clearSelection() Q_D(QItemSelectionModel); if (d->ranges.count() == 0 && d->currentSelection.count() == 0) return; - QItemSelection selection = d->ranges; - selection.merge(d->currentSelection, d->currentCommand); - d->ranges.clear(); - d->currentSelection.clear(); - emit selectionChanged(QItemSelection(), selection); + + select(QItemSelection(), Clear); } diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index eb56f56..f73607b 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -1502,7 +1502,7 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved( \l{Model Subclassing Reference}. \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming}, - {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example} + {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example}, QIdentityProxyModel */ /*! diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index e494ee5..59a3d15 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -1104,6 +1104,21 @@ void QTableView::setRootIndex(const QModelIndex &index) /*! \reimp */ +void QTableView::doItemsLayout() +{ + Q_D(QTableView); + QAbstractItemView::doItemsLayout(); + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) + d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value()); + else + d->verticalHeader->setOffset(verticalScrollBar()->value()); + if (!d->verticalHeader->updatesEnabled()) + d->verticalHeader->setUpdatesEnabled(true); +} + +/*! + \reimp +*/ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel) { Q_D(QTableView); @@ -1975,9 +1990,13 @@ QModelIndexList QTableView::selectedIndexes() const previous number of rows is specified by \a oldCount, and the new number of rows is specified by \a newCount. */ -void QTableView::rowCountChanged(int /*oldCount*/, int /*newCount*/ ) +void QTableView::rowCountChanged(int oldCount, int newCount ) { Q_D(QTableView); + //when removing rows, we need to disable updates for the header until the geometries have been + //updated and the offset has been adjusted, or we risk calling paintSection for all the sections + if (newCount < oldCount) + d->verticalHeader->setUpdatesEnabled(false); d->doDelayedItemsLayout(); } diff --git a/src/gui/itemviews/qtableview.h b/src/gui/itemviews/qtableview.h index d4be086..7ab9d08 100644 --- a/src/gui/itemviews/qtableview.h +++ b/src/gui/itemviews/qtableview.h @@ -71,6 +71,7 @@ public: void setModel(QAbstractItemModel *model); void setRootIndex(const QModelIndex &index); void setSelectionModel(QItemSelectionModel *selectionModel); + void doItemsLayout(); QHeaderView *horizontalHeader() const; QHeaderView *verticalHeader() const; diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 0a03397..6658300 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -2361,8 +2361,13 @@ extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wPa #ifndef QT_NO_ACCESSIBILITY case WM_GETOBJECT: { + /* On Win64, lParam can be 0x00000000fffffffc or 0xfffffffffffffffc (!), + but MSDN says that lParam should be converted to a DWORD + before its compared against OBJID_CLIENT + */ + const DWORD dwObjId = (DWORD)lParam; // Ignoring all requests while starting up - if (QApplication::startingUp() || QApplication::closingDown() || lParam != (LPARAM)OBJID_CLIENT) { + if (QApplication::startingUp() || QApplication::closingDown() || dwObjId != OBJID_CLIENT) { result = false; break; } diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 5705214..c5ea239 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -11205,6 +11205,7 @@ void QWidget::setAccessibleName(const QString &name) { Q_D(QWidget); d->accessibleName = name; + QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged); } QString QWidget::accessibleName() const @@ -11226,6 +11227,7 @@ void QWidget::setAccessibleDescription(const QString &description) { Q_D(QWidget); d->accessibleDescription = description; + QAccessible::updateAccessibility(this, 0, QAccessible::DescriptionChanged); } QString QWidget::accessibleDescription() const diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index 8f99d6a..3d04c9a 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -223,16 +223,13 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q --yy; } if (!(opt->state & State_Enabled) && !(opt->state & State_On)) { - int pnt; - p->setPen(opt->palette.highlightedText().color()); - QPoint offset(1, 1); - for (pnt = 0; pnt < a.size(); ++pnt) - a[pnt].translate(offset.x(), offset.y()); + p->save(); + p->translate(1, 1); + p->setPen(opt->palette.light().color()); p->drawLines(a); - for (pnt = 0; pnt < a.size(); ++pnt) - a[pnt].translate(offset.x(), offset.y()); + p->restore(); } - p->setPen(opt->palette.text().color()); + p->setPen((opt->state & State_On) ? opt->palette.highlightedText().color() : opt->palette.text().color()); p->drawLines(a); break; } case PE_Frame: diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index 2d21628..18003ce 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -4707,7 +4707,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex HIThemeFrameDrawInfo fdi; fdi.version = qt_mac_hitheme_version; - fdi.state = kThemeStateInactive; + fdi.state = tds; fdi.kind = kHIThemeFrameTextFieldSquare; fdi.isFocused = false; HIRect hirect = qt_hirectForQRect(lineeditRect); diff --git a/src/gui/styles/qwindowsstyle.cpp b/src/gui/styles/qwindowsstyle.cpp index 44f3f92..1dcfd00 100644 --- a/src/gui/styles/qwindowsstyle.cpp +++ b/src/gui/styles/qwindowsstyle.cpp @@ -1858,8 +1858,8 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai } QRect vCheckRect = visualRect(opt->direction, menuitem->rect, QRect(menuitem->rect.x(), menuitem->rect.y(), checkcol, menuitem->rect.height())); - if (checked) { - if (act && !dis) { + if (!menuitem->icon.isNull() && checked) { + if (act) { qDrawShadePanel(p, vCheckRect, menuitem->palette, true, 1, &menuitem->palette.brush(QPalette::Button)); diff --git a/src/gui/styles/qwindowsvistastyle.cpp b/src/gui/styles/qwindowsvistastyle.cpp index 7f1a3ab..123741e 100644 --- a/src/gui/styles/qwindowsvistastyle.cpp +++ b/src/gui/styles/qwindowsvistastyle.cpp @@ -969,7 +969,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) { - if (QWindowsVistaAnimation *anim = d->widgetAnimation(widget)) { + QWindowsVistaAnimation *anim = d->widgetAnimation(widget); + if (anim && (btn->state & State_Enabled)) { anim->paint(painter, option); } else { name = QLatin1String("BUTTON"); @@ -996,7 +997,6 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) && (state & State_Enabled) && (state & State_Active)) { - QWindowsVistaAnimation *anim = d->widgetAnimation(widget); if (!anim && widget) { QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); startImage.fill(0); @@ -1074,8 +1074,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption } if (const QProgressBar *progressbar = qobject_cast<const QProgressBar *>(widget)) { - if (((progressbar->value() > 0 && d->transitionsEnabled()) || isIndeterminate)) { - if (!d->widgetAnimation(progressbar) && progressbar->value() < progressbar->maximum()) { + if (isIndeterminate || (progressbar->value() > 0 && (progressbar->value() < progressbar->maximum()) && d->transitionsEnabled())) { + if (!d->widgetAnimation(progressbar)) { QWindowsVistaAnimation *a = new QWindowsVistaAnimation; a->setWidget(const_cast<QWidget*>(widget)); a->setStartTime(QTime::currentTime()); @@ -2502,7 +2502,6 @@ void QWindowsVistaStylePrivate::timerEvent() animations[i]->widget()->update(); if (!animations[i]->widget() || - !animations[i]->widget()->isEnabled() || !animations[i]->widget()->isVisible() || animations[i]->widget()->window()->isMinimized() || !animations[i]->running() || diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp index 74a20fc..4b2c3a5 100644 --- a/src/gui/styles/qwindowsxpstyle.cpp +++ b/src/gui/styles/qwindowsxpstyle.cpp @@ -1196,8 +1196,14 @@ QRect QWindowsXPStyle::subElementRect(SubElement sr, const QStyleOption *option, if (qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) { rect = QWindowsStyle::subElementRect(sr, option, widget); - if (sr == SE_TabWidgetTabContents) - rect.adjust(0, 0, -2, -2); + if (sr == SE_TabWidgetTabContents) { + if (const QTabWidget *tabWidget = qobject_cast<const QTabWidget *>(widget)) { + if (tabWidget->documentMode()) + break; + } + + rect.adjust(0, 0, -2, -2); + } } break; case SE_TabWidgetTabBar: { diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 289faa9..ced66e5 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -651,7 +651,12 @@ void QLineControl::internalSetText(const QString &txt, int pos, bool edited) m_modifiedState = m_undoState = 0; m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos; m_textDirty = (oldText != m_text); - finishChange(-1, true, edited); + bool changed = finishChange(-1, true, edited); + +#ifndef QT_NO_ACCESSIBILITY + if (changed) + QAccessible::updateAccessibility(parent(), 0, QAccessible::TextUpdated); +#endif } @@ -1238,6 +1243,9 @@ void QLineControl::emitCursorPositionChanged() const int oldLast = m_lastCursorPos; m_lastCursorPos = m_cursor; cursorPositionChanged(oldLast, m_cursor); +#ifndef QT_NO_ACCESSIBILITY + QAccessible::updateAccessibility(parent(), 0, QAccessible::TextCaretMoved); +#endif } } diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 3c505c8..7f3cad6 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -61,10 +61,10 @@ #include "QtGui/qtextlayout.h" #include "QtGui/qstyleoption.h" #include "QtCore/qpointer.h" -#include "QtGui/qlineedit.h" #include "QtGui/qclipboard.h" #include "QtCore/qpoint.h" #include "QtGui/qcompleter.h" +#include "QtGui/qaccessible.h" QT_BEGIN_HEADER diff --git a/src/gui/widgets/qlineedit_p.cpp b/src/gui/widgets/qlineedit_p.cpp index 23ac613..03716d4 100644 --- a/src/gui/widgets/qlineedit_p.cpp +++ b/src/gui/widgets/qlineedit_p.cpp @@ -153,6 +153,7 @@ void QLineEditPrivate::init(const QString& txt) { Q_Q(QLineEdit); control = new QLineControl(txt); + control->setParent(q); control->setFont(q->font()); QObject::connect(control, SIGNAL(textChanged(QString)), q, SIGNAL(textChanged(QString))); diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index 32f6077..3169776 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -84,7 +84,6 @@ public: ~QLineEditPrivate() { - delete control; } QLineControl *control; diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index b12e5c5..b0ea00f 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -228,6 +228,12 @@ QList<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const void QMenuPrivate::updateActionRects() const { Q_Q(const QMenu); + updateActionRects(popupGeometry(q)); +} + +void QMenuPrivate::updateActionRects(const QRect &screen) const +{ + Q_Q(const QMenu); if (!itemsDirty) return; @@ -237,20 +243,10 @@ void QMenuPrivate::updateActionRects() const actionRects.resize(actions.count()); actionRects.fill(QRect()); - //let's try to get the last visible action - int lastVisibleAction = actions.count() - 1; - for(;lastVisibleAction >= 0; --lastVisibleAction) { - const QAction *action = actions.at(lastVisibleAction); - if (action->isVisible()) { - //removing trailing separators - if (action->isSeparator() && collapsibleSeparators) - continue; - break; - } - } + int lastVisibleAction = getLastVisibleAction(); int max_column_width = 0, - dh = popupGeometry(q).height(), + dh = screen.height(), y = 0; QStyle *style = q->style(); QStyleOption opt; @@ -351,7 +347,6 @@ void QMenuPrivate::updateActionRects() const const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin)); max_column_width = qMax(min_column_width, max_column_width); - //calculate position const int base_y = vmargin + fw + topmargin + (scroll ? scroll->scrollOffset : 0) + @@ -382,6 +377,34 @@ void QMenuPrivate::updateActionRects() const itemsDirty = 0; } +QSize QMenuPrivate::adjustMenuSizeForScreen(const QRect &screen) +{ + Q_Q(QMenu); + QSize ret = screen.size(); + itemsDirty = true; + updateActionRects(screen); + const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q); + ret.setWidth(actionRects.at(getLastVisibleAction()).right() + fw); + return ret; +} + +int QMenuPrivate::getLastVisibleAction() const +{ + //let's try to get the last visible action + int lastVisibleAction = actions.count() - 1; + for (;lastVisibleAction >= 0; --lastVisibleAction) { + const QAction *action = actions.at(lastVisibleAction); + if (action->isVisible()) { + //removing trailing separators + if (action->isSeparator() && collapsibleSeparators) + continue; + break; + } + } + return lastVisibleAction; +} + + QRect QMenuPrivate::actionRect(QAction *act) const { int index = actions.indexOf(act); @@ -1813,9 +1836,20 @@ void QMenu::popup(const QPoint &p, QAction *atAction) else #endif screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); - const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this); bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen); + + // if the screens have very different geometries and the menu is too big, we have to recalculate + if (size.height() > screen.height() || size.width() > screen.width()) { + size = d->adjustMenuSizeForScreen(screen); + adjustToDesktop = true; + } + // Layout is not right, we might be able to save horizontal space + if (d->ncols >1 && size.height() < screen.height()) { + size = d->adjustMenuSizeForScreen(screen); + adjustToDesktop = true; + } + #ifdef QT_KEYPAD_NAVIGATION if (!atAction && QApplication::keypadNavigationEnabled()) { // Try to have one item activated @@ -1909,6 +1943,27 @@ void QMenu::popup(const QPoint &p, QAction *atAction) } } } + const int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this); + const QSize menuSize(sizeHint()); + QMenu *caused = qobject_cast<QMenu*>(d_func()->causedPopup.widget); + if (caused && caused->geometry().width() + menuSize.width() + subMenuOffset < screen.width()) { + QRect parentActionRect(caused->d_func()->actionRect(caused->d_func()->currentAction)); + const QPoint actionTopLeft = caused->mapToGlobal(parentActionRect.topLeft()); + parentActionRect.moveTopLeft(actionTopLeft); + if (isRightToLeft()) { + if ((pos.x() + menuSize.width() > parentActionRect.left() - subMenuOffset) + && (pos.x() < parentActionRect.right())) + { + pos.rx() = parentActionRect.right(); + } + } else { + if ((pos.x() < parentActionRect.right() + subMenuOffset) + && (pos.x() + menuSize.width() > parentActionRect.left())) + { + pos.rx() = parentActionRect.left() - menuSize.width(); + } + } + } setGeometry(QRect(pos, size)); #ifndef QT_NO_EFFECTS int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; @@ -2941,28 +2996,8 @@ void QMenu::internalDelayedPopup() const QRect actionRect(d->actionRect(d->currentAction)); const QSize menuSize(d->activeMenu->sizeHint()); const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top()))); - const QPoint leftPos(mapToGlobal(QPoint(actionRect.left() - subMenuOffset - menuSize.width(), actionRect.top()))); QPoint pos(rightPos); - QMenu *caused = qobject_cast<QMenu*>(d->activeMenu->d_func()->causedPopup.widget); - - const QRect availGeometry(d->popupGeometry(caused)); - if (isRightToLeft()) { - pos = leftPos; - if ((caused && caused->x() < x()) || pos.x() < availGeometry.left()) { - if(rightPos.x() + menuSize.width() < availGeometry.right()) - pos = rightPos; - else - pos.rx() = availGeometry.left(); - } - } else { - if ((caused && caused->x() > x()) || pos.x() + menuSize.width() > availGeometry.right()) { - if(leftPos.x() < availGeometry.left()) - pos.rx() = availGeometry.right() - menuSize.width(); - else - pos = leftPos; - } - } //calc sloppy focus buffer if (style()->styleHint(QStyle::SH_Menu_SloppySubMenus, 0, this)) { diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index b6efde3..005ce1d 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -194,10 +194,13 @@ public: mutable QVector<QRect> actionRects; mutable QHash<QAction *, QWidget *> widgetItems; void updateActionRects() const; + void updateActionRects(const QRect &screen) const; QRect popupGeometry(const QWidget *widget) const; QRect popupGeometry(int screen = -1) const; mutable uint ncols : 4; //4 bits is probably plenty uint collapsibleSeparators : 1; + QSize adjustMenuSizeForScreen(const QRect & screen); + int getLastVisibleAction() const; bool activationRecursionGuard; @@ -296,7 +299,6 @@ public: void updateLayoutDirection(); - //menu fading/scrolling effects bool doChildEffects; diff --git a/src/plugins/accessible/widgets/complexwidgets.cpp b/src/plugins/accessible/widgets/complexwidgets.cpp index e638413..85be0b0 100644 --- a/src/plugins/accessible/widgets/complexwidgets.cpp +++ b/src/plugins/accessible/widgets/complexwidgets.cpp @@ -971,7 +971,11 @@ QString QAccessibleItemView::text(Text t, int child) const return QAccessibleAbstractScrollArea::text(t, child); QAccessibleItemRow item(itemView(), childIndex(child)); - return item.text(t, 1); + if (item.isValid()) { + return item.text(t, 1); + } else { + return QString(); + } } else { return QAccessibleAbstractScrollArea::text(t, child); } diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp index 09b5015..4402932 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -401,9 +401,14 @@ int QAccessibleStackedWidget::childCount() const int QAccessibleStackedWidget::indexOfChild(const QAccessibleInterface *child) const { - if (!child || (stackedWidget()->currentWidget() != child->object())) + if (!child) return -1; - return 1; + + QWidget* widget = qobject_cast<QWidget*>(child->object()); + int index = stackedWidget()->indexOf(widget); + if (index >= 0) // one based counting of children + return index + 1; + return -1; } int QAccessibleStackedWidget::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const @@ -413,9 +418,9 @@ int QAccessibleStackedWidget::navigate(RelationFlag relation, int entry, QAccess QObject *targetObject = 0; switch (relation) { case Child: - if (entry != 1) + if (entry < 1 || entry > stackedWidget()->count()) return -1; - targetObject = stackedWidget()->currentWidget(); + targetObject = stackedWidget()->widget(entry-1); break; default: return QAccessibleWidgetEx::navigate(relation, entry, target); @@ -1334,7 +1339,7 @@ QRect QAccessibleTextEdit::characterRect(int offset, CoordinateType coordType) QRect r = edit->cursorRect(cursor); if (cursor.movePosition(QTextCursor::NextCharacter)) { - r.setWidth(edit->cursorRect(cursor).y() - r.y()); + r.setWidth(edit->cursorRect(cursor).x() - r.x()); } else { // we don't know the width of the character - maybe because we're at document end // in that case, IAccessible2 tells us to return the width of a default character @@ -1603,7 +1608,7 @@ void QAccessibleTextEdit::setAttributes(int startOffset, int endOffset, const QS #ifndef QT_NO_MAINWINDOW QAccessibleMainWindow::QAccessibleMainWindow(QWidget *widget) - : QAccessibleWidgetEx(widget, Application) { } + : QAccessibleWidgetEx(widget, Window) { } QVariant QAccessibleMainWindow::invokeMethodEx(QAccessible::Method /*method*/, int /*child*/, const QVariantList & /*params*/) { diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp index 21d2d67..aa64630 100644 --- a/src/plugins/accessible/widgets/simplewidgets.cpp +++ b/src/plugins/accessible/widgets/simplewidgets.cpp @@ -131,7 +131,7 @@ QString QAccessibleButton::actionText(int action, Text text, int child) const /*! \reimp */ bool QAccessibleButton::doAction(int action, int child, const QVariantList ¶ms) { - if (child || !widget()->isEnabled() || !widget()->isVisible()) + if (child || !widget()->isEnabled()) return false; switch (action) { @@ -155,9 +155,6 @@ bool QAccessibleButton::doAction(int action, int child, const QVariantList ¶ QString QAccessibleButton::text(Text t, int child) const { QString str; - if (!widget()->isVisible()) - return str; - switch (t) { case Accelerator: { @@ -227,6 +224,9 @@ QString QAccessibleButton::description(int actionIndex) { switch (actionIndex) { case 0: + if (button()->isCheckable()) { + return QLatin1String("Toggles the button."); + } return QLatin1String("Clicks the button."); default: return QString(); @@ -237,6 +237,13 @@ QString QAccessibleButton::name(int actionIndex) { switch (actionIndex) { case 0: + if (button()->isCheckable()) { + if (button()->isChecked()) { + return QLatin1String("Uncheck"); + } else { + return QLatin1String("Check"); + } + } return QLatin1String("Press"); default: return QString(); @@ -247,6 +254,13 @@ QString QAccessibleButton::localizedName(int actionIndex) { switch (actionIndex) { case 0: + if (button()->isCheckable()) { + if (button()->isChecked()) { + return tr("Uncheck"); + } else { + return tr("Check"); + } + } return tr("Press"); default: return QString(); @@ -380,9 +394,6 @@ QRect QAccessibleToolButton::rect(int child) const QString QAccessibleToolButton::text(Text t, int child) const { QString str; - if (!toolButton()->isVisible()) - return str; - switch (t) { case Name: str = toolButton()->text(); @@ -454,7 +465,7 @@ QString QAccessibleToolButton::actionText(int action, Text text, int child) cons */ bool QAccessibleToolButton::doAction(int action, int child, const QVariantList ¶ms) { - if (!widget()->isEnabled() || !widget()->isVisible()) + if (!widget()->isEnabled()) return false; if (action == 1 || child == ButtonDropMenu) { if(!child) @@ -513,8 +524,6 @@ QAccessible::Role QAccessibleDisplay::role(int child) const QString QAccessibleDisplay::text(Text t, int child) const { QString str; - if (!widget()->isVisible()) - return str; switch (t) { case Name: str = widget()->accessibleName(); @@ -674,8 +683,6 @@ QLineEdit *QAccessibleLineEdit::lineEdit() const QString QAccessibleLineEdit::text(Text t, int child) const { QString str; - if (!lineEdit()->isVisible()) - return str; switch (t) { case Value: if (lineEdit()->echoMode() == QLineEdit::Normal) @@ -692,8 +699,6 @@ QString QAccessibleLineEdit::text(Text t, int child) const /*! \reimp */ void QAccessibleLineEdit::setText(Text t, int control, const QString &text) { - if (!lineEdit()->isVisible()) - return; if (t != Value || control) { QAccessibleWidgetEx::setText(t, control, text); return; diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro index 0d77fff..22c5e51 100644 --- a/tests/auto/gui.pro +++ b/tests/auto/gui.pro @@ -84,6 +84,7 @@ SUBDIRS=\ qheaderview \ qicoimageformat \ qicon \ + qidentityproxymodel \ qimageiohandler \ qimagereader \ qimagewriter \ diff --git a/tests/auto/headers/tst_headers.cpp b/tests/auto/headers/tst_headers.cpp index b5c65ef..b6135d0 100644 --- a/tests/auto/headers/tst_headers.cpp +++ b/tests/auto/headers/tst_headers.cpp @@ -243,6 +243,10 @@ void tst_Headers::licenseCheck() QCOMPARE(content.at(i++), QString("**")); if (sourceFile.endsWith("/tests/auto/modeltest/dynamictreemodel.cpp") || sourceFile.endsWith("/tests/auto/modeltest/dynamictreemodel.h") + || sourceFile.endsWith("/src/gui/itemviews/qidentityproxymodel.h") + || sourceFile.endsWith("/src/gui/itemviews/qidentityproxymodel.cpp") + || sourceFile.endsWith("/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp") + || sourceFile.endsWith("/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp") || sourceFile.endsWith("/src/network/kernel/qnetworkproxy_p.h")) { // These files are not copyrighted by Nokia. diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index 8d9603b..7ff1a08 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -245,10 +245,13 @@ private slots: void actionText(); void doAction(); + void applicationTest(); + void mainWindowTest(); void buttonTest(); void sliderTest(); void scrollBarTest(); void tabTest(); + void tabWidgetTest(); void menuTest(); void spinBoxTest(); void doubleSpinBoxTest(); @@ -479,6 +482,11 @@ void tst_QAccessibility::eventTest() QVERIFY_EVENT(button, 0, QAccessible::StateChanged); QVERIFY_EVENT(button, 0, QAccessible::StateChanged); + button->setAccessibleName("Olaf the second"); + QVERIFY_EVENT(button, 0, QAccessible::NameChanged); + button->setAccessibleDescription("This is a button labeled Olaf"); + QVERIFY_EVENT(button, 0, QAccessible::DescriptionChanged); + button->hide(); QVERIFY_EVENT(button, 0, QAccessible::ObjectHide); @@ -1821,49 +1829,100 @@ void tst_QAccessibility::doAction() #endif } +void tst_QAccessibility::applicationTest() +{ +#ifdef QTEST_ACCESSIBILITY + QLatin1String name = QLatin1String("My Name"); + qApp->setApplicationName(name); + QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(qApp); + QCOMPARE(interface->text(QAccessible::Name, 0), name); + QCOMPARE(interface->role(0), QAccessible::Application); + delete interface; +#else + QSKIP("Test needs accessibility support.", SkipAll); +#endif +} + +void tst_QAccessibility::mainWindowTest() +{ +#ifdef QTEST_ACCESSIBILITY + QMainWindow mw; + mw.resize(300, 200); + mw.show(); // triggers layout + + QLatin1String name = QLatin1String("I am the main window"); + mw.setWindowTitle(name); + QTest::qWaitForWindowShown(&mw); + + QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&mw); + QCOMPARE(interface->text(QAccessible::Name, 0), name); + QCOMPARE(interface->role(0), QAccessible::Window); + delete interface; + +#else + QSKIP("Test needs accessibility support.", SkipAll); +#endif +} + +class CounterButton : public QPushButton { + Q_OBJECT +public: + CounterButton(const QString& name, QWidget* parent) + : QPushButton(name, parent), clickCount(0) + { + connect(this, SIGNAL(clicked(bool)), SLOT(incClickCount())); + } + int clickCount; +public Q_SLOTS: + void incClickCount() { + ++clickCount; + } +}; + void tst_QAccessibility::buttonTest() { -//#ifdef QTEST_ACCESSIBILITY -#if 0 - QAccessibleInterface *test = 0; - Q3VBox vbox; +#ifdef QTEST_ACCESSIBILITY + QWidget window; + window.setLayout(new QVBoxLayout); // Standard push button - QPushButton pushButton("Ok", &vbox); + CounterButton pushButton("Ok", &window); - // toggle push button - QPushButton togglepush("Toggle", &vbox); - togglepush.setToggleButton(TRUE); - - // push button with a menu - QPushButton menuButton("Menu", &vbox); - Q3PopupMenu buttonMenu(&menuButton); - buttonMenu.insertItem("Some item"); - menuButton.setPopup(&buttonMenu); + // toggle button + QPushButton toggleButton("Toggle", &window); + toggleButton.setCheckable(true); // standard checkbox - QCheckBox checkBox("Check me!", &vbox); + QCheckBox checkBox("Check me!", &window); // tristate checkbox - QCheckBox tristate("Tristate!", &vbox); + QCheckBox tristate("Tristate!", &window); tristate.setTristate(TRUE); // radiobutton - QRadioButton radio("Radio me!", &vbox); + QRadioButton radio("Radio me!", &window); // standard toolbutton - QToolButton toolbutton(&vbox); + QToolButton toolbutton(&window); toolbutton.setText("Tool"); toolbutton.setMinimumSize(20,20); // standard toolbutton - QToolButton toggletool(&vbox); - toggletool.setToggleButton(TRUE); + QToolButton toggletool(&window); + toggletool.setCheckable(true); toggletool.setText("Toggle"); toggletool.setMinimumSize(20,20); +#if 0 + // QT3_SUPPORT + // push button with a menu + QPushButton menuButton("Menu", &window); + Q3PopupMenu buttonMenu(&menuButton); + buttonMenu.insertItem("Some item"); + menuButton.setPopup(&buttonMenu); + // menu toolbutton - QToolButton menuToolButton(&vbox); + QToolButton menuToolButton(&window); menuToolButton.setText("Menu Tool"); Q3PopupMenu toolMenu(&menuToolButton); toolMenu.insertItem("Some item"); @@ -1871,141 +1930,149 @@ void tst_QAccessibility::buttonTest() menuToolButton.setMinimumSize(20,20); // splitted menu toolbutton - QToolButton splitToolButton(&vbox); + QToolButton splitToolButton(&window); splitToolButton.setTextLabel("Split Tool"); Q3PopupMenu splitMenu(&splitToolButton); splitMenu.insertItem("Some item"); splitToolButton.setPopup(&splitMenu); splitToolButton.setPopupDelay(0); splitToolButton.setMinimumSize(20,20); +#endif // test push button - QVERIFY(QAccessible::queryAccessibleInterface(&pushButton, &test)); - QCOMPARE(test->role(0), QAccessible::PushButton); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - pushButton.setDown(TRUE); - QCOMPARE(test->state(0), (int)QAccessible::Pressed); - QVERIFY(test->doAction(QAccessible::Press, 0)); + QAccessibleInterface* interface = QAccessible::queryAccessibleInterface(&pushButton); + QAccessibleActionInterface* actionInterface = interface->actionInterface(); + QVERIFY(actionInterface != 0); + + QCOMPARE(interface->role(0), QAccessible::PushButton); + + // currently our buttons only have click as action, press and release are missing + QCOMPARE(actionInterface->actionCount(), 1); + QCOMPARE(actionInterface->name(0), QString("Press")); + QCOMPARE(pushButton.clickCount, 0); + actionInterface->doAction(0); QTest::qWait(500); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - test->release(); - - // test toggle push button - QVERIFY(QAccessible::queryAccessibleInterface(&togglepush, &test)); - QCOMPARE(test->role(0), QAccessible::CheckBox); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); + QCOMPARE(pushButton.clickCount, 1); + delete interface; + + // test toggle button + interface = QAccessible::queryAccessibleInterface(&toggleButton); + actionInterface = interface->actionInterface(); + QCOMPARE(interface->role(0), QAccessible::CheckBox); + QCOMPARE(actionInterface->description(0), QString("Toggles the button.")); + QCOMPARE(actionInterface->name(0), QString("Check")); + QVERIFY(!toggleButton.isChecked()); + QVERIFY((interface->state(0) & QAccessible::Checked) == 0); + actionInterface->doAction(0); QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); - - // test menu push button - QVERIFY(QAccessible::queryAccessibleInterface(&menuButton, &test)); - QCOMPARE(test->role(0), QAccessible::ButtonMenu); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open")); - QCOMPARE(test->state(0), (int)QAccessible::HasPopup); - test->release(); + QCOMPARE(actionInterface->name(0), QString("Uncheck")); + QVERIFY(toggleButton.isChecked()); + QVERIFY((interface->state(0) & QAccessible::Checked)); + delete interface; + +// // test menu push button +// QVERIFY(QAccessible::queryAccessibleInterface(&menuButton, &test)); +// QCOMPARE(test->role(0), QAccessible::ButtonMenu); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open")); +// QCOMPARE(test->state(0), (int)QAccessible::HasPopup); +// test->release(); // test check box - QVERIFY(QAccessible::queryAccessibleInterface(&checkBox, &test)); - QCOMPARE(test->role(0), QAccessible::CheckBox); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); + interface = QAccessible::queryAccessibleInterface(&checkBox); + actionInterface = interface->actionInterface(); + QCOMPARE(interface->role(0), QAccessible::CheckBox); + QCOMPARE(actionInterface->name(0), QString("Check")); + QVERIFY((interface->state(0) & QAccessible::Checked) == 0); + actionInterface->doAction(0); QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); - - // test tristate check box - QVERIFY(QAccessible::queryAccessibleInterface(&tristate, &test)); - QCOMPARE(test->role(0), QAccessible::CheckBox); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Toggle")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); - QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Mixed); - QVERIFY(test->doAction(QAccessible::Press, 0)); - QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); + QCOMPARE(actionInterface->name(0), QString("Uncheck")); + QVERIFY(interface->state(0) & QAccessible::Checked); + QVERIFY(checkBox.isChecked()); + delete interface; + +// // test tristate check box +// QVERIFY(QAccessible::queryAccessibleInterface(&tristate, &test)); +// QCOMPARE(test->role(0), QAccessible::CheckBox); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Toggle")); +// QCOMPARE(test->state(0), (int)QAccessible::Normal); +// QVERIFY(test->doAction(QAccessible::Press, 0)); +// QTest::qWait(500); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); +// QCOMPARE(test->state(0), (int)QAccessible::Mixed); +// QVERIFY(test->doAction(QAccessible::Press, 0)); +// QTest::qWait(500); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); +// QCOMPARE(test->state(0), (int)QAccessible::Checked); +// test->release(); // test radiobutton - QVERIFY(QAccessible::queryAccessibleInterface(&radio, &test)); - QCOMPARE(test->role(0), QAccessible::RadioButton); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); - QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); - - // test standard toolbutton - QVERIFY(QAccessible::queryAccessibleInterface(&toolbutton, &test)); - QCOMPARE(test->role(0), QAccessible::PushButton); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - test->release(); - - // toggle tool button - QVERIFY(QAccessible::queryAccessibleInterface(&toggletool, &test)); - QCOMPARE(test->role(0), QAccessible::CheckBox); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); + interface = QAccessible::queryAccessibleInterface(&radio); + actionInterface = interface->actionInterface(); + QCOMPARE(interface->role(0), QAccessible::RadioButton); + QCOMPARE(actionInterface->name(0), QString("Check")); + QVERIFY((interface->state(0) & QAccessible::Checked) == 0); + actionInterface->doAction(0); QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); - - // test menu toolbutton - QVERIFY(QAccessible::queryAccessibleInterface(&menuToolButton, &test)); - QCOMPARE(test->role(0), QAccessible::ButtonMenu); - QCOMPARE(test->defaultAction(0), 1); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open")); - QCOMPARE(test->state(0), (int)QAccessible::HasPopup); - QCOMPARE(test->actionCount(0), 1); - QCOMPARE(test->actionText(QAccessible::Press, QAccessible::Name, 0), QString("Press")); - test->release(); - - // test splitted menu toolbutton - QVERIFY(QAccessible::queryAccessibleInterface(&splitToolButton, &test)); - QCOMPARE(test->childCount(), 2); - QCOMPARE(test->role(0), QAccessible::ButtonDropDown); - QCOMPARE(test->role(1), QAccessible::PushButton); - QCOMPARE(test->role(2), QAccessible::ButtonMenu); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->defaultAction(1), QAccessible::Press); - QCOMPARE(test->defaultAction(2), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); - QCOMPARE(test->state(0), (int)QAccessible::HasPopup); - QCOMPARE(test->actionCount(0), 1); - QCOMPARE(test->actionText(1, QAccessible::Name, 0), QString("Open")); - QCOMPARE(test->actionText(test->defaultAction(1), QAccessible::Name, 1), QString("Press")); - QCOMPARE(test->state(1), (int)QAccessible::Normal); - QCOMPARE(test->actionText(test->defaultAction(2), QAccessible::Name, 2), QString("Open")); - QCOMPARE(test->state(2), (int)QAccessible::HasPopup); - test->release(); + QCOMPARE(actionInterface->name(0), QString("Uncheck")); + QVERIFY(interface->state(0) & QAccessible::Checked); + QVERIFY(checkBox.isChecked()); + delete interface; + +// // test standard toolbutton +// QVERIFY(QAccessible::queryAccessibleInterface(&toolbutton, &test)); +// QCOMPARE(test->role(0), QAccessible::PushButton); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); +// QCOMPARE(test->state(0), (int)QAccessible::Normal); +// test->release(); + +// // toggle tool button +// QVERIFY(QAccessible::queryAccessibleInterface(&toggletool, &test)); +// QCOMPARE(test->role(0), QAccessible::CheckBox); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); +// QCOMPARE(test->state(0), (int)QAccessible::Normal); +// QVERIFY(test->doAction(QAccessible::Press, 0)); +// QTest::qWait(500); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); +// QCOMPARE(test->state(0), (int)QAccessible::Checked); +// test->release(); + +// // test menu toolbutton +// QVERIFY(QAccessible::queryAccessibleInterface(&menuToolButton, &test)); +// QCOMPARE(test->role(0), QAccessible::ButtonMenu); +// QCOMPARE(test->defaultAction(0), 1); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open")); +// QCOMPARE(test->state(0), (int)QAccessible::HasPopup); +// QCOMPARE(test->actionCount(0), 1); +// QCOMPARE(test->actionText(QAccessible::Press, QAccessible::Name, 0), QString("Press")); +// test->release(); + +// // test splitted menu toolbutton +// QVERIFY(QAccessible::queryAccessibleInterface(&splitToolButton, &test)); +// QCOMPARE(test->childCount(), 2); +// QCOMPARE(test->role(0), QAccessible::ButtonDropDown); +// QCOMPARE(test->role(1), QAccessible::PushButton); +// QCOMPARE(test->role(2), QAccessible::ButtonMenu); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->defaultAction(1), QAccessible::Press); +// QCOMPARE(test->defaultAction(2), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); +// QCOMPARE(test->state(0), (int)QAccessible::HasPopup); +// QCOMPARE(test->actionCount(0), 1); +// QCOMPARE(test->actionText(1, QAccessible::Name, 0), QString("Open")); +// QCOMPARE(test->actionText(test->defaultAction(1), QAccessible::Name, 1), QString("Press")); +// QCOMPARE(test->state(1), (int)QAccessible::Normal); +// QCOMPARE(test->actionText(test->defaultAction(2), QAccessible::Name, 2), QString("Open")); +// QCOMPARE(test->state(2), (int)QAccessible::HasPopup); +// test->release(); QTestAccessibility::clearEvents(); #else -// QSKIP("Test needs accessibility support.", SkipAll); - QSKIP("No action interface in Qt 4 yet.", SkipAll); + QSKIP("Test needs accessibility support.", SkipAll); #endif } @@ -2350,6 +2417,99 @@ void tst_QAccessibility::tabTest() #endif } +void tst_QAccessibility::tabWidgetTest() +{ +#ifdef QTEST_ACCESSIBILITY + QTabWidget *tabWidget = new QTabWidget(); + tabWidget->show(); + + // the interface for the tab is just a container for tabbar and stacked widget + QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(tabWidget); + QVERIFY(interface); + QCOMPARE(interface->childCount(), 2); + QCOMPARE(interface->role(0), QAccessible::Client); + + // Create pages, check navigation + QLabel *label1 = new QLabel("Page 1", tabWidget); + tabWidget->addTab(label1, "Tab 1"); + QLabel *label2 = new QLabel("Page 2", tabWidget); + tabWidget->addTab(label2, "Tab 2"); + + QCOMPARE(interface->childCount(), 2); + + QAccessibleInterface* tabBarInterface = 0; + // there is no special logic to sort the children, so the contents will be 1, the tab bar 2 + QCOMPARE(interface->navigate(QAccessible::Child, 2 , &tabBarInterface), 0); + QVERIFY(tabBarInterface); + QCOMPARE(tabBarInterface->childCount(), 4); + QCOMPARE(tabBarInterface->role(0), QAccessible::PageTabList); + + QAccessibleInterface* tabButton1Interface = 0; + QCOMPARE(tabBarInterface->navigate(QAccessible::Child, 1 , &tabButton1Interface), 1); + QVERIFY(tabButton1Interface == 0); + + QCOMPARE(tabBarInterface->role(1), QAccessible::PageTab); + QCOMPARE(tabBarInterface->text(QAccessible::Name, 1), QLatin1String("Tab 1")); + QCOMPARE(tabBarInterface->role(2), QAccessible::PageTab); + QCOMPARE(tabBarInterface->text(QAccessible::Name, 2), QLatin1String("Tab 2")); + QCOMPARE(tabBarInterface->role(3), QAccessible::PushButton); + QCOMPARE(tabBarInterface->text(QAccessible::Name, 3), QLatin1String("Scroll Left")); + QCOMPARE(tabBarInterface->role(4), QAccessible::PushButton); + QCOMPARE(tabBarInterface->text(QAccessible::Name, 4), QLatin1String("Scroll Right")); + + QAccessibleInterface* stackWidgetInterface = 0; + QCOMPARE(interface->navigate(QAccessible::Child, 1, &stackWidgetInterface), 0); + QVERIFY(stackWidgetInterface); + QCOMPARE(stackWidgetInterface->childCount(), 2); + QCOMPARE(stackWidgetInterface->role(0), QAccessible::LayeredPane); + + QAccessibleInterface* stackChild1Interface = 0; + QCOMPARE(stackWidgetInterface->navigate(QAccessible::Child, 1, &stackChild1Interface), 0); + QVERIFY(stackChild1Interface); +#ifndef Q_CC_INTEL + QCOMPARE(stackChild1Interface->childCount(), 0); +#endif + QCOMPARE(stackChild1Interface->role(0), QAccessible::StaticText); + QCOMPARE(stackChild1Interface->text(QAccessible::Name, 0), QLatin1String("Page 1")); + QCOMPARE(label1, stackChild1Interface->object()); + + // Navigation in stack widgets should be consistent + QAccessibleInterface* parent = 0; + QCOMPARE(stackChild1Interface->navigate(QAccessible::Ancestor, 1, &parent), 0); + QVERIFY(parent); +#ifndef Q_CC_INTEL + QCOMPARE(parent->childCount(), 2); +#endif + QCOMPARE(parent->role(0), QAccessible::LayeredPane); + delete parent; + + QAccessibleInterface* stackChild2Interface = 0; + QCOMPARE(stackWidgetInterface->navigate(QAccessible::Child, 2, &stackChild2Interface), 0); + QVERIFY(stackChild2Interface); + QCOMPARE(stackChild2Interface->childCount(), 0); + QCOMPARE(stackChild2Interface->role(0), QAccessible::StaticText); + QCOMPARE(label2, stackChild2Interface->object()); // the text will be empty since it is not visible + + QCOMPARE(stackChild2Interface->navigate(QAccessible::Ancestor, 1, &parent), 0); + QVERIFY(parent); +#ifndef Q_CC_INTEL + QCOMPARE(parent->childCount(), 2); +#endif + QCOMPARE(parent->role(0), QAccessible::LayeredPane); + delete parent; + + delete tabBarInterface; + delete stackChild1Interface; + delete stackChild2Interface; + delete stackWidgetInterface; + delete interface; + delete tabWidget; + QTestAccessibility::clearEvents(); +#else + QSKIP("Test needs accessibility support.", SkipAll); +#endif +} + void tst_QAccessibility::menuTest() { #ifdef QTEST_ACCESSIBILITY @@ -2679,6 +2839,11 @@ void tst_QAccessibility::textEditTest() QCOMPARE(iface->text(QAccessible::Value, 4), QString("hello world")); QCOMPARE(iface->text(QAccessible::Value, 5), QString("how are you today?")); QCOMPARE(iface->text(QAccessible::Value, 6), QString()); + QCOMPARE(iface->textInterface()->characterCount(), 31); + QFontMetrics fm(edit.font()); + QCOMPARE(iface->textInterface()->characterRect(0, QAccessible2::RelativeToParent).size(), QSize(fm.width("h"), fm.height())); + QCOMPARE(iface->textInterface()->characterRect(5, QAccessible2::RelativeToParent).size(), QSize(fm.width(" "), fm.height())); + QCOMPARE(iface->textInterface()->characterRect(6, QAccessible2::RelativeToParent).size(), QSize(fm.width("w"), fm.height())); } QTestAccessibility::clearEvents(); #else @@ -3883,10 +4048,10 @@ void tst_QAccessibility::pushButtonTest() QAccessibleInterface *acc; QAccessibleInterface *acc2; int entry = accToplevel->childAt(pt.x(), pt.y()); - int child = accToplevel->navigate(QAccessible::Child, entry, &acc); + accToplevel->navigate(QAccessible::Child, entry, &acc); if (acc) { entry = acc->childAt(pt.x(), pt.y()); - child = acc->navigate(QAccessible::Child, entry, &acc2); + acc->navigate(QAccessible::Child, entry, &acc2); delete acc; acc = acc2; } diff --git a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp index 53781c9..e8d0f57 100644 --- a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -632,7 +632,12 @@ void tst_QFileSystemModel::filters_data() QTest::addColumn<int>("rowCount"); #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) QTest::newRow("no dirs") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs) << QStringList() << 2; - QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 1; + QTest::newRow("no dirs - dotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dotanddotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 0; + QTest::newRow("one dir - dot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 2; + QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 2; + QTest::newRow("one dir - dotanddotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; QTest::newRow("one dir") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs) << QStringList() << 3; QTest::newRow("no dir + hidden") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::Hidden) << QStringList() << 2; QTest::newRow("dir+hid+files") << (QStringList() << "a" << "b" << "c") << QStringList() << @@ -650,7 +655,12 @@ void tst_QFileSystemModel::filters_data() #else QTest::qWait(3000); // We need to calm down a bit... QTest::newRow("no dirs") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs) << QStringList() << 0; - QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 1; + QTest::newRow("no dirs - dotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dotanddotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 0; + QTest::newRow("one dir - dot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 2; + QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 2; + QTest::newRow("one dir - dotanddotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; QTest::newRow("one dir") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs) << QStringList() << 1; QTest::newRow("no dir + hidden") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::Hidden) << QStringList() << 0; QTest::newRow("dir+hid+files") << (QStringList() << "a" << "b" << "c") << QStringList() << @@ -699,10 +709,23 @@ void tst_QFileSystemModel::filters() // Make sure that we do what QDir does QDir xFactor(tmp); QDir::Filters filters = (QDir::Filters)dirFilters; + QStringList dirEntries; + if (nameFilters.count() > 0) - QCOMPARE(xFactor.entryList(nameFilters, filters).count(), rowCount); + dirEntries = xFactor.entryList(nameFilters, filters); else - QVERIFY(xFactor.entryList(filters).count() == rowCount); + dirEntries = xFactor.entryList(filters); + + QCOMPARE(dirEntries.count(), rowCount); + + QStringList modelEntries; + + for (int i = 0; i < rowCount; ++i) + modelEntries.append(model->data(model->index(i, 0, root), QFileSystemModel::FileNameRole).toString()); + + qSort(dirEntries); + qSort(modelEntries); + QCOMPARE(dirEntries, modelEntries); #ifdef Q_OS_LINUX if (files.count() >= 3 && rowCount >= 3 && rowCount != 5) { diff --git a/tests/auto/qidentityproxymodel/qidentityproxymodel.pro b/tests/auto/qidentityproxymodel/qidentityproxymodel.pro new file mode 100644 index 0000000..f529e20 --- /dev/null +++ b/tests/auto/qidentityproxymodel/qidentityproxymodel.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +INCLUDEPATH += $$PWD/../modeltest + +SOURCES += tst_qidentityproxymodel.cpp ../modeltest/dynamictreemodel.cpp ../modeltest/modeltest.cpp +HEADERS += ../modeltest/dynamictreemodel.h ../modeltest/modeltest.h diff --git a/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp b/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp new file mode 100644 index 0000000..cfc3f1a --- /dev/null +++ b/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include "../../shared/util.h" + +#include <QtCore> +#include <QtGui> + +#include "dynamictreemodel.h" +#include "qidentityproxymodel.h" + +//TESTED CLASS= +//TESTED_FILES= + +Q_DECLARE_METATYPE(QModelIndex) + +class tst_QIdentityProxyModel : public QObject +{ + Q_OBJECT + +public: + + tst_QIdentityProxyModel(); + virtual ~tst_QIdentityProxyModel(); + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void insertRows(); + void removeRows(); + void moveRows(); + void reset(); + +protected: + void verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent = QModelIndex()); + +private: + QStandardItemModel *m_model; + QIdentityProxyModel *m_proxy; +}; + +tst_QIdentityProxyModel::tst_QIdentityProxyModel() + : m_model(0), m_proxy(0) +{ + +} + +tst_QIdentityProxyModel::~tst_QIdentityProxyModel() +{ + +} + +void tst_QIdentityProxyModel::initTestCase() +{ + qRegisterMetaType<QModelIndex>("QModelIndex"); + + m_model = new QStandardItemModel(0, 1); + m_proxy = new QIdentityProxyModel(); +} + +void tst_QIdentityProxyModel::cleanupTestCase() +{ + delete m_proxy; + delete m_model; +} + +void tst_QIdentityProxyModel::init() +{ +} + +void tst_QIdentityProxyModel::cleanup() +{ + m_model->clear(); + m_model->insertColumns(0, 1); +} + +void tst_QIdentityProxyModel::verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent) +{ + const int rows = model->rowCount(parent); + const int columns = model->columnCount(parent); + const QModelIndex proxyParent = m_proxy->mapFromSource(parent); + + QVERIFY(m_proxy->mapToSource(proxyParent) == parent); + QVERIFY(rows == m_proxy->rowCount(proxyParent)); + QVERIFY(columns == m_proxy->columnCount(proxyParent)); + + for (int row = 0; row < rows; ++row) { + for (int column = 0; column < columns; ++column) { + const QModelIndex idx = model->index(row, column, parent); + const QModelIndex proxyIdx = m_proxy->mapFromSource(idx); + QVERIFY(proxyIdx.model() == m_proxy); + QVERIFY(m_proxy->mapToSource(proxyIdx) == idx); + QVERIFY(proxyIdx.isValid()); + QVERIFY(proxyIdx.row() == row); + QVERIFY(proxyIdx.column() == column); + QVERIFY(proxyIdx.parent() == proxyParent); + QVERIFY(proxyIdx.data() == idx.data()); + QVERIFY(proxyIdx.flags() == idx.flags()); + const int childCount = m_proxy->rowCount(proxyIdx); + const bool hasChildren = m_proxy->hasChildren(proxyIdx); + QVERIFY(model->hasChildren(idx) == hasChildren); + QVERIFY((childCount > 0) == hasChildren); + + if (hasChildren) + verifyIdentity(model, idx); + } + } +} + +/* + tests +*/ + +void tst_QIdentityProxyModel::insertRows() +{ + QStandardItem *parentItem = m_model->invisibleRootItem(); + for (int i = 0; i < 4; ++i) { + QStandardItem *item = new QStandardItem(QString("item %0").arg(i)); + parentItem->appendRow(item); + parentItem = item; + } + + m_proxy->setSourceModel(m_model); + + verifyIdentity(m_model); + + QSignalSpy modelBeforeSpy(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); + QSignalSpy modelAfterSpy(m_model, SIGNAL(rowsInserted(QModelIndex,int,int))); + QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); + QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsInserted(QModelIndex,int,int))); + + QStandardItem *item = new QStandardItem(QString("new item")); + parentItem->appendRow(item); + + QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size()); + QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size()); + + QVERIFY(modelBeforeSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value<QModelIndex>())); + QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1)); + QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2)); + + QVERIFY(modelAfterSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyAfterSpy.first().first().value<QModelIndex>())); + QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1)); + QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2)); + + verifyIdentity(m_model); + +} + +void tst_QIdentityProxyModel::removeRows() +{ + QStandardItem *parentItem = m_model->invisibleRootItem(); + for (int i = 0; i < 4; ++i) { + QStandardItem *item = new QStandardItem(QString("item %0").arg(i)); + parentItem->appendRow(item); + parentItem = item; + } + + m_proxy->setSourceModel(m_model); + + verifyIdentity(m_model); + + QSignalSpy modelBeforeSpy(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy modelAfterSpy(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int))); + QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsRemoved(QModelIndex,int,int))); + + const QModelIndex topLevel = m_model->index(0, 0, QModelIndex()); + const QModelIndex secondLevel = m_model->index(0, 0, topLevel); + const QModelIndex thirdLevel = m_model->index(0, 0, secondLevel); + + QVERIFY(thirdLevel.isValid()); + + m_model->removeRow(0, secondLevel); + + QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size()); + QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size()); + + QVERIFY(modelBeforeSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value<QModelIndex>())); + QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1)); + QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2)); + + QVERIFY(modelAfterSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyAfterSpy.first().first().value<QModelIndex>())); + QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1)); + QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2)); + + verifyIdentity(m_model); +} + +void tst_QIdentityProxyModel::moveRows() +{ + DynamicTreeModel model; + + { + ModelInsertCommand insertCommand(&model); + insertCommand.setStartRow(0); + insertCommand.setEndRow(9); + insertCommand.doCommand(); + } + { + ModelInsertCommand insertCommand(&model); + insertCommand.setAncestorRowNumbers(QList<int>() << 5); + insertCommand.setStartRow(0); + insertCommand.setEndRow(9); + insertCommand.doCommand(); + } + + m_proxy->setSourceModel(&model); + + verifyIdentity(&model); + + QSignalSpy modelBeforeSpy(&model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + QSignalSpy modelAfterSpy(&model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + + { + ModelMoveCommand moveCommand(&model, 0); + moveCommand.setAncestorRowNumbers(QList<int>() << 5); + moveCommand.setStartRow(3); + moveCommand.setEndRow(4); + moveCommand.setDestRow(1); + moveCommand.doCommand(); + } + + QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size()); + QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size()); + + QVERIFY(modelBeforeSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value<QModelIndex>())); + QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1)); + QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2)); + QVERIFY(modelBeforeSpy.first().at(3).value<QModelIndex>() == m_proxy->mapToSource(proxyBeforeSpy.first().at(3).value<QModelIndex>())); + QVERIFY(modelBeforeSpy.first().at(4) == proxyBeforeSpy.first().at(4)); + + QVERIFY(modelAfterSpy.first().first().value<QModelIndex>() == m_proxy->mapToSource(proxyAfterSpy.first().first().value<QModelIndex>())); + QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1)); + QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2)); + QVERIFY(modelAfterSpy.first().at(3).value<QModelIndex>() == m_proxy->mapToSource(proxyAfterSpy.first().at(3).value<QModelIndex>())); + QVERIFY(modelAfterSpy.first().at(4) == proxyAfterSpy.first().at(4)); + + verifyIdentity(&model); + + m_proxy->setSourceModel(0); +} + +void tst_QIdentityProxyModel::reset() +{ + DynamicTreeModel model; + + { + ModelInsertCommand insertCommand(&model); + insertCommand.setStartRow(0); + insertCommand.setEndRow(9); + insertCommand.doCommand(); + } + { + ModelInsertCommand insertCommand(&model); + insertCommand.setAncestorRowNumbers(QList<int>() << 5); + insertCommand.setStartRow(0); + insertCommand.setEndRow(9); + insertCommand.doCommand(); + } + + m_proxy->setSourceModel(&model); + + verifyIdentity(&model); + + QSignalSpy modelBeforeSpy(&model, SIGNAL(modelAboutToBeReset())); + QSignalSpy modelAfterSpy(&model, SIGNAL(modelReset())); + QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(modelAboutToBeReset())); + QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(modelReset())); + + { + ModelResetCommandFixed resetCommand(&model, 0); + resetCommand.setAncestorRowNumbers(QList<int>() << 5); + resetCommand.setStartRow(3); + resetCommand.setEndRow(4); + resetCommand.setDestRow(1); + resetCommand.doCommand(); + } + + QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size()); + QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size()); + + verifyIdentity(&model); + m_proxy->setSourceModel(0); +} + +QTEST_MAIN(tst_QIdentityProxyModel) +#include "tst_qidentityproxymodel.moc" diff --git a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp index 6e20fb2..d91b068 100644 --- a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp +++ b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp @@ -101,6 +101,7 @@ private slots: void testDifferentModels(); void testValidRangesInSelectionsAfterReset(); + void testChainedSelectionClear(); private: QAbstractItemModel *model; @@ -2655,5 +2656,58 @@ void tst_QItemSelectionModel::testValidRangesInSelectionsAfterReset() model.setStringList(strings); } +class DuplicateItemSelectionModel : public QItemSelectionModel +{ + Q_OBJECT +public: + DuplicateItemSelectionModel(QItemSelectionModel *target, QAbstractItemModel *model, QObject *parent = 0) + : QItemSelectionModel(model, parent), m_target(target) + { + + } + + void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) + { + QItemSelectionModel::select(selection, command); + m_target->select(selection, command); + } + + using QItemSelectionModel::select; + +private: + QItemSelectionModel *m_target; + +}; + +void tst_QItemSelectionModel::testChainedSelectionClear() +{ + QStringListModel model(QStringList() << "Apples" << "Pears"); + + QItemSelectionModel selectionModel(&model, 0); + DuplicateItemSelectionModel duplicate(&selectionModel, &model, 0); + + duplicate.select(model.index(0, 0), QItemSelectionModel::Select); + + { + QModelIndexList selectedIndexes = selectionModel.selection().indexes(); + QModelIndexList duplicatedIndexes = duplicate.selection().indexes(); + + QVERIFY(selectedIndexes.size() == duplicatedIndexes.size()); + QVERIFY(selectedIndexes.size() == 1); + QVERIFY(selectedIndexes.first() == model.index(0, 0)); + } + + duplicate.clearSelection(); + + { + QModelIndexList selectedIndexes = selectionModel.selection().indexes(); + QModelIndexList duplicatedIndexes = duplicate.selection().indexes(); + + QVERIFY(selectedIndexes.size() == duplicatedIndexes.size()); + QVERIFY(selectedIndexes.size() == 0); + } + +} + QTEST_MAIN(tst_QItemSelectionModel) #include "tst_qitemselectionmodel.moc" diff --git a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index d26f0cd..8e7f393 100644 --- a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -149,7 +149,6 @@ private slots: void testMultipleProxiesWithSelection(); void mapSelectionFromSource(); - void testResetInternalData(); void filteredColumns(); protected: @@ -3183,142 +3182,6 @@ void tst_QSortFilterProxyModel::taskQTBUG_10287_unnecessaryMapCreation() // No assert failure, it passes. } -/** - * A proxy which changes the background color for items ending in 'y' or 'r' - */ -class CustomDataProxy : public QSortFilterProxyModel -{ - Q_OBJECT - -public: - CustomDataProxy(QObject *parent = 0) - : QSortFilterProxyModel(parent) - { - setDynamicSortFilter(true); - } - - void setSourceModel(QAbstractItemModel *sourceModel) - { - // It would be possible to use only the modelReset signal of the source model to clear - // the data in *this, however, this requires that the slot is connected - // before QSortFilterProxyModel::setSourceModel is called, and even then depends - // on the order of invokation of slots being the same as the order of connection. - // ie, not reliable. -// connect(sourceModel, SIGNAL(modelReset()), SLOT(resetInternalData())); - QSortFilterProxyModel::setSourceModel(sourceModel); - // Making the connect after the setSourceModel call clears the data too late. -// connect(sourceModel, SIGNAL(modelReset()), SLOT(resetInternalData())); - - // This could be done in data(), but the point is to need to cache something in the proxy - // which needs to be cleared on reset. - for (int i = 0; i < sourceModel->rowCount(); ++i) - { - if (sourceModel->index(i, 0).data().toString().endsWith(QLatin1Char('y'))) - { - m_backgroundColours.insert(i, Qt::blue); - } else if (sourceModel->index(i, 0).data().toString().endsWith(QLatin1Char('r'))) - { - m_backgroundColours.insert(i, Qt::red); - } - } - } - - QVariant data(const QModelIndex &index, int role) const - { - if (role != Qt::BackgroundRole) - return QSortFilterProxyModel::data(index, role); - return m_backgroundColours.value(index.row()); - } - -private slots: - void resetInternalData() - { - m_backgroundColours.clear(); - } - -private: - QHash<int, QColor> m_backgroundColours; -}; - -class ModelObserver : public QObject -{ - Q_OBJECT -public: - ModelObserver(QAbstractItemModel *model, QObject *parent = 0) - : QObject(parent), m_model(model) - { - connect(m_model, SIGNAL(modelAboutToBeReset()), SLOT(modelAboutToBeReset())); - connect(m_model, SIGNAL(modelReset()), SLOT(modelReset())); - } - -public slots: - void modelAboutToBeReset() - { - int reds = 0, blues = 0; - for (int i = 0; i < m_model->rowCount(); ++i) - { - QColor color = m_model->index(i, 0).data(Qt::BackgroundRole).value<QColor>(); - if (color == Qt::blue) - ++blues; - if (color == Qt::red) - ++reds; - } - QCOMPARE(blues, 11); - QCOMPARE(reds, 4); - } - - void modelReset() - { - int reds = 0, blues = 0; - for (int i = 0; i < m_model->rowCount(); ++i) - { - QColor color = m_model->index(i, 0).data(Qt::BackgroundRole).value<QColor>(); - if (color == Qt::blue) - ++blues; - if (color == Qt::red) - ++reds; - } - QCOMPARE(reds, 0); - QCOMPARE(blues, 0); - } - -private: - QAbstractItemModel * const m_model; - -}; - -void tst_QSortFilterProxyModel::testResetInternalData() -{ - - QStringListModel model(QStringList() << "Monday" - << "Tuesday" - << "Wednesday" - << "Thursday" - << "Friday" - << "January" - << "February" - << "March" - << "April" - << "May" - << "Saturday" - << "June" - << "Sunday" - << "July" - << "August" - << "September" - << "October" - << "November" - << "December"); - - CustomDataProxy proxy; - proxy.setSourceModel(&model); - - ModelObserver observer(&proxy); - - // Cause the source model to reset. - model.setStringList(QStringList() << "Spam" << "Eggs"); -} - class FilteredColumnProxyModel : public QSortFilterProxyModel { Q_OBJECT diff --git a/tests/auto/qtablewidget/tst_qtablewidget.cpp b/tests/auto/qtablewidget/tst_qtablewidget.cpp index d17e064..40aece4 100644 --- a/tests/auto/qtablewidget/tst_qtablewidget.cpp +++ b/tests/auto/qtablewidget/tst_qtablewidget.cpp @@ -41,6 +41,7 @@ #include <QtTest/QtTest> +#include "../../shared/util.h" #include <qeventloop.h> #include <qlist.h> #include <qpair.h> @@ -1472,7 +1473,7 @@ void tst_QTableWidget::task219380_removeLastRow() testWidget->removeRow(19); //we remove the last row //we make sure the editor is at the cell position - QCOMPARE(testWidget->cellWidget(18, 0)->geometry(), testWidget->visualItemRect(&item)); + QTRY_COMPARE(testWidget->cellWidget(18, 0)->geometry(), testWidget->visualItemRect(&item)); } void tst_QTableWidget::task262056_sortDuplicate() |