Kross
model.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 * model.cpp 00003 * This file is part of the KDE project 00004 * copyright (C) 2006-2007 by Sebastian Sauer (mail@dipe.org) 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * You should have received a copy of the GNU Library General Public License 00015 * along with this program; see the file COPYING. If not, write to 00016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 * Boston, MA 02110-1301, USA. 00018 ***************************************************************************/ 00019 00020 #include "model.h" 00021 00022 #include <kross/core/action.h> 00023 #include <kross/core/actioncollection.h> 00024 #include <kross/core/manager.h> 00025 00026 #include <kglobal.h> 00027 #include <klocale.h> 00028 #include <kdebug.h> 00029 00030 #include <QtCore/QEvent> 00031 #include <QtCore/QMimeData> 00032 #include <QtCore/QPointer> 00033 00034 using namespace Kross; 00035 00036 /****************************************************************************** 00037 * ActionCollectionModel 00038 */ 00039 00040 namespace Kross { 00041 00043 class ActionCollectionModel::Private 00044 { 00045 public: 00046 QPointer<ActionCollection> collection; 00047 Mode mode; 00048 }; 00049 00050 } 00051 00052 ActionCollectionModel::ActionCollectionModel(QObject* parent, ActionCollection* collection, Mode mode) 00053 : QAbstractItemModel(parent) 00054 , d( new Private() ) 00055 { 00056 //krossdebug( QString( "ActionCollectionModel::ActionCollectionModel:") ); 00057 d->collection = collection ? collection : Kross::Manager::self().actionCollection(); 00058 d->mode = mode; 00059 //setSupportedDragActions(Qt::MoveAction); 00060 00061 //ActionCollection propagates signals to parent 00062 QObject::connect( d->collection, SIGNAL( dataChanged( Action* ) ), this, SLOT( slotDataChanged( Action* ) ) ); 00063 QObject::connect( d->collection, SIGNAL( dataChanged( ActionCollection* ) ), this, SLOT( slotDataChanged( ActionCollection* ) ) ); 00064 00065 QObject::connect( d->collection, SIGNAL( collectionToBeInserted( ActionCollection*, ActionCollection* ) ), this, SLOT( slotCollectionToBeInserted( ActionCollection*, ActionCollection* ) ) ); 00066 QObject::connect( d->collection, SIGNAL( collectionInserted( ActionCollection*, ActionCollection* ) ), this, SLOT( slotCollectionInserted( ActionCollection*, ActionCollection* ) ) ); 00067 QObject::connect( d->collection, SIGNAL( collectionToBeRemoved( ActionCollection*, ActionCollection* ) ), this, SLOT( slotCollectionToBeRemoved( ActionCollection*, ActionCollection* ) ) ); 00068 QObject::connect( d->collection, SIGNAL( collectionRemoved( ActionCollection*, ActionCollection* ) ), this, SLOT( slotCollectionRemoved( ActionCollection*, ActionCollection* ) ) ); 00069 00070 QObject::connect( d->collection, SIGNAL( actionToBeInserted( Action*, ActionCollection* ) ), this, SLOT( slotActionToBeInserted( Action*, ActionCollection* ) ) ); 00071 QObject::connect( d->collection, SIGNAL( actionInserted( Action*, ActionCollection* ) ), this, SLOT( slotActionInserted( Action*, ActionCollection* ) ) ); 00072 QObject::connect( d->collection, SIGNAL( actionToBeRemoved( Action*, ActionCollection* ) ), this, SLOT( slotActionToBeRemoved( Action*, ActionCollection* ) ) ); 00073 QObject::connect( d->collection, SIGNAL( actionRemoved( Action*, ActionCollection* ) ), this, SLOT( slotActionRemoved( Action*, ActionCollection* ) ) ); 00074 } 00075 00076 ActionCollectionModel::~ActionCollectionModel() 00077 { 00078 delete d; 00079 } 00080 00081 ActionCollection *ActionCollectionModel::rootCollection() const 00082 { 00083 return d->collection; 00084 } 00085 00086 int ActionCollectionModel::rowNumber( ActionCollection *collection ) const 00087 { 00088 Q_ASSERT( collection != 0 ); 00089 ActionCollection *par = collection->parentCollection(); 00090 Q_ASSERT( par != 0 ); 00091 int row = par->collections().indexOf( collection->objectName() ) + par->actions().count(); 00092 return row; 00093 } 00094 00095 QModelIndex ActionCollectionModel::indexForCollection( ActionCollection *collection ) const 00096 { 00097 if ( collection == d->collection ) { 00098 return QModelIndex(); 00099 } 00100 return createIndex( rowNumber( collection ), 0, collection->parentCollection() ); 00101 } 00102 00103 QModelIndex ActionCollectionModel::indexForAction( Action *act ) const 00104 { 00105 ActionCollection *coll = static_cast<ActionCollection*>( act->parent() ); 00106 return createIndex( coll->actions().indexOf( act ), 0, coll ); 00107 } 00108 00109 void ActionCollectionModel::slotCollectionToBeInserted( ActionCollection* child, ActionCollection* parent ) 00110 { 00111 //krossdebug( QString( "ActionCollectionModel::slotCollectionToBeInserted: %1 %2" ).arg( child->name() ).arg( parent->name( ) ) ); 00112 Q_ASSERT( parent ); 00113 Q_UNUSED( child ) 00114 int row = parent->actions().count() + parent->collections().count(); // we assume child is appended!! 00115 QModelIndex parIdx = indexForCollection( parent ); 00116 beginInsertRows( parIdx, row, row ); 00117 } 00118 00119 void ActionCollectionModel::slotCollectionInserted( ActionCollection*, ActionCollection* ) 00120 { 00121 //krossdebug( QString( "ActionCollectionModel::slotCollectionInserted: %1 %2" ).arg( child->name( ) ).arg( parent->name( ) ) ); 00122 endInsertRows(); 00123 } 00124 00125 void ActionCollectionModel::slotCollectionToBeRemoved( ActionCollection* child, ActionCollection* parent ) 00126 { 00127 //krossdebug( QString( "ActionCollectionModel::slotCollectionToBeRemoved: %1 %2" ).arg( child->name() ).arg( parent->name() ) ); 00128 int row = rowNumber( child ); 00129 QModelIndex parIdx = indexForCollection( parent ); 00130 beginRemoveRows( parIdx, row, row ); 00131 } 00132 00133 void ActionCollectionModel::slotCollectionRemoved( ActionCollection*, ActionCollection* ) 00134 { 00135 //krossdebug( QString( "ActionCollectionModel::slotCollectionRemoved: %1 %2" ).arg( child->name() ).arg( parent->name() ) ); 00136 endRemoveRows(); 00137 } 00138 00139 void ActionCollectionModel::slotActionToBeInserted( Action* child, ActionCollection* parent ) 00140 { 00141 //krossdebug( QString( "ActionCollectionModel::slotActionInserted: %1 %2" ).arg( child->name() ).arg( parent->name() ) ); 00142 Q_ASSERT( parent ); 00143 Q_UNUSED( child ) 00144 int row = parent->actions().count(); // assume child is appended to actions!! 00145 QModelIndex parIdx = indexForCollection( parent ); 00146 beginInsertRows( parIdx, row, row ); 00147 } 00148 00149 void ActionCollectionModel::slotActionInserted( Action*, ActionCollection* ) 00150 { 00151 //krossdebug( QString( "ActionCollectionModel::slotActionInserted: %1 %2" ).arg( child->name() ).arg( parent->name() ) ); 00152 endInsertRows(); 00153 } 00154 00155 void ActionCollectionModel::slotActionToBeRemoved( Action* child, ActionCollection* parent ) 00156 { 00157 //krossdebug( QString( "ActionCollectionModel::slotActionToBeRemoved: %1 %2" ).arg( child->name() ).arg( parent->name() ) ); 00158 Q_ASSERT( parent ); 00159 int row = parent->actions().indexOf( child ); 00160 QModelIndex parIdx = indexForCollection( parent ); 00161 beginRemoveRows( parIdx, row, row ); 00162 } 00163 00164 void ActionCollectionModel::slotActionRemoved( Action*, ActionCollection* ) 00165 { 00166 //krossdebug( QString( "ActionCollectionModel::slotActionRemoved: %1 %2" ).arg( child->name() ).arg( parent->name() ) ); 00167 endRemoveRows(); 00168 } 00169 00170 //NOTE: not used anymore, remove? 00171 void ActionCollectionModel::slotUpdated() 00172 { 00173 //emit layoutAboutToBeChanged(); 00174 //emit layoutChanged(); 00175 } 00176 00177 void ActionCollectionModel::slotDataChanged( ActionCollection* coll ) 00178 { 00179 //krossdebug( QString( "ActionCollectionModel::slotDataChanged: %1" ).arg( coll->name() ) ); 00180 QModelIndex idx = indexForCollection( coll ); 00181 emit dataChanged( idx, idx ); // NOTE: change if more than one column 00182 } 00183 00184 void ActionCollectionModel::slotDataChanged( Action* act ) 00185 { 00186 //krossdebug( QString( "ActionCollectionModel::slotDataChanged: %1" ).arg( act->name() ) ); 00187 QModelIndex idx = indexForAction( act ); 00188 emit dataChanged( idx, idx ); // NOTE: change if more than one column 00189 } 00190 00191 Action* ActionCollectionModel::action(const QModelIndex& index) 00192 { 00193 ActionCollection *par = static_cast<ActionCollection*>( index.internalPointer() ); 00194 if ( par == 0 || index.row() >= par->actions().count() ) { 00195 return 0; 00196 } 00197 return par->actions().value( index.row() ); 00198 } 00199 00200 ActionCollection* ActionCollectionModel::collection(const QModelIndex& index) 00201 { 00202 ActionCollection *par = static_cast<ActionCollection*>( index.internalPointer() ); 00203 if ( par == 0 ) { 00204 return 0; 00205 } 00206 int row = index.row() - par->actions().count(); 00207 if ( row < 0 ) { 00208 return 0; // this is probably an action 00209 } 00210 return par->collection( par->collections().value( row) ); 00211 } 00212 00213 int ActionCollectionModel::columnCount(const QModelIndex&) const 00214 { 00215 return 1; 00216 } 00217 00218 int ActionCollectionModel::rowCount(const QModelIndex& index) const 00219 { 00220 if ( action( index) ) { 00221 return 0; 00222 } 00223 ActionCollection* par = index.isValid() ? collection( index ) : d->collection.data(); 00224 Q_ASSERT_X( par, "ActionCollectionModel::rowCount", "index is not an action nor a collection" ); 00225 if (!par) { 00226 kWarning()<<"index is not an action nor a collection"<<index; 00227 return 0; 00228 } 00229 int rows = par->actions().count() + par->collections().count(); 00230 return rows; 00231 } 00232 00233 QModelIndex ActionCollectionModel::index(int row, int column, const QModelIndex& parent) const 00234 { 00235 if ( ! hasIndex( row, column, parent ) ) { 00236 return QModelIndex(); 00237 } 00238 ActionCollection* par = parent.isValid() ? collection( parent ) : d->collection.data(); 00239 if ( par == 0 ) { 00240 // safety: may happen if parent index is an action (ModelTest tests this) 00241 return QModelIndex(); 00242 } 00243 return createIndex( row, column, par ); 00244 } 00245 00246 QModelIndex ActionCollectionModel::parent(const QModelIndex& index) const 00247 { 00248 if( ! index.isValid() ) { 00249 return QModelIndex(); 00250 } 00251 ActionCollection *par = static_cast<ActionCollection*>( index.internalPointer() ); 00252 Q_ASSERT( par != 0 ); 00253 if ( par == d->collection ) { 00254 return QModelIndex(); 00255 } 00256 return createIndex( rowNumber( par ), 0, par->parentCollection() ); 00257 } 00258 00259 Qt::ItemFlags ActionCollectionModel::flags(const QModelIndex &index) const 00260 { 00261 Qt::ItemFlags flags = QAbstractItemModel::flags(index); 00262 if( ! index.isValid() ) 00263 return Qt::ItemIsDropEnabled | flags; 00264 00265 flags |= Qt::ItemIsSelectable; 00266 //flags |= Qt::ItemIsEditable; 00267 flags |= Qt::ItemIsDragEnabled; 00268 flags |= Qt::ItemIsDropEnabled; 00269 00270 if( (index.column() == 0) && (d->mode & UserCheckable) ) 00271 flags |= Qt::ItemIsUserCheckable; 00272 return flags; 00273 } 00274 00275 QVariant ActionCollectionModel::data(const QModelIndex& index, int role) const 00276 { 00277 if( index.isValid() ) { 00278 Action *act = action( index ); 00279 if ( act ) { 00280 switch( role ) { 00281 case Qt::DecorationRole: { 00282 if( d->mode & Icons ) 00283 if( ! act->iconName().isEmpty() ) 00284 return act->icon(); 00285 } break; 00286 case Qt::DisplayRole: 00287 return KGlobal::locale()->removeAcceleratorMarker( act->text() ); 00288 case Qt::ToolTipRole: // fall through 00289 case Qt::WhatsThisRole: { 00290 if( d->mode & ToolTips ) { 00291 const QString file = QFileInfo( act->file() ).fileName(); 00292 return QString( "<qt><b>%1</b><br>%2</qt>" ) 00293 .arg( file.isEmpty() ? act->name() : file ) 00294 .arg( act->description() ); 00295 } 00296 } break; 00297 case Qt::CheckStateRole: { 00298 if( d->mode & UserCheckable ) 00299 return act->isEnabled() ? Qt::Checked : Qt::Unchecked; 00300 } break; 00301 default: break; 00302 } 00303 return QVariant(); 00304 } 00305 ActionCollection *coll = collection( index ); 00306 if ( coll ) { 00307 switch( role ) { 00308 case Qt::DecorationRole: { 00309 if( d->mode & Icons ) 00310 if( ! coll->iconName().isEmpty() ) 00311 return coll->icon(); 00312 } break; 00313 case Qt::DisplayRole: 00314 return coll->text(); 00315 case Qt::ToolTipRole: // fall through 00316 case Qt::WhatsThisRole: { 00317 if( d->mode & ToolTips ) 00318 return QString( "<qt><b>%1</b><br>%2</qt>" ).arg( coll->text() ).arg( coll->description() ); 00319 } break; 00320 case Qt::CheckStateRole: { 00321 if( d->mode & UserCheckable ) 00322 return coll->isEnabled() ? Qt::Checked : Qt::Unchecked; 00323 } break; 00324 default: break; 00325 } 00326 return QVariant(); 00327 } 00328 } 00329 return QVariant(); 00330 } 00331 00332 bool ActionCollectionModel::setData(const QModelIndex &index, const QVariant &value, int role) 00333 { 00334 Q_UNUSED(value); 00335 if( ! index.isValid() /*|| ! (d->mode & UserCheckable)*/ ) 00336 return false; 00337 00338 Action *act = action( index ); 00339 if ( act ) { 00340 switch( role ) { 00341 //case Qt::EditRole: act->setText( value.toString() ); break; 00342 case Qt::CheckStateRole: act->setEnabled( ! act->isEnabled() ); break; 00343 default: return false; 00344 } 00345 return false; 00346 } 00347 ActionCollection *coll = collection( index ); 00348 if ( coll ) { 00349 switch( role ) { 00350 //case Qt::EditRole: item->coll->setText( value.toString() ); break; 00351 case Qt::CheckStateRole: coll->setEnabled( ! coll->isEnabled() ); break; 00352 default: return false; 00353 } 00354 return false; 00355 } 00356 //emit dataChanged(index, index); 00357 return true; 00358 } 00359 00360 bool ActionCollectionModel::insertRows(int row, int count, const QModelIndex& parent) 00361 { 00362 krossdebug( QString("ActionCollectionModel::insertRows: row=%1 count=%2").arg(row).arg(count) ); 00363 if( ! parent.isValid() ) 00364 return false; 00365 00366 ActionCollection* coll = collection( parent ); 00367 if ( coll ) { 00368 krossdebug( QString( "ActionCollectionModel::insertRows: parentindex is ActionCollection with name=%1" ).arg( coll->name() ) ); 00369 } else { 00370 Action *act = action( parent ); 00371 if ( act ) { 00372 krossdebug( QString( "ActionCollectionModel::insertRows: parentindex is Action with name=%1" ).arg( act->name() ) ); 00373 } 00374 } 00375 return QAbstractItemModel::insertRows(row, count, parent); 00376 } 00377 00378 bool ActionCollectionModel::removeRows(int row, int count, const QModelIndex& parent) 00379 { 00380 krossdebug( QString("ActionCollectionModel::removeRows: row=%1 count=%2").arg(row).arg(count) ); 00381 return QAbstractItemModel::removeRows(row, count, parent); 00382 } 00383 00384 bool ActionCollectionModel::insertColumns(int column, int count, const QModelIndex& parent) 00385 { 00386 krossdebug( QString("ActionCollectionModel::insertColumns: column=%1 count=%2").arg(column).arg(count) ); 00387 return QAbstractItemModel::insertColumns(column, count, parent); 00388 } 00389 00390 bool ActionCollectionModel::removeColumns(int column, int count, const QModelIndex& parent) 00391 { 00392 krossdebug( QString("ActionCollectionModel::removeColumns: column=%1 count=%2").arg(column).arg(count) ); 00393 return QAbstractItemModel::removeColumns(column, count, parent); 00394 } 00395 00396 QStringList ActionCollectionModel::mimeTypes() const 00397 { 00398 //krossdebug( QString("ActionCollectionModel::mimeTypes") ); 00399 return QStringList() << "application/vnd.text.list"; 00400 } 00401 00402 QString fullPath(const QModelIndex& index) 00403 { 00404 if( ! index.isValid() ) return QString(); 00405 QString n; 00406 Action *a = ActionCollectionModel::action( index ); 00407 if ( a ) { 00408 n = a->name(); 00409 } else { 00410 ActionCollection *c = ActionCollectionModel::collection( index ); 00411 if ( c ) { 00412 n = c->name() + '/'; 00413 if ( ! n.endsWith('/' ) ) 00414 n += '/'; 00415 } 00416 } 00417 ActionCollection* par = static_cast<ActionCollection*>( index.internalPointer() ); 00418 for ( ActionCollection *p = par; p != 0; p = par->parentCollection() ) { 00419 QString s = p->name(); 00420 if ( ! s.endsWith( '/' ) ) { 00421 s += '/'; 00422 } 00423 n = s + n; 00424 } 00425 return n; 00426 } 00427 00428 QMimeData* ActionCollectionModel::mimeData(const QModelIndexList& indexes) const 00429 { 00430 //krossdebug( QString("ActionCollectionModel::mimeData") ); 00431 QMimeData* mimeData = new QMimeData(); 00432 QByteArray encodedData; 00433 00434 QDataStream stream(&encodedData, QIODevice::WriteOnly); 00435 foreach(const QModelIndex &index, indexes) { 00436 //if( ! index.isValid() ) continue; 00437 //QString text = data(index, Qt::DisplayRole).toString(); 00438 QString path = fullPath(index); 00439 if( ! path.isNull() ) 00440 stream << path; 00441 } 00442 00443 mimeData->setData("application/vnd.text.list", encodedData); 00444 return mimeData; 00445 } 00446 00447 bool ActionCollectionModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) 00448 { 00449 krossdebug( QString("ActionCollectionModel::dropMimeData: row=%1 col=%2").arg(row).arg(column) ); 00450 if( action == Qt::IgnoreAction ) return true; 00451 if( ! data->hasFormat("application/vnd.text.list") ) return false; 00452 if( column > 0 ) return false; 00453 00454 krossdebug( QString("ActionCollectionModel::dropMimeData: ENCODED DATA:") ); 00455 QByteArray encodedData = data->data("application/vnd.text.list"); 00456 QDataStream stream(&encodedData, QIODevice::ReadOnly); 00457 QStringList newItems; 00458 int rows = 0; 00459 while( ! stream.atEnd() ) { 00460 QString text; 00461 stream >> text; 00462 newItems << text; 00463 krossdebug( QString(" %1 \"%2\"").arg(rows).arg(text) ); 00464 ++rows; 00465 } 00466 00467 //FIXME: return false for now since insertRows/removeRows need to be implemented before! 00468 //return false; 00469 00470 /* 00471 int beginRow; 00472 if( row != -1 ) 00473 beginRow = row; 00474 else if( parent.isValid() ) 00475 beginRow = parent.row(); 00476 else 00477 beginRow = rowCount( QModelIndex() ); 00478 krossdebug( QString("ActionCollectionModel::dropMimeData: beginRow=%1").arg(beginRow) ); 00479 */ 00480 00481 QModelIndex targetindex = index( row, column, parent ); 00482 ActionCollection *coll = collection( targetindex ); 00483 if ( coll ) { 00484 krossdebug( QString( "ActionCollectionModel::dropMimeData: parentindex is ActionCollection with name=%1" ).arg( coll->name() ) ); 00485 } else { 00486 Action *act = this->action( targetindex ); 00487 if ( act ) { 00488 krossdebug( QString( "ActionCollectionModel::dropMimeData: parentindex is Action with name=%1" ).arg( act->name() ) ); 00489 } 00490 } 00491 return false; 00492 //return QAbstractItemModel::dropMimeData(data, action, row, column, parent); 00493 } 00494 00495 Qt::DropActions ActionCollectionModel::supportedDropActions() const 00496 { 00497 return Qt::CopyAction | Qt::MoveAction | Qt::TargetMoveAction; 00498 //return Qt::CopyAction | Qt::MoveAction | Qt::TargetMoveAction | Qt::LinkAction; 00499 } 00500 00501 /****************************************************************************** 00502 * ActionCollectionProxyModel 00503 */ 00504 00505 ActionCollectionProxyModel::ActionCollectionProxyModel(QObject* parent, ActionCollectionModel* model) 00506 : QSortFilterProxyModel(parent) 00507 { 00508 setSourceModel( model ? model : new ActionCollectionModel(this) ); 00509 setFilterCaseSensitivity(Qt::CaseInsensitive); 00510 setDynamicSortFilter(true); 00511 } 00512 00513 ActionCollectionProxyModel::~ActionCollectionProxyModel() 00514 { 00515 } 00516 00517 void ActionCollectionProxyModel::setSourceModel(QAbstractItemModel* sourceModel) 00518 { 00519 Q_ASSERT( dynamic_cast< ActionCollectionModel* >(sourceModel) ); 00520 QSortFilterProxyModel::setSourceModel(sourceModel); 00521 } 00522 00523 bool ActionCollectionProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const 00524 { 00525 //krossdebug( QString( "ActionCollectionProxyModel::filterAcceptsRow: row=%1 parentrow=%2" ).arg( source_row ).arg( source_parent.row() ) ); 00526 QModelIndex index = sourceModel()->index(source_row, 0, source_parent); 00527 if( ! index.isValid() ) 00528 return false; 00529 00530 Action *action = ActionCollectionModel::action( index ); 00531 if ( action ) { 00532 return action->isEnabled() && QSortFilterProxyModel::filterAcceptsRow( source_row, source_parent ); 00533 } 00534 ActionCollection *collection = ActionCollectionModel::collection( index ); 00535 if( collection ) { 00536 return collection->isEnabled(); 00537 } 00538 return true; 00539 } 00540 00541 #include "model.moc"
KDE 4.6 API Reference