diff --git a/akonadi/entityfilterproxymodel.cpp b/akonadi/entityfilterproxymodel.cpp index 5f5d02769..31b3d4315 100644 --- a/akonadi/entityfilterproxymodel.cpp +++ b/akonadi/entityfilterproxymodel.cpp @@ -1,271 +1,279 @@ /* Copyright (c) 2007 Bruno Virlet Copyright (c) 2009 Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "entityfilterproxymodel.h" #include "entitytreemodel.h" #include #include #include #include using namespace Akonadi; namespace Akonadi { /** * @internal */ class EntityFilterProxyModelPrivate { public: EntityFilterProxyModelPrivate( EntityFilterProxyModel *parent ) : q_ptr( parent ), m_headerSet(0) { } QStringList includedMimeTypes; QStringList excludedMimeTypes; QPersistentModelIndex m_rootIndex; int m_headerSet; Q_DECLARE_PUBLIC(EntityFilterProxyModel) EntityFilterProxyModel *q_ptr; }; } EntityFilterProxyModel::EntityFilterProxyModel( QObject *parent ) : QSortFilterProxyModel( parent ), d_ptr( new EntityFilterProxyModelPrivate( this ) ) { // TODO: Override setSourceModel and do this there? setSupportedDragActions( Qt::CopyAction | Qt::MoveAction ); } EntityFilterProxyModel::~EntityFilterProxyModel() { delete d_ptr; } void EntityFilterProxyModel::addMimeTypeInclusionFilters(const QStringList &typeList) { Q_D(EntityFilterProxyModel); d->includedMimeTypes << typeList; invalidateFilter(); } void EntityFilterProxyModel::addMimeTypeExclusionFilters(const QStringList &typeList) { Q_D(EntityFilterProxyModel); d->excludedMimeTypes << typeList; invalidateFilter(); } void EntityFilterProxyModel::addMimeTypeInclusionFilter(const QString &type) { Q_D(EntityFilterProxyModel); d->includedMimeTypes << type; invalidateFilter(); } void EntityFilterProxyModel::addMimeTypeExclusionFilter(const QString &type) { Q_D(EntityFilterProxyModel); d->excludedMimeTypes << type; invalidateFilter(); } bool EntityFilterProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent) const { Q_D(const EntityFilterProxyModel); // All rows that are not below m_rootIndex are unfiltered. bool found = false; const bool rootIsValid = d->m_rootIndex.isValid(); QModelIndex _parent = sourceParent; while (true) { if (_parent == d->m_rootIndex) { found = true; break; } _parent = _parent.parent(); if (!_parent.isValid() && rootIsValid) { break; } } if (!found) { return true; } const QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent); const QString rowMimetype = idx.data( EntityTreeModel::MimeTypeRole ).toString(); if ( d->excludedMimeTypes.contains( rowMimetype ) ) return false; if ( d->includedMimeTypes.isEmpty() || d->includedMimeTypes.contains( rowMimetype ) ) return true; return false; } QStringList EntityFilterProxyModel::mimeTypeInclusionFilters() const { Q_D(const EntityFilterProxyModel); return d->includedMimeTypes; } QStringList EntityFilterProxyModel::mimeTypeExclusionFilters() const { Q_D(const EntityFilterProxyModel); return d->excludedMimeTypes; } void EntityFilterProxyModel::clearFilters() { Q_D(EntityFilterProxyModel); d->includedMimeTypes.clear(); d->excludedMimeTypes.clear(); invalidateFilter(); } void EntityFilterProxyModel::setRootIndex(const QModelIndex &srcIndex) { Q_D(EntityFilterProxyModel); d->m_rootIndex = srcIndex; reset(); } void EntityFilterProxyModel::setHeaderSet(int set) { Q_D(EntityFilterProxyModel); d->m_headerSet = set; } QVariant EntityFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role ) const { Q_D(const EntityFilterProxyModel); role += (EntityTreeModel::TerminalUserRole * d->m_headerSet); return sourceModel()->headerData(section, orientation, role); } bool EntityFilterProxyModel::dropMimeData( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent ) { Q_ASSERT(sourceModel()); const QModelIndex sourceParent = mapToSource(parent); return sourceModel()->dropMimeData(data, action, row, column, sourceParent); } QMimeData* EntityFilterProxyModel::mimeData( const QModelIndexList & indexes ) const { Q_ASSERT(sourceModel()); QModelIndexList sourceIndexes; foreach(const QModelIndex& index, indexes) sourceIndexes << mapToSource(index); return sourceModel()->mimeData(sourceIndexes); } QStringList EntityFilterProxyModel::mimeTypes() const { Q_ASSERT(sourceModel()); return sourceModel()->mimeTypes(); } QModelIndexList EntityFilterProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const { if (EntityTreeModel::AmazingCompletionRole != role) return QSortFilterProxyModel::match(start, role, value, hits, flags); // We match everything in the source model because sorting will change what we should show. const int allHits = -1; QModelIndexList proxyList; QMap proxyMap; QModelIndexList sourceList = sourceModel()->match(mapToSource(start), role, value, allHits, flags); QModelIndexList::const_iterator it; const QModelIndexList::const_iterator begin = sourceList.constBegin(); const QModelIndexList::const_iterator end = sourceList.constEnd(); QModelIndex proxyIndex; for (it = begin; it != end; ++it) { proxyIndex = mapFromSource(*it); // Any filtered indexes will be invalid when mapped. if (!proxyIndex.isValid()) continue; // Inserting in a QMap gives us sorting by key for free. proxyMap.insert(proxyIndex.row(), proxyIndex); } if (hits == -1) return proxyMap.values(); return proxyMap.values().mid(0, hits); } int EntityFilterProxyModel::columnCount(const QModelIndex &parent) const { Q_D(const EntityFilterProxyModel); QVariant var = sourceModel()->data(parent, EntityTreeModel::ColumnCountRole + (EntityTreeModel::TerminalUserRole * d->m_headerSet)); if( !var.isValid() ) return 0; return var.toInt(); } bool EntityFilterProxyModel::hasChildren(const QModelIndex &parent) const { if ( !parent.isValid() ) return sourceModel()->hasChildren(parent); Q_D(const EntityFilterProxyModel); if ( EntityTreeModel::ItemListHeaders == d->m_headerSet) return false; if ( EntityTreeModel::CollectionTreeHeaders == d->m_headerSet ) { QModelIndex childIndex = parent.child( 0, 0 ); while ( childIndex.isValid() ) { Collection col = childIndex.data( EntityTreeModel::CollectionRole ).value(); if (col.isValid()) return true; childIndex = childIndex.sibling( childIndex.row() + 1, childIndex.column() ); } } return false; } +bool EntityFilterProxyModel::canFetchMore( const QModelIndex &parent ) const +{ + Q_D(const EntityFilterProxyModel); + if ( EntityTreeModel::CollectionTreeHeaders == d->m_headerSet ) + return false; + return QSortFilterProxyModel::canFetchMore(parent); +} + #include "entityfilterproxymodel.moc" diff --git a/akonadi/entityfilterproxymodel.h b/akonadi/entityfilterproxymodel.h index 3416dc422..72a94be3c 100644 --- a/akonadi/entityfilterproxymodel.h +++ b/akonadi/entityfilterproxymodel.h @@ -1,160 +1,162 @@ /* Copyright (c) 2007 Bruno Virlet Copyright (c) 2009 Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_ENTITYFILTERPROXYMODEL_H #define AKONADI_ENTITYFILTERPROXYMODEL_H #include "akonadi_export.h" #include namespace Akonadi { class EntityFilterProxyModelPrivate; /** * @short A proxy model that filters entities by mime type. * * This class can be used on top of an EntityTreeModel to exclude entities by mimetype * or to include only certain mimetypes. * * @code * * Akonadi::EntityTreeModel *model = new Akonadi::EntityTreeModel( this ); * * Akonadi::EntityFilterProxyModel *proxy = new Akonadi::EntityFilterProxyModel(); * proxy->addMimeTypeInclusionFilter( "message/rfc822" ); * proxy->setSourceModel( model ); * * Akonadi::EntityTreeView *view = new Akonadi::EntityTreeView( this ); * view->setModel( proxy ); * * @endcode * * @li If a mimetype is in both the exclusion list and the inclusion list, it is excluded. * @li If the mimeTypeInclusionFilter is empty, all mimetypes are * accepted (except if they are in the exclusion filter of course). * * * @author Bruno Virlet * @author Stephen Kelly * @since 4.4 */ class AKONADI_EXPORT EntityFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: /** * Creates a new proxy filter model. * * @param parent The parent object. */ explicit EntityFilterProxyModel( QObject *parent = 0 ); /** * Destroys the proxy filter model. */ virtual ~EntityFilterProxyModel(); /** * Add mime types to be shown by the filter. * * @param mimeTypes A list of mime types to be included. */ void addMimeTypeInclusionFilters( const QStringList &mimeTypes ); /** * Add mimetypes to filter out * * @param mimeTypes A list to exclude from the model. */ void addMimeTypeExclusionFilters( const QStringList &mimeTypes ); /** * Add mime type to be shown by the filter. * * @param mimeType A mime type to be shown. */ void addMimeTypeInclusionFilter( const QString &mimeType ); /** * Add mime type to be excluded by the filter. * * @param mimeType A mime type to be excluded. */ void addMimeTypeExclusionFilter( const QString &mimeType ); /** * Returns the list of mime type inclusion filters. */ QStringList mimeTypeInclusionFilters() const; /** * Returns the list of mime type exclusion filters. */ QStringList mimeTypeExclusionFilters() const; /** * Clear all mime type filters. */ void clearFilters(); /** * Sets the @p index that shall be used as the root for this model. */ void setRootIndex( const QModelIndex &index ); /** * Sets the header @p set of the filter model. * * \sa EntityTreeModel::HeaderGroup */ void setHeaderSet( int set ); virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; // QAbstractProxyModel does not proxy all methods... virtual bool dropMimeData( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent ); virtual QMimeData* mimeData( const QModelIndexList & indexes ) const; virtual QStringList mimeTypes() const; virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const; + virtual bool canFetchMore(const QModelIndex &parent) const; + /** Reimplemented to handle the AmazingCompletionRole. */ virtual QModelIndexList match( const QModelIndex& start, int role, const QVariant& value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags( Qt::MatchStartsWith | Qt::MatchWrap ) ) const; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; protected: virtual bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const; private: //@cond PRIVATE Q_DECLARE_PRIVATE( EntityFilterProxyModel ) EntityFilterProxyModelPrivate *d_ptr; //@endcond }; } #endif