entityorderproxymodel.cpp
00001 /* 00002 Copyright (C) 2010 Klarälvdalens Datakonsult AB, 00003 a KDAB Group company, info@kdab.net, 00004 author Stephen Kelly <stephen@kdab.com> 00005 00006 This library is free software; you can redistribute it and/or modify it 00007 under the terms of the GNU Library General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or (at your 00009 option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, but WITHOUT 00012 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00014 License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to the 00018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00019 02110-1301, USA. 00020 */ 00021 00022 00023 #include "entityorderproxymodel.h" 00024 00025 #include <QMimeData> 00026 00027 #include <KDE/KConfigGroup> 00028 00029 #include "collection.h" 00030 #include "item.h" 00031 #include "entitytreemodel.h" 00032 00033 namespace Akonadi 00034 { 00035 00036 class EntityOrderProxyModelPrivate 00037 { 00038 public: 00039 EntityOrderProxyModelPrivate( EntityOrderProxyModel *qq ) 00040 : q_ptr( qq ) 00041 { 00042 00043 } 00044 00045 void saveOrder( const QModelIndex &index ); 00046 00047 KConfigGroup m_orderConfig; 00048 00049 Q_DECLARE_PUBLIC(EntityOrderProxyModel) 00050 EntityOrderProxyModel * const q_ptr; 00051 00052 }; 00053 00054 } 00055 00056 using namespace Akonadi; 00057 00058 EntityOrderProxyModel::EntityOrderProxyModel( QObject* parent ) 00059 : QSortFilterProxyModel(parent), d_ptr( new EntityOrderProxyModelPrivate( this ) ) 00060 { 00061 setDynamicSortFilter(true); 00062 } 00063 00064 EntityOrderProxyModel::~EntityOrderProxyModel() 00065 { 00066 delete d_ptr; 00067 } 00068 00069 void EntityOrderProxyModel::setOrderConfig( KConfigGroup& configGroup ) 00070 { 00071 Q_D( EntityOrderProxyModel ); 00072 layoutAboutToBeChanged(); 00073 d->m_orderConfig = configGroup; 00074 layoutChanged(); 00075 } 00076 00077 bool EntityOrderProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const 00078 { 00079 Q_D( const EntityOrderProxyModel ); 00080 00081 if ( !d->m_orderConfig.isValid() ) 00082 return QSortFilterProxyModel::lessThan( left, right ); 00083 00084 Collection col = left.data( EntityTreeModel::ParentCollectionRole ).value<Collection>(); 00085 00086 if ( !d->m_orderConfig.hasKey( QString::number( col.id() ) ) ) 00087 return QSortFilterProxyModel::lessThan( left, right ); 00088 00089 const QStringList list = d->m_orderConfig.readEntry( QString::number( col.id() ), QStringList() ); 00090 00091 if ( list.isEmpty() ) 00092 return QSortFilterProxyModel::lessThan( left, right ); 00093 00094 const QString leftValue = configString( left ); 00095 const QString rightValue = configString( right ); 00096 00097 const int leftPosition = list.indexOf( leftValue ); 00098 const int rightPosition = list.indexOf( rightValue ); 00099 00100 if ( leftPosition < 0 || rightPosition < 0 ) 00101 return QSortFilterProxyModel::lessThan( left, right ); 00102 00103 return leftPosition < rightPosition; 00104 } 00105 00106 bool EntityOrderProxyModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent ) 00107 { 00108 Q_D( EntityOrderProxyModel ); 00109 00110 if ( !d->m_orderConfig.isValid() ) 00111 return QSortFilterProxyModel::dropMimeData( data, action, row, column, parent ); 00112 00113 if ( !data->hasFormat( QLatin1String( "text/uri-list" ) ) ) 00114 return QSortFilterProxyModel::dropMimeData( data, action, row, column, parent ); 00115 00116 if ( row == -1 ) 00117 return QSortFilterProxyModel::dropMimeData( data, action, row, column, parent ); 00118 00119 bool containsMove = false; 00120 00121 const KUrl::List urls = KUrl::List::fromMimeData( data ); 00122 00123 Collection parentCol; 00124 00125 if (parent.isValid()) 00126 parentCol = parent.data( EntityTreeModel::CollectionRole ).value<Collection>(); 00127 else 00128 { 00129 if (!hasChildren(parent)) 00130 return QSortFilterProxyModel::dropMimeData( data, action, row, column, parent ); 00131 00132 const QModelIndex targetIndex = index( 0, column, parent ); 00133 00134 parentCol = targetIndex.data( EntityTreeModel::ParentCollectionRole ).value<Collection>(); 00135 } 00136 00137 QStringList droppedList; 00138 foreach ( const KUrl &url, urls ) { 00139 Collection col = Collection::fromUrl( url ); 00140 00141 if ( !col.isValid() ) 00142 { 00143 Item item = Item::fromUrl( url ); 00144 if ( !item.isValid() ) 00145 continue; 00146 00147 const QModelIndexList list = EntityTreeModel::modelIndexesForItem( this, item ); 00148 if ( list.isEmpty() ) 00149 continue; 00150 00151 if ( !containsMove && list.first().data( EntityTreeModel::ParentCollectionRole ).value<Collection>().id() != parentCol.id() ) 00152 containsMove = true; 00153 00154 droppedList << configString( list.first() ); 00155 } else { 00156 const QModelIndex idx = EntityTreeModel::modelIndexForCollection( this, col ); 00157 if ( !idx.isValid() ) 00158 continue; 00159 00160 if ( !containsMove && idx.data( EntityTreeModel::ParentCollectionRole ).value<Collection>().id() != parentCol.id() ) 00161 containsMove = true; 00162 00163 droppedList << configString( idx ); 00164 } 00165 } 00166 00167 QStringList existingList; 00168 if ( d->m_orderConfig.hasKey( QString::number( parentCol.id() ) ) ) { 00169 existingList = d->m_orderConfig.readEntry( QString::number( parentCol.id() ), QStringList() ); 00170 } else { 00171 const QModelIndex sourceIndex = mapToSource( parent ); 00172 const int rowCount = sourceModel()->rowCount( sourceIndex ); 00173 for (int row = 0; row < rowCount; ++row) { 00174 static const int column = 0; 00175 const QModelIndex idx = sourceModel()->index( row, column, sourceIndex ); 00176 existingList.append( configString( idx ) ); 00177 } 00178 } 00179 const int numberOfDroppedElement( droppedList.size() ); 00180 for ( int i = 0; i < numberOfDroppedElement; ++i ) 00181 { 00182 const QString droppedItem = droppedList.at( i ); 00183 const int existingIndex = existingList.indexOf( droppedItem ); 00184 existingList.removeAt( existingIndex ); 00185 existingList.insert( row + i - (existingIndex > row ? 0 : 1), droppedList.at( i ) ); 00186 } 00187 00188 d->m_orderConfig.writeEntry( QString::number( parentCol.id() ), existingList ); 00189 00190 if ( containsMove ) 00191 { 00192 bool result = QSortFilterProxyModel::dropMimeData( data, action, row, column, parent ); 00193 invalidate(); 00194 return result; 00195 } 00196 invalidate(); 00197 return true; 00198 } 00199 00200 QModelIndexList EntityOrderProxyModel::match( const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags ) const 00201 { 00202 if ( role < Qt::UserRole ) 00203 return QSortFilterProxyModel::match( start, role, value, hits, flags ); 00204 00205 QModelIndexList list; 00206 QModelIndex proxyIndex; 00207 foreach ( const QModelIndex &idx, sourceModel()->match( mapToSource( start ), role, value, hits, flags ) ) { 00208 proxyIndex = mapFromSource( idx ); 00209 if ( proxyIndex.isValid() ) 00210 list << proxyIndex; 00211 } 00212 00213 return list; 00214 } 00215 00216 void EntityOrderProxyModelPrivate::saveOrder( const QModelIndex &parent ) 00217 { 00218 Q_Q( const EntityOrderProxyModel ); 00219 int rowCount = q->rowCount( parent ); 00220 00221 if ( rowCount == 0 ) 00222 return; 00223 00224 static const int column = 0; 00225 QModelIndex childIndex = q->index( 0, column, parent ); 00226 00227 QString parentKey = q->parentConfigString( childIndex ); 00228 00229 if ( parentKey.isEmpty() ) 00230 return; 00231 00232 QStringList list; 00233 00234 list << q->configString( childIndex ); 00235 saveOrder( childIndex ); 00236 00237 for ( int row = 1; row < rowCount; ++row ) 00238 { 00239 childIndex = q->index( row, column, parent ); 00240 list << q->configString( childIndex ); 00241 saveOrder( childIndex ); 00242 } 00243 00244 m_orderConfig.writeEntry( parentKey, list ); 00245 } 00246 00247 QString EntityOrderProxyModel::parentConfigString( const QModelIndex& index ) const 00248 { 00249 const Collection col = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>(); 00250 00251 Q_ASSERT( col.isValid() ); 00252 if ( !col.isValid() ) 00253 return QString(); 00254 00255 return QString::number( col.id() ); 00256 } 00257 00258 QString EntityOrderProxyModel::configString( const QModelIndex& index ) const 00259 { 00260 Entity::Id eId = index.data( EntityTreeModel::ItemIdRole ).toLongLong(); 00261 if ( eId != -1 ) 00262 { 00263 return QString::fromLatin1( "i" ) + QString::number( eId ); 00264 } 00265 eId = index.data( EntityTreeModel::CollectionIdRole ).toLongLong(); 00266 if ( eId != -1 ) 00267 { 00268 return QString::fromLatin1( "c" ) + QString::number( eId ); 00269 } 00270 Q_ASSERT( !"Invalid entity" ); 00271 return QString(); 00272 } 00273 00274 void EntityOrderProxyModel::saveOrder() 00275 { 00276 Q_D( EntityOrderProxyModel ); 00277 d->saveOrder( QModelIndex() ); 00278 d->m_orderConfig.sync(); 00279 } 00280 00281 void EntityOrderProxyModel::clearOrder( const QModelIndex& parent ) 00282 { 00283 Q_D( EntityOrderProxyModel ); 00284 00285 const QString parentKey = parentConfigString( index( 0, 0, parent ) ); 00286 00287 if ( parentKey.isEmpty() ) 00288 return; 00289 00290 d->m_orderConfig.deleteEntry( parentKey ); 00291 invalidate(); 00292 } 00293 00294 void EntityOrderProxyModel::clearTreeOrder() 00295 { 00296 Q_D( EntityOrderProxyModel ); 00297 d->m_orderConfig.deleteGroup(); 00298 invalidate(); 00299 }