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