diff --git a/akonadi/CMakeLists.txt b/akonadi/CMakeLists.txt index e9cce0c79..a462390e2 100644 --- a/akonadi/CMakeLists.txt +++ b/akonadi/CMakeLists.txt @@ -1,287 +1,288 @@ project(akonadi-kde) add_definitions( -DKDE_DEFAULT_DEBUG_AREA=5250 ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}" ) if(CMAKE_COMPILE_GCOV) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") endif(CMAKE_COMPILE_GCOV) if (KDE4_BUILD_TESTS) # only with this macro the AKONADI_TESTS_EXPORT macro will do something add_definitions(-DCOMPILING_TESTS) add_subdirectory( tests ) endif (KDE4_BUILD_TESTS) add_definitions( -DQT_NO_CAST_FROM_ASCII ) add_definitions( -DQT_NO_CAST_TO_ASCII ) add_subdirectory( kabc ) add_subdirectory( kmime ) add_subdirectory( contact ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${QT_QTDBUS_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${KDE4_INCLUDE_DIR} ${AKONADI_INCLUDE_DIR} ${AKONADI_INCLUDE_DIR}/akonadi/private ) # libakonadi-kde set( akonadikde_LIB_SRC entity.cpp # keep it at top to not break enable-final agentbase.cpp agentfilterproxymodel.cpp agentinstance.cpp agentinstancecreatejob.cpp agentinstancemodel.cpp agentinstancewidget.cpp agentmanager.cpp agenttype.cpp agenttypemodel.cpp agenttypewidget.cpp agenttypedialog.cpp asyncselectionhandler.cpp attribute.cpp attributefactory.cpp cachepolicy.cpp cachepolicypage.cpp changerecorder.cpp collection.cpp collectioncombobox.cpp collectioncopyjob.cpp collectioncreatejob.cpp collectiondeletejob.cpp collectiondialog.cpp collectionfilterproxymodel.cpp collectiongeneralpropertiespage.cpp collectionfetchjob.cpp collectionfetchscope.cpp collectionmodel.cpp collectionmodel_p.cpp collectionmodifyjob.cpp collectionmovejob.cpp collectionpathresolver.cpp collectionpropertiesdialog.cpp collectionpropertiespage.cpp collectionquotaattribute.cpp collectionrequester.cpp collectionrightsattribute.cpp collectionselectjob.cpp collectionstatistics.cpp collectionstatisticsdelegate.cpp collectionstatisticsjob.cpp collectionstatisticsmodel.cpp collectionsync.cpp collectionview.cpp dragdropmanager.cpp control.cpp entitycache.cpp entitydisplayattribute.cpp entityhiddenattribute.cpp entitylistview.cpp entitymimetypefiltermodel.cpp entityrightsfiltermodel.cpp entitytreemodel.cpp entitytreemodel_p.cpp entitytreeview.cpp entitytreeviewstatesaver.cpp erroroverlay.cpp exception.cpp favoritecollectionsmodel.cpp firstrun.cpp flatcollectionproxymodel.cpp item.cpp itemcreatejob.cpp itemcopyjob.cpp itemdeletejob.cpp itemfetchjob.cpp itemfetchscope.cpp itemmodel.cpp itemmonitor.cpp itemmovejob.cpp itemsearchjob.cpp itemserializer.cpp itemserializerplugin.cpp itemmodifyjob.cpp itemsync.cpp itemview.cpp job.cpp + kdescendantsproxymodel.cpp linkjob.cpp mimetypechecker.cpp monitor.cpp monitor_p.cpp partfetcher.cpp pastehelper.cpp preprocessorbase.cpp preprocessorbase_p.cpp protocolhelper.cpp resourcebase.cpp resourcescheduler.cpp resourceselectjob.cpp resourcesynchronizationjob.cpp searchcreatejob.cpp selectionproxymodel.cpp selftestdialog.cpp session.cpp servermanager.cpp specialcollectionattribute.cpp specialcollections.cpp specialcollectionshelperjobs.cpp specialcollectionsrequestjob.cpp standardactionmanager.cpp statisticsproxymodel.cpp subscriptionjob.cpp subscriptionchangeproxymodel.cpp subscriptiondialog.cpp subscriptionmodel.cpp transactionjobs.cpp transactionsequence.cpp transportresourcebase.cpp unlinkjob.cpp # Temporary until ported to Qt-plugin framework pluginloader.cpp ) # DBus interfaces and adaptors set(akonadi_xml ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.NotificationManager.xml) set_source_files_properties(${akonadi_xml} PROPERTIES INCLUDE "notificationmessage_p.h") qt4_add_dbus_interface( akonadikde_LIB_SRC ${akonadi_xml} notificationmanagerinterface ) qt4_add_dbus_interfaces( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.AgentManager.xml ) qt4_add_dbus_interfaces( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Tracer.xml ) qt4_add_dbus_interfaces( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Agent.Control.xml ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Resource.xml resourcebase.h Akonadi::ResourceBase ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Preprocessor.xml preprocessorbase_p.h Akonadi::PreprocessorBasePrivate ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Agent.Status.xml agentbase.h Akonadi::AgentBase ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC ${AKONADI_DBUS_INTERFACES_DIR}/org.freedesktop.Akonadi.Agent.Control.xml agentbase.h Akonadi::AgentBase ) qt4_add_dbus_adaptor( akonadikde_LIB_SRC interfaces/org.freedesktop.Akonadi.Resource.Transport.xml transportresourcebase_p.h Akonadi::TransportResourceBasePrivate ) kde4_add_ui_files( akonadikde_LIB_SRC cachepolicypage.ui collectiongeneralpropertiespage.ui subscriptiondialog.ui controlprogressindicator.ui selftestdialog.ui ) kde4_add_library( akonadi-kde SHARED ${akonadikde_LIB_SRC} ) macro_ensure_version( "4.2.0" ${KDE_VERSION} KDE_IS_AT_LEAST_42 ) target_link_libraries( akonadi-kde ${KDE4_SOLID_LIBS} ${QT_QTNETWORK_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTSQL_LIBRARY} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${AKONADI_COMMON_LIBRARIES} ) set( AKONADI_KDE_DEPS ${KDE4_KDEUI_LIBS} ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} ) if(${KDE_IS_AT_LEAST_42}) target_link_libraries( akonadi-kde LINK_INTERFACE_LIBRARIES ${AKONADI_KDE_DEPS}) else(${KDE_IS_AT_LEAST_42}) target_link_libraries( akonadi-kde ${AKONADI_KDE_DEPS}) endif(${KDE_IS_AT_LEAST_42}) set_target_properties( akonadi-kde PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) install( TARGETS akonadi-kde EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS} ) ########### install files ############### install( FILES akonadi_export.h agentbase.h agentfilterproxymodel.h agentinstance.h agentinstancecreatejob.h agentinstancemodel.h agentinstancewidget.h agentmanager.h agenttype.h agenttypemodel.h agenttypewidget.h agenttypedialog.h attribute.h attributefactory.h cachepolicy.h changerecorder.h collection.h collectioncombobox.h collectioncopyjob.h collectioncreatejob.h collectiondeletejob.h collectiondialog.h collectionfilterproxymodel.h collectionfetchjob.h collectionfetchscope.h collectionmodel.h collectionmodifyjob.h collectionmovejob.h collectionpropertiesdialog.h collectionpropertiespage.h collectionquotaattribute.h collectionrequester.h collectionstatisticsdelegate.h collectionstatisticsmodel.h collectionstatistics.h collectionstatisticsjob.h collectionview.h control.h entity.h entitydisplayattribute.h entityhiddenattribute.h entitylistview.h entitymimetypefiltermodel.h entityrightsfiltermodel.h entitytreemodel.h entitytreeview.h entitytreeviewstatesaver.h exception.h favoritecollectionsmodel.h item.h itemcreatejob.h itemcopyjob.h itemdeletejob.h itemfetchjob.h itemfetchscope.h itemmodel.h itemmodifyjob.h itemmonitor.h itemmovejob.h itempayloadinternals_p.h itemsearchjob.h itemserializerplugin.h itemsync.h itemview.h job.h linkjob.h mimetypechecker.h monitor.h partfetcher.h preprocessorbase.h qtest_akonadi.h resourcebase.h resourcesynchronizationjob.h searchcreatejob.h selectionproxymodel.h session.h servermanager.h specialcollections.h specialcollectionsrequestjob.h standardactionmanager.h statisticsproxymodel.h transactionjobs.h transactionsequence.h transportresourcebase.h unlinkjob.h DESTINATION ${INCLUDE_INSTALL_DIR}/akonadi COMPONENT Devel ) install( FILES collectionpathresolver_p.h DESTINATION ${INCLUDE_INSTALL_DIR}/akonadi/private COMPONENT Devel ) install( FILES kcfg2dbus.xsl DESTINATION ${DATA_INSTALL_DIR}/akonadi-kde ) diff --git a/akonadi/collectioncombobox.cpp b/akonadi/collectioncombobox.cpp index 74ea374e5..c13f2ef70 100644 --- a/akonadi/collectioncombobox.cpp +++ b/akonadi/collectioncombobox.cpp @@ -1,162 +1,162 @@ /* This file is part of Akonadi Contact. Copyright (c) 2007-2009 Tobias Koenig 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 "collectioncombobox.h" #include "asyncselectionhandler_p.h" #include #include #include #include #include #include -#include +#include "kdescendantsproxymodel_p.h" #include using namespace Akonadi; class CollectionComboBox::Private { public: Private( QAbstractItemModel *customModel, CollectionComboBox *parent ) : mParent( parent ), mMonitor( 0 ), mModel( 0 ) { QAbstractItemModel *baseModel; if ( customModel ) { baseModel = customModel; } else { mMonitor = new Akonadi::ChangeRecorder( mParent ); mMonitor->fetchCollection( true ); mMonitor->setCollectionMonitored( Akonadi::Collection::root() ); mModel = new EntityTreeModel( Session::defaultSession(), mMonitor, mParent ); mModel->setItemPopulationStrategy( EntityTreeModel::NoItemPopulation ); KDescendantsProxyModel *proxyModel = new KDescendantsProxyModel( parent ); proxyModel->setSourceModel( mModel ); baseModel = proxyModel; } mMimeTypeFilterModel = new CollectionFilterProxyModel( parent ); mMimeTypeFilterModel->setSourceModel( baseModel ); mRightsFilterModel = new EntityRightsFilterModel( parent ); mRightsFilterModel->setSourceModel( mMimeTypeFilterModel ); mParent->setModel( mRightsFilterModel ); mSelectionHandler = new AsyncSelectionHandler( mRightsFilterModel, mParent ); mParent->connect( mSelectionHandler, SIGNAL( collectionAvailable( const QModelIndex& ) ), mParent, SLOT( activated( const QModelIndex& ) ) ); mParent->connect( mParent, SIGNAL( activated( int ) ), mParent, SLOT( activated( int ) ) ); } ~Private() { } void activated( int index ); void activated( const QModelIndex& index ); CollectionComboBox *mParent; ChangeRecorder *mMonitor; EntityTreeModel *mModel; CollectionFilterProxyModel *mMimeTypeFilterModel; EntityRightsFilterModel *mRightsFilterModel; AsyncSelectionHandler *mSelectionHandler; }; void CollectionComboBox::Private::activated( int index ) { const QModelIndex modelIndex = mParent->model()->index( index, 0 ); if ( modelIndex.isValid() ) emit mParent->currentChanged( modelIndex.data( EntityTreeModel::CollectionRole).value() ); } void CollectionComboBox::Private::activated( const QModelIndex &index ) { mParent->setCurrentIndex( index.row() ); } CollectionComboBox::CollectionComboBox( QWidget *parent ) : KComboBox( parent ), d( new Private( 0, this ) ) { } CollectionComboBox::CollectionComboBox( QAbstractItemModel *model, QWidget *parent ) : KComboBox( parent ), d( new Private( model, this ) ) { } CollectionComboBox::~CollectionComboBox() { delete d; } void CollectionComboBox::setMimeTypeFilter( const QStringList &contentMimeTypes ) { d->mMimeTypeFilterModel->clearFilters(); d->mMimeTypeFilterModel->addMimeTypeFilters( contentMimeTypes ); if ( d->mMonitor ) foreach ( const QString &mimeType, contentMimeTypes ) d->mMonitor->setMimeTypeMonitored( mimeType, true ); } QStringList CollectionComboBox::mimeTypeFilter() const { return d->mMimeTypeFilterModel->mimeTypeFilters(); } void CollectionComboBox::setAccessRightsFilter( Collection::Rights rights ) { d->mRightsFilterModel->setAccessRights( rights ); } Collection::Rights CollectionComboBox::accessRightsFilter() const { return d->mRightsFilterModel->accessRights(); } void CollectionComboBox::setDefaultCollection( const Collection &collection ) { d->mSelectionHandler->waitForCollection( collection ); } Akonadi::Collection CollectionComboBox::currentCollection() const { const QModelIndex modelIndex = model()->index( currentIndex(), 0 ); if ( modelIndex.isValid() ) return modelIndex.data( Akonadi::EntityTreeModel::CollectionRole ).value(); else return Akonadi::Collection(); } #include "collectioncombobox.moc" diff --git a/akonadi/contact/CMakeLists.txt b/akonadi/contact/CMakeLists.txt index 9af553db2..a42dee423 100644 --- a/akonadi/contact/CMakeLists.txt +++ b/akonadi/contact/CMakeLists.txt @@ -1,110 +1,111 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${Boost_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/kabc ) add_subdirectory(tests) add_subdirectory(kcm) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII ${KDE4_ENABLE_EXCEPTIONS}") ########### next target ############### set(akonadicontact_actions_SRCS actions/dialphonenumberaction.cpp actions/showaddressaction.cpp actions/qskypedialer.cpp ) kde4_add_kcfg_files(akonadicontact_actions_SRCS actions/contactactionssettings.kcfgc) set(akonadicontact_editor_SRCS editor/addresseditwidget.cpp editor/contacteditorwidget.cpp editor/dateeditwidget.cpp editor/displaynameeditwidget.cpp editor/emaileditwidget.cpp editor/freebusyeditwidget.cpp editor/geoeditwidget.cpp editor/imagewidget.cpp editor/imeditwidget.cpp editor/kdatepickerpopup.cpp editor/nameeditwidget.cpp editor/phoneeditwidget.cpp editor/secrecyeditwidget.cpp editor/soundeditwidget.cpp ) set(akonadicontact_LIB_SRC attributeregistrar.cpp collectionfiltermodel.cpp + ../kdescendantsproxymodel.cpp contactcompletionmodel.cpp contactdefaultactions.cpp contacteditor.cpp contacteditordialog.cpp contactgroupeditor.cpp contactgroupeditordelegate.cpp contactgroupeditordialog.cpp contactgroupexpandjob.cpp contactgrouplineedit.cpp contactgroupmodel.cpp contactgroupsearchjob.cpp contactgroupviewer.cpp contactgroupviewerdialog.cpp contactmetadata.cpp contactmetadataattribute.cpp contactsearchjob.cpp contactviewer.cpp contactviewerdialog.cpp recentcontactscollections.cpp recentcontactscollectionrequestjob.cpp waitingoverlay.cpp ${akonadicontact_actions_SRCS} ${akonadicontact_editor_SRCS} ) qt4_wrap_ui(akonadicontact_LIB_SRC contactgroupeditor.ui) kde4_add_kcfg_files(akonadicontact_LIB_SRC recentcontactscollectionssettings.kcfgc ) kde4_add_library(akonadi-contact SHARED ${akonadicontact_LIB_SRC}) target_link_libraries(akonadi-contact akonadi-kde kabc kcal ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_PHONON_LIBS}) target_link_libraries(akonadi-contact LINK_INTERFACE_LIBRARIES akonadi-kde kabc kcal ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_PHONON_LIBS}) set_target_properties(akonadi-contact PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) install(TARGETS akonadi-contact EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES editor/pics/world.jpg DESTINATION ${DATA_INSTALL_DIR}/akonadi/contact/pics) install(FILES editor/data/zone.tab DESTINATION ${DATA_INSTALL_DIR}/akonadi/contact/data) install(FILES recentcontactscollections.kcfg DESTINATION ${KCFG_INSTALL_DIR} ) install( FILES akonadi-contact_export.h contactdefaultactions.h contacteditor.h contacteditordialog.h contacteditorpageplugin.h contactgroupeditor.h contactgroupeditordialog.h contactgroupexpandjob.h contactgroupsearchjob.h contactgroupviewer.h contactgroupviewerdialog.h contactsearchjob.h contactviewer.h contactviewerdialog.h recentcontactscollectionrequestjob.h DESTINATION ${INCLUDE_INSTALL_DIR}/akonadi/contact COMPONENT Devel ) diff --git a/akonadi/contact/contactcompletionmodel.cpp b/akonadi/contact/contactcompletionmodel.cpp index 49547dea4..79a3a0403 100644 --- a/akonadi/contact/contactcompletionmodel.cpp +++ b/akonadi/contact/contactcompletionmodel.cpp @@ -1,135 +1,135 @@ /* This file is part of Akonadi Contact. Copyright (c) 2009 Tobias Koenig 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 "contactcompletionmodel_p.h" -#include +#include "../kdescendantsproxymodel_p.h" #include #include #include #include #include using namespace Akonadi; QAbstractItemModel* ContactCompletionModel::mSelf = 0; QAbstractItemModel* ContactCompletionModel::self() { if ( mSelf ) return mSelf; ChangeRecorder *monitor = new ChangeRecorder; monitor->fetchCollection( true ); monitor->itemFetchScope().fetchFullPayload(); monitor->setCollectionMonitored( Akonadi::Collection::root() ); monitor->setMimeTypeMonitored( KABC::Addressee::mimeType() ); ContactCompletionModel *model = new ContactCompletionModel( Session::defaultSession(), monitor ); KDescendantsProxyModel *descModel = new KDescendantsProxyModel( model ); descModel->setSourceModel( model ); EntityMimeTypeFilterModel *filter = new Akonadi::EntityMimeTypeFilterModel( model ); filter->setSourceModel( descModel ); filter->addMimeTypeExclusionFilter( Akonadi::Collection::mimeType() ); filter->setHeaderGroup( Akonadi::EntityTreeModel::ItemListHeaders ); mSelf = filter; return mSelf; } ContactCompletionModel::ContactCompletionModel( Session *session, ChangeRecorder *monitor, QObject *parent ) : EntityTreeModel( session, monitor, parent ) { } ContactCompletionModel::~ContactCompletionModel() { } QVariant ContactCompletionModel::entityData( const Item &item, int column, int role ) const { if ( !item.hasPayload() ) { // Pass modeltest if ( role == Qt::DisplayRole ) return item.remoteId(); return QVariant(); } if ( role == Qt::DisplayRole || role == Qt::EditRole ) { const KABC::Addressee contact = item.payload(); switch ( column ) { case NameColumn: if ( !contact.formattedName().isEmpty() ) return contact.formattedName(); else return contact.assembledName(); break; case NameAndEmailColumn: { QString name = QString::fromLatin1( "%1 %2" ).arg( contact.givenName() ) .arg( contact.familyName() ).simplified(); if ( name.isEmpty() ) name = contact.organization().simplified(); if ( name.isEmpty() ) return QString(); const QString email = contact.preferredEmail().simplified(); if ( email.isEmpty() ) return QString(); return QString::fromLatin1( "%1 <%2>" ).arg( name ).arg( email ); } break; case EmailColumn: return contact.preferredEmail(); break; } } return EntityTreeModel::entityData( item, column, role ); } QVariant ContactCompletionModel::entityData( const Collection &collection, int column, int role ) const { return EntityTreeModel::entityData( collection, column, role ); } int ContactCompletionModel::columnCount( const QModelIndex &parent ) const { if ( !parent.isValid() ) return 3; else return 0; } int ContactCompletionModel::entityColumnCount( HeaderGroup ) const { return 3; } #include "contactcompletionmodel_p.moc" diff --git a/akonadi/kdescendantsproxymodel.cpp b/akonadi/kdescendantsproxymodel.cpp index b7289c5f5..04b1a023b 100644 --- a/akonadi/kdescendantsproxymodel.cpp +++ b/akonadi/kdescendantsproxymodel.cpp @@ -1,909 +1,909 @@ /* 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 "kdescendantsproxymodel.h" +#include "kdescendantsproxymodel_p.h" #include "kdebug.h" #include /** @internal Private implementation of DescendantsProxyModel. */ class KDescendantsProxyModelPrivate { public: KDescendantsProxyModelPrivate(KDescendantsProxyModel *model) : q_ptr(model), m_displayAncestorData( false ), m_ancestorSeparator( QLatin1String( " / " ) ) { } Q_DECLARE_PUBLIC( KDescendantsProxyModel ) KDescendantsProxyModel *q_ptr; /** @internal Returns the @p row -th descendant of sourceParent. For example, if the source model looks like: @code -> Item 0-0 (this is row-depth) -> -> Item 0-1 -> -> Item 1-1 -> -> -> Item 0-2 -> -> -> Item 1-2 -> Item 1-0 @endcode Then findSourceIndexForRow(3, index(Item 0-0)) will return an index for Item 1-2 @returns The model index in the source model. */ QModelIndex findSourceIndexForRow( int row, QModelIndex sourceParent) const; /** @internal Returns true if @p sourceIndex has a ancestor that is m_rootDescendIndex. Note that isDescended(m_rootDescendIndex) is false; @param sourceIndex The index in the source model. @returns Whether sourceIndex is an ancestor of rootIndex */ bool isDescended(const QModelIndex &sourceIndex) const; /** @internal Returns the number of descendants below @p sourceIndex. For example, if the source model looks like: @code -> Item 0-0 (this is row-depth) -> -> Item 0-1 -> -> Item 1-1 -> -> -> Item 0-2 -> -> -> Item 1-2 -> Item 1-0 @endcode The descendant count of the rootIndex would be 6, of Item 0-0 would be 4, of Item 1-1 would be 2, of Item 1-2 would be 0 etc. */ int descendantCount(const QModelIndex &sourceIndex, int ignoreTerminals=ObserveTerminals) const; enum TerminalIgnorance { ObserveTerminals, IgnoreTerminals }; /** @internal Returns the row of @p sourceIndex below the rootDescendIndex. For example, if the source model looks like: @code -> Item 0-0 (this is row-depth) -> -> Item 0-1 -> -> Item 1-1 -> -> -> Item 0-2 -> -> -> Item 1-2 -> Item 1-0 @endcode Then descendedRow(index(Item 0-0) would be 0, descendedRow(index(Item 0-1) would be 1, descendedRow(index(Item 0-2) would be 3, descendedRow(index(Item 1-0) would be 5 etc. @returns The row in the proxy model where @p sourceIndex is represented. */ int descendedRow(const QModelIndex &sourceIndex) const; QModelIndexList matchDescendants(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags, int until, const bool matchAll) const; enum Operation { InsertOperation, RemoveOperation }; void insertOrRemoveRows(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, int type); void sourceRowsAboutToBeInserted(const QModelIndex &, int start, int end); void sourceRowsInserted(const QModelIndex &, int start, int end); void sourceRowsAboutToBeRemoved(const QModelIndex &, int start, int end); void sourceRowsRemoved(const QModelIndex &, int start, int end); void sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow); void sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow); void sourceModelAboutToBeReset(); void sourceModelReset(); void sourceLayoutAboutToBeChanged(); void sourceLayoutChanged(); void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); QPersistentModelIndex m_rootDescendIndex; // Hmm, if I make this QHash instead then moves are // automatically handled. Nope, they're not. deeper levels than base would // still need to be updated or calculated. mutable QHash m_descendantsCount; bool m_displayAncestorData; QString m_ancestorSeparator; QList m_terminalIndexes; void descendNewIndexes(); QList m_layoutChangePersistentIndexes; QModelIndexList m_proxyIndexes; }; KDescendantsProxyModel::KDescendantsProxyModel( QObject *parent ) : QAbstractProxyModel( parent ), d_ptr( new KDescendantsProxyModelPrivate(this) ) { Q_D(KDescendantsProxyModel); d->m_rootDescendIndex = QModelIndex(); } void KDescendantsProxyModel::setRootIndex(const QModelIndex &index) { Q_D(KDescendantsProxyModel); if (index.isValid()) Q_ASSERT(index.model() == sourceModel()); d->m_rootDescendIndex = index; d->m_descendantsCount.clear(); reset(); } KDescendantsProxyModel::~KDescendantsProxyModel() { Q_D(KDescendantsProxyModel); d->m_descendantsCount.clear(); delete d_ptr; } QModelIndex KDescendantsProxyModelPrivate::findSourceIndexForRow( int row, QModelIndex idx ) const { Q_Q( const KDescendantsProxyModel ); int childCount = q->sourceModel()->rowCount(idx); for (int childRow = 0; childRow < childCount; childRow++) { QModelIndex childIndex = q->sourceModel()->index(childRow, 0, idx); if (row == 0) { return childIndex; } row--; if (q->sourceModel()->hasChildren(childIndex)) { int childDesc = descendantCount(childIndex); if (childDesc > row) { return findSourceIndexForRow(row, childIndex); } row -= childDesc; } } // This should probably never happen if you use descendantCount before calling this method. return QModelIndex(); } void KDescendantsProxyModel::setSourceModel(QAbstractItemModel * sourceModel) { Q_D(KDescendantsProxyModel); disconnect( sourceModel, SIGNAL(modelReset()), this, SLOT( sourceModelReset() ) ); disconnect( sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset() ) ); disconnect( sourceModel, SIGNAL(layoutChanged()), this, SLOT(sourceLayoutChanged()) ); disconnect( sourceModel, SIGNAL(layoutAboutToBeChanged()), this, SLOT(sourceLayoutAboutToBeChanged()) ); disconnect( sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex & ) ) ); disconnect( sourceModel, SIGNAL(rowsInserted(const QModelIndex, int, int)), this, SLOT(sourceRowsInserted(const QModelIndex, int, int)) ); disconnect( sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex, int, int)), this, SLOT(sourceRowsAboutToBeInserted(const QModelIndex, int, int)) ); disconnect( sourceModel, SIGNAL(rowsRemoved(const QModelIndex, int, int)), this, SLOT(sourceRowsRemoved(const QModelIndex, int, int)) ); disconnect( sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex, int, int)), this, SLOT(sourceRowsAboutToBeRemoved(const QModelIndex, int, int)) ); disconnect( sourceModel, SIGNAL(rowsMoved(const QModelIndex, int, int, const QModelIndex, int)), this, SLOT(sourceRowsMoved(const QModelIndex, int, int, const QModelIndex, int)) ); disconnect( sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex, int, int, const QModelIndex, int)), this, SLOT(sourceRowsAboutToBeMoved(const QModelIndex, int, int, const QModelIndex, int) ) ); QAbstractProxyModel::setSourceModel( sourceModel ); connect( sourceModel, SIGNAL(modelReset()), SLOT( sourceModelReset() ) ); connect( sourceModel, SIGNAL(modelAboutToBeReset()), SLOT(sourceModelAboutToBeReset() ) ); connect( sourceModel, SIGNAL(layoutChanged()), SLOT(sourceLayoutChanged()) ); connect( sourceModel, SIGNAL(layoutAboutToBeChanged()), SLOT(sourceLayoutAboutToBeChanged()) ); connect( sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex & ) ) ); connect( sourceModel, SIGNAL(rowsInserted(const QModelIndex, int, int)), SLOT(sourceRowsInserted(const QModelIndex, int, int)) ); connect( sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex, int, int)), SLOT(sourceRowsAboutToBeInserted(const QModelIndex, int, int)) ); connect( sourceModel, SIGNAL(rowsRemoved(const QModelIndex, int, int)), SLOT(sourceRowsRemoved(const QModelIndex, int, int)) ); connect( sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex, int, int)), SLOT(sourceRowsAboutToBeRemoved(const QModelIndex, int, int)) ); connect( sourceModel, SIGNAL(rowsMoved(const QModelIndex, int, int, const QModelIndex, int)), SLOT(sourceRowsMoved(const QModelIndex, int, int, const QModelIndex, int)) ); connect( sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex, int, int, const QModelIndex, int)), SLOT(sourceRowsAboutToBeMoved(const QModelIndex, int, int, const QModelIndex, int) ) ); d->m_descendantsCount.clear(); reset(); } bool KDescendantsProxyModelPrivate::isDescended(const QModelIndex &sourceIndex) const { Q_Q(const KDescendantsProxyModel); if (sourceIndex == m_rootDescendIndex) { return false; } QModelIndex parentIndex = q->sourceModel()->parent(sourceIndex); if (parentIndex == m_rootDescendIndex) { return true; } bool found = false; forever { parentIndex = parentIndex.parent(); if (parentIndex == m_rootDescendIndex) { found = true; break; } if (!parentIndex.isValid()) break; } return found; } int KDescendantsProxyModelPrivate::descendedRow(const QModelIndex &sourceIndex) const { Q_Q(const KDescendantsProxyModel); QModelIndex parentIndex = sourceIndex.parent(); int row = sourceIndex.row(); for (int childRow = 0; childRow < sourceIndex.row(); childRow++ ) { QModelIndex childIndex = q->sourceModel()->index( childRow, sourceIndex.column(), parentIndex ); if (q->sourceModel()->hasChildren(childIndex)) row += descendantCount(childIndex); } if (parentIndex == m_rootDescendIndex) { // Return 0 instead of -1 for an invalid index. if (row < 0) { return 0; } return row; } else if(!parentIndex.isValid()) { // Should never happen. // Someone must have called this with sourceIndex outside of m_rootDescendIndex return 0; } else { int dr = descendedRow(parentIndex); return row + dr + 1; } } QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex & sourceIndex) const { Q_D(const KDescendantsProxyModel); if (sourceIndex == d->m_rootDescendIndex) { return QModelIndex(); } if ( d->isDescended( sourceIndex ) ) { int row = d->descendedRow( sourceIndex ); if (row < 0) return QModelIndex(); return createIndex( row, sourceIndex.column() ); } else { return QModelIndex(); } } void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &sourceParentIndex, int start, int end) { insertOrRemoveRows(sourceParentIndex, start, end, InsertOperation); } void KDescendantsProxyModelPrivate::insertOrRemoveRows(const QModelIndex &sourceParentIndex, int start, int end, int operationType) { Q_Q(KDescendantsProxyModel); int c = descendedRow(sourceParentIndex); // Can't simply get the descendantCount of sourceModel()->index(start, 0, sourceParent), // because start might not exist as a child of sourceParent yet. // Maybe I should special case (!sourceParent.hasChildren) instead. // Only the first column can have child items. It is only those we need to count. const int column = 0; for (int childRow = 0; childRow < start; childRow++) { QModelIndex childIndex = q->sourceModel()->index( childRow, column, sourceParentIndex ); // kDebug() << childIndex << descendantCount(childIndex); if (q->sourceModel()->hasChildren(childIndex)) c += descendantCount(childIndex); } // @code // -> Item 0-0 (this is row-depth) // -> -> Item 0-1 // -> -> Item 1-1 // -> -> -> Item 0-2 // -> -> -> Item 1-2 // -> Item 1-0 // @endcode // // If the sourceModel reports that a row is inserted between Item 0-2 Item 1-2, // this methods receives a sourceParent of Item 1-1, and a start of 1. // It has a descendedRow of 2. The proxied start is the number of rows above parent, // and the start below parent. The parent itself must also be accounted for if it // is part of the model. // Check if it's descended instead? int proxy_start = c + start; int proxy_end = c + end; if (isDescended(sourceParentIndex)) { proxy_start++; proxy_end++; } if (operationType == InsertOperation) q->beginInsertRows(m_rootDescendIndex, proxy_start, proxy_end); else if (operationType == RemoveOperation) { // need to notify that we're also removing the descendants. for (int childRow = start; childRow <= end; childRow++) { QModelIndex childIndex = q->sourceModel()->index(childRow, column, sourceParentIndex); if (q->sourceModel()->hasChildren(childIndex)) proxy_end += descendantCount(childIndex); } Q_ASSERT( proxy_end <= q->rowCount() ); q->beginRemoveRows(m_rootDescendIndex, proxy_start, proxy_end); } } void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &sourceParentIndex, int start, int end) { Q_Q(KDescendantsProxyModel); m_descendantsCount.clear(); // Don't count the descendants of newly inserted indexes until after endInsertRows. // The reason for this is that at the time we emitted beginInsertRows, we couldn't count the descendants // of new items (they weren't known to the sourceModel), and now we can. const int column = 0; for (int childRow = start; childRow <= end; childRow++) { QModelIndex childIndex = q->sourceModel()->index( childRow, column, sourceParentIndex ); m_terminalIndexes << QPersistentModelIndex(childIndex); } q->endInsertRows(); descendNewIndexes(); } void KDescendantsProxyModelPrivate::descendNewIndexes() { Q_Q(KDescendantsProxyModel); QMutableListIterator i(m_terminalIndexes); while (i.hasNext()) { QModelIndex idx = i.next(); int descCount = descendantCount(idx, IgnoreTerminals); if (descCount <= 0) { i.remove(); continue; } // if descCount > 0, this is a new index which has new child indexes. int proxyStart = descendedRow(idx); // Need to ignore terminals so we know how many rows will be inserted by removing them. int proxyEnd = proxyStart + descendantCount(idx, IgnoreTerminals); if (isDescended(idx)) { proxyStart++; proxyEnd++; } q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd - 1 ); i.remove(); m_descendantsCount.clear(); q->endInsertRows(); } } void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destRow) { Q_Q(KDescendantsProxyModel); int c = descendedRow(parent); int d = descendedRow(destParent); bool allowMove = q->beginMoveRows(QModelIndex(), c+1+start, c+1+end, QModelIndex(), d+1+destRow); Q_ASSERT(allowMove); } void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &sourceParentIndex, int start, int end, const QModelIndex &destParentIndex, int destRow) { Q_Q(KDescendantsProxyModel); Q_UNUSED(sourceParentIndex); Q_UNUSED(start); Q_UNUSED(end); Q_UNUSED(destParentIndex); Q_UNUSED(destRow); m_descendantsCount.clear(); q->endMoveRows(); } void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { insertOrRemoveRows(parent, start, end, RemoveOperation); } void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &sourceParentIndex, int start, int end) { Q_Q(KDescendantsProxyModel); Q_UNUSED(sourceParentIndex); Q_UNUSED(start); Q_UNUSED(end); m_descendantsCount.clear(); q->endRemoveRows(); } void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset() { Q_Q(KDescendantsProxyModel); q->beginResetModel(); } void KDescendantsProxyModelPrivate::sourceModelReset() { Q_Q(KDescendantsProxyModel); m_descendantsCount.clear(); q->endResetModel(); } void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged() { Q_Q(KDescendantsProxyModel); emit q->layoutAboutToBeChanged(); foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) { m_proxyIndexes << proxyPersistentIndex; m_layoutChangePersistentIndexes << QPersistentModelIndex(q->mapToSource(proxyPersistentIndex)); } } void KDescendantsProxyModelPrivate::sourceLayoutChanged() { Q_Q(KDescendantsProxyModel); for(int i = 0; i < m_proxyIndexes.size(); ++i) { q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i))); } m_layoutChangePersistentIndexes.clear(); m_proxyIndexes.clear(); m_descendantsCount.clear(); emit q->layoutChanged(); } QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const { Q_D(const KDescendantsProxyModel); if (!proxyIndex.isValid()) return d->m_rootDescendIndex; if (proxyIndex.column() >= sourceModel()->columnCount()) return QModelIndex(); QModelIndex idx = d->findSourceIndexForRow( proxyIndex.row(), d->m_rootDescendIndex ); if (proxyIndex.column() > 0) { return sourceModel()->index(idx.row(), proxyIndex.column(), idx.parent()); } return idx; } QVariant KDescendantsProxyModel::data(const QModelIndex & index, int role) const { Q_D(const KDescendantsProxyModel ); if (!sourceModel()) return QVariant(); if (!index.isValid()) return sourceModel()->data(index, role); QModelIndex sourceIndex = mapToSource( index ); if ((d->m_displayAncestorData) && ( role == Qt::DisplayRole ) ) { if (!sourceIndex.isValid()) { return QVariant(); } QString displayData = sourceIndex.data().toString(); sourceIndex = sourceIndex.parent(); while (sourceIndex.isValid()) { displayData.prepend(d->m_ancestorSeparator); displayData.prepend(sourceIndex.data().toString()); sourceIndex = sourceIndex.parent(); } return displayData; } else { return sourceIndex.data(role); } } QMimeData* KDescendantsProxyModel::mimeData( const QModelIndexList & indexes ) const { Q_ASSERT(sourceModel()); QModelIndexList sourceIndexes; foreach(const QModelIndex& index, indexes) sourceIndexes << mapToSource(index); return sourceModel()->mimeData(sourceIndexes); } QStringList KDescendantsProxyModel::mimeTypes() const { Q_ASSERT(sourceModel()); return sourceModel()->mimeTypes(); } bool KDescendantsProxyModel::hasChildren ( const QModelIndex & parent ) const { return rowCount(parent) > 0; } int KDescendantsProxyModel::rowCount(const QModelIndex & proxyIndex) const { Q_D(const KDescendantsProxyModel ); if (!sourceModel() || proxyIndex.column() > 0) return 0; QModelIndex sourceIndex = mapToSource(proxyIndex); if (sourceIndex == d->m_rootDescendIndex) { int c = d->descendantCount(sourceIndex); return c; } return 0; } void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { Q_Q( KDescendantsProxyModel ); int topRow = topLeft.row(); int bottomRow = bottomRight.row(); for(int i = topRow; i <= bottomRow; ++i) { QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent()); QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft); // TODO. If an index does not have any descendants, then we can emit in blocks of rows. // As it is we emit once for each row. QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent()); QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight); emit q->dataChanged(proxyTopLeft, proxyBottomRight); } } int KDescendantsProxyModelPrivate::descendantCount(const QModelIndex &sourceIndex, int ignoreTerminals) const { if (sourceIndex.column() > 0) return 0; if (ObserveTerminals == ignoreTerminals) { if (m_terminalIndexes.contains(sourceIndex)) { return 0; } } Q_Q( const KDescendantsProxyModel ); if (m_descendantsCount.contains(sourceIndex.internalId())) { return m_descendantsCount.value(sourceIndex.internalId()); } int sourceIndexRowCount = q->sourceModel()->rowCount(sourceIndex); if (sourceIndexRowCount == 0) return 0; int c = 0; c += sourceIndexRowCount; int childRow = 0; QModelIndex childIndex = q->sourceModel()->index(childRow, 0, sourceIndex); while (childIndex.isValid()) { c += descendantCount(childIndex); childRow++; childIndex = q->sourceModel()->index(childRow, 0, sourceIndex); } m_descendantsCount.insert( sourceIndex.internalId(), c ); return c; } QModelIndex KDescendantsProxyModel::index(int r, int c, const QModelIndex& parent) const { Q_D(const KDescendantsProxyModel ); if (!sourceModel()) return QModelIndex(); if ( (r < 0) || (c < 0) || (c >= sourceModel()->columnCount() ) ) return QModelIndex(); if ( r >= d->descendantCount(parent) ) return QModelIndex(); // TODO: Use is decended instead? if (parent.isValid()) return QModelIndex(); return createIndex(r, c); } QModelIndex KDescendantsProxyModel::parent(const QModelIndex& proxyIndex) const { Q_UNUSED(proxyIndex); return QModelIndex(); } int KDescendantsProxyModel::columnCount(const QModelIndex &index) const { if (!sourceModel()) return 0; return sourceModel()->columnCount(); } void KDescendantsProxyModel::setDisplayAncestorData( bool display ) { Q_D(KDescendantsProxyModel); d->m_displayAncestorData = display; } bool KDescendantsProxyModel::displayAncestorData() const { Q_D(const KDescendantsProxyModel ); return d->m_displayAncestorData; } void KDescendantsProxyModel::setAncestorSeparator( const QString &separator ) { Q_D(KDescendantsProxyModel); d->m_ancestorSeparator = separator; } QString KDescendantsProxyModel::ancestorSeparator() const { Q_D(const KDescendantsProxyModel ); return d->m_ancestorSeparator; } Qt::ItemFlags KDescendantsProxyModel::flags( const QModelIndex &index ) const { // if index is invalid, it might be mapped to a valid source index with more flags. // Can't allow that... if (!index.isValid()) return 0; return QAbstractProxyModel::flags(index); } QModelIndexList KDescendantsProxyModelPrivate::matchDescendants(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags, int until, const bool matchAll) const { Q_Q(const KDescendantsProxyModel); QModelIndexList matches; if (!start.isValid()) return matches; const int column = start.column(); const int firstRow = 0; QModelIndex idx = start; while (idx.row() <= until) { Q_ASSERT(idx.isValid()); if (q->sourceModel()->hasChildren(idx)) { QModelIndex firstChild = idx.child(firstRow, column); matches << q->match(q->mapFromSource(firstChild), role, value, hits, flags); if (!matchAll && (matches.size() >= hits)) { return matches.mid(0, hits); } } int row = idx.row(); if (row == until) { break; } idx = idx.sibling(row + 1, column); } return matches; } QModelIndexList KDescendantsProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const { Q_D(const KDescendantsProxyModel ); // We only really need to do all this for the AmazingCompletionRole, but there's no clean way to // determine what that is. QModelIndexList sourceList; QModelIndexList proxyList; QModelIndex beginIndex = start; QModelIndex sourceStart = mapToSource(start); QModelIndex parent = sourceModel()->parent(sourceStart); int parentRowCount = sourceModel()->rowCount(sourceModel()->parent(sourceStart)); const bool matchAll = (hits == -1); const int firstHit = 1; const int column = start.column(); const int proxyRowCount = rowCount(); Q_ASSERT(sourceStart.column() == start.column()); sourceList = sourceModel()->match(sourceStart, role, value, firstHit, flags); int lastRow; if (sourceList.isEmpty()) { lastRow = parentRowCount - 1; proxyList = d->matchDescendants(mapToSource(start), role, value, hits, flags, lastRow, matchAll); if (matchAll) return proxyList; return proxyList.mid(0, hits); } else { forever { QModelIndex firstIndexHit; if (sourceList.isEmpty()) { lastRow = parentRowCount - 1; } else { firstIndexHit = sourceList.first(); Q_ASSERT(firstIndexHit.column() == start.column()); lastRow = firstIndexHit.row() - 1; } proxyList << d->matchDescendants(sourceStart, role, value, hits, flags, lastRow, matchAll); if (sourceList.isEmpty()) break; QModelIndex proxyFirst = mapFromSource(firstIndexHit); proxyList << proxyFirst; if (!matchAll && ( proxyList.size() >= hits)) { return proxyList.mid(0, hits); } if (proxyFirst.row() == proxyRowCount - 1) break; sourceStart = mapToSource(index(proxyFirst.row() + 1, proxyFirst.column())); Q_ASSERT(sourceStart.isValid()); sourceList = sourceModel()->match(sourceStart, role, value, firstHit, flags); } } QModelIndex nextStart = start.sibling(start.row() + parentRowCount + 1, column); if (nextStart.isValid()) proxyList << match(nextStart, role, value, hits, flags); if (matchAll) return proxyList; return proxyList.mid(0, hits); } Qt::DropActions KDescendantsProxyModel::supportedDropActions() const { Q_ASSERT(sourceModel()); return sourceModel()->supportedDropActions(); } -#include "moc_kdescendantsproxymodel.cpp" +#include "moc_kdescendantsproxymodel_p.cpp" diff --git a/akonadi/kdescendantsproxymodel_p.h b/akonadi/kdescendantsproxymodel_p.h index b5e21fec3..a762b779e 100644 --- a/akonadi/kdescendantsproxymodel_p.h +++ b/akonadi/kdescendantsproxymodel_p.h @@ -1,212 +1,212 @@ /* 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 DESCENDANTENTITIESPROXYMODEL_H #define DESCENDANTENTITIESPROXYMODEL_H #include #include class KDescendantsProxyModelPrivate; /** @brief Proxy Model for restructuring a Tree into a list. A KDescendantsProxyModel may be used to alter how the items in the tree are presented. Given a model which is represented as a tree: \image html entitytreemodel.png "A plain EntityTreeModel in a view" The KDescendantsProxyModel restructures the sourceModel to represent it as a flat list. @code // ... Create an entityTreeModel KDescendantsProxyModel *descProxy = new KDescendantsProxyModel(this); descProxy->setSourceModel(entityTree); view->setModel(descProxy); @endcode \image html descendantentitiesproxymodel.png "A KDescendantsProxyModel." KDescendantEntitiesProxyModel can also display the ancestors of the index in the source model as part of its display. @code // ... Create an entityTreeModel KDescendantsProxyModel *descProxy = new KDescendantesProxyModel(this); descProxy->setSourceModel(entityTree); // #### This is new descProxy->setDisplayAncestorData(true, QString(" / ")); view->setModel(descProxy); @endcode \image html descendantentitiesproxymodel-withansecnames.png "A KDescendantsProxyModel with ancestor names." @since 4.4 @author Stephen Kelly */ -class KDEUI_EXPORT KDescendantsProxyModel : public QAbstractProxyModel +class KDescendantsProxyModel : public QAbstractProxyModel { Q_OBJECT public: /** * Creates a new descendant entities proxy model. * * @param parent The parent object. */ explicit KDescendantsProxyModel( QObject *parent = 0 ); /** * Destroys the descendant entities proxy model. */ virtual ~KDescendantsProxyModel(); /** * Sets the source @p model of the proxy. */ virtual void setSourceModel( QAbstractItemModel *model ); /** * Sets the root index to @p index. This is the root of the proxy model. * * @param index The root index in the *source* model which will be shown in this model. * If the index is invalid, the model is empty. * * \note You must set the model before setting the root index. */ void setRootIndex( const QModelIndex &index); /** * Set whether to show ancestor data in the model. If @p display is true, then * a source model which is displayed as * * @code * -> "Item 0-0" (this is row-depth) * -> -> "Item 0-1" * -> -> "Item 1-1" * -> -> -> "Item 0-2" * -> -> -> "Item 1-2" * -> "Item 1-0" * @endcode * * will be displayed as * * @code * -> *Item 0-0" * -> "Item 0-0 / Item 0-1" * -> "Item 0-0 / Item 1-1" * -> "Item 0-0 / Item 1-1 / Item 0-2" * -> "Item 0-0 / Item 1-1 / Item 1-2" * -> "Item 1-0" * @endcode * * If @p display is false, the proxy will show * * @code * -> *Item 0-0" * -> "Item 0-1" * -> "Item 1-1" * -> "Item 0-2" * -> "Item 1-2" * -> "Item 1-0" * @endcode * * Default is false. */ void setDisplayAncestorData( bool display ); /** * Whether ancestor data will be displayed. */ bool displayAncestorData() const; /** * Sets the ancestor @p separator used between data of ancestors. */ void setAncestorSeparator( const QString &separator ); /** * Separator used between data of ancestors. */ QString ancestorSeparator() const; /** * Returns the number of descendant entries for the given model @p index. */ int descendantCount( const QModelIndex &index ) const; QModelIndex mapFromSource ( const QModelIndex & sourceIndex ) const; QModelIndex mapToSource ( const QModelIndex & proxyIndex ) const; virtual Qt::ItemFlags flags( const QModelIndex &index ) const; QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual int rowCount( const QModelIndex & parent = QModelIndex() ) const; virtual QMimeData* mimeData( const QModelIndexList & indexes ) const; virtual QStringList mimeTypes() const; virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const; virtual QModelIndex index(int, int, const QModelIndex &parent = QModelIndex() ) const; virtual QModelIndex parent(const QModelIndex&) const; virtual int columnCount(const QModelIndex& index = QModelIndex()) const; virtual Qt::DropActions supportedDropActions() const; /** Reimplemented to match all descendants. */ virtual QModelIndexList match(const QModelIndex& start, int role, const QVariant& value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags( Qt::MatchStartsWith | Qt::MatchWrap ) ) const; private: Q_DECLARE_PRIVATE( KDescendantsProxyModel ) //@cond PRIVATE KDescendantsProxyModelPrivate *d_ptr; Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeInserted(const QModelIndex &, int, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsInserted(const QModelIndex &, int, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsRemoved(const QModelIndex &, int, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)) Q_PRIVATE_SLOT(d_func(), void sourceModelAboutToBeReset()) Q_PRIVATE_SLOT(d_func(), void sourceModelReset()) Q_PRIVATE_SLOT(d_func(), void sourceLayoutAboutToBeChanged()) Q_PRIVATE_SLOT(d_func(), void sourceLayoutChanged()) Q_PRIVATE_SLOT(d_func(), void sourceDataChanged(const QModelIndex &, const QModelIndex &)) // Make these private, they shouldn't be called by applications // virtual bool insertRows(int , int, const QModelIndex & = QModelIndex()); // virtual bool insertColumns(int, int, const QModelIndex & = QModelIndex()); // virtual bool removeRows(int, int, const QModelIndex & = QModelIndex()); // virtual bool removeColumns(int, int, const QModelIndex & = QModelIndex()); //@endcond }; #endif