File indexing completed on 2024-05-05 04:51:46
0001 /* 0002 SPDX-FileCopyrightText: 2008 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 2009 Arthur Renato Mello <arthur@mandriva.com> 0004 SPDX-FileCopyrightText: 2009 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net> 0005 SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl> 0006 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "k3bmovixprojectmodel.h" 0012 #include "k3bmovixdoc.h" 0013 #include "k3bmovixfileitem.h" 0014 0015 #include <KUrlMimeData> 0016 #include <KLocalizedString> 0017 0018 #include <QUrl> 0019 #include <QMimeData> 0020 #include <QDataStream> 0021 #include <QIcon> 0022 0023 namespace K3b { 0024 0025 class MovixProjectModel::Private 0026 { 0027 public: 0028 Private( MovixProjectModel* parent, MovixDoc* doc ) 0029 : project( doc ), 0030 q( parent ) { } 0031 0032 MovixDoc* project; 0033 0034 void _k_itemsAboutToBeInserted( int pos, int count ) 0035 { 0036 q->beginInsertRows( QModelIndex(), pos, pos + count - 1 ); 0037 } 0038 0039 void _k_itemsInserted() 0040 { 0041 q->endInsertRows(); 0042 } 0043 0044 void _k_itemsAboutToBeRemoved( int pos, int count ) 0045 { 0046 q->beginRemoveRows( QModelIndex(), pos, pos + count - 1 ); 0047 } 0048 0049 void _k_itemsRemoved() 0050 { 0051 q->endRemoveRows(); 0052 } 0053 0054 void _k_subTitleAboutToBeInserted( K3b::MovixFileItem* item ) 0055 { 0056 q->beginInsertRows( q->indexForItem( item ), 0, 0 ); 0057 } 0058 0059 void _k_subTitleInserted() 0060 { 0061 q->endInsertRows(); 0062 } 0063 0064 void _k_subTitleAboutToBeRemoved( K3b::MovixFileItem* item ) 0065 { 0066 q->beginRemoveRows( q->indexForItem( item ), 0, 0 ); 0067 } 0068 0069 void _k_subTitleRemoved() 0070 { 0071 q->endRemoveRows(); 0072 } 0073 0074 private: 0075 MovixProjectModel* q; 0076 }; 0077 0078 0079 MovixProjectModel::MovixProjectModel( MovixDoc* doc, QObject* parent ) 0080 : 0081 QAbstractItemModel( parent ), 0082 d( new Private( this, doc ) ) 0083 { 0084 // item handling 0085 connect( doc, SIGNAL(itemsAboutToBeInserted(int,int)), 0086 this, SLOT(_k_itemsAboutToBeInserted(int,int)), Qt::DirectConnection ); 0087 connect( doc, SIGNAL(itemsInserted()), 0088 this, SLOT(_k_itemsInserted()), Qt::DirectConnection ); 0089 connect( doc, SIGNAL(itemsAboutToBeRemoved(int,int)), 0090 this, SLOT(_k_itemsAboutToBeRemoved(int,int)), Qt::DirectConnection ); 0091 connect( doc, SIGNAL(itemsRemoved()), 0092 this, SLOT(_k_itemsRemoved()), Qt::DirectConnection ); 0093 0094 // subtitle handling 0095 connect( doc, SIGNAL(subTitleAboutToBeInserted(K3b::MovixFileItem*)), 0096 this, SLOT(_k_subTitleAboutToBeInserted(K3b::MovixFileItem*)), Qt::DirectConnection ); 0097 connect( doc, SIGNAL(subTitleInserted()), 0098 this, SLOT(_k_subTitleInserted()), Qt::DirectConnection ); 0099 connect( doc, SIGNAL(subTitleAboutToBeRemoved(K3b::MovixFileItem*)), 0100 this, SLOT(_k_subTitleAboutToBeRemoved(K3b::MovixFileItem*)), Qt::DirectConnection ); 0101 connect( doc, SIGNAL(subTitleRemoved()), 0102 this, SLOT(_k_subTitleRemoved()), Qt::DirectConnection ); 0103 } 0104 0105 0106 MovixProjectModel::~MovixProjectModel() 0107 { 0108 delete d; 0109 } 0110 0111 0112 MovixDoc* MovixProjectModel::project() const 0113 { 0114 return d->project; 0115 } 0116 0117 0118 MovixFileItem* MovixProjectModel::itemForIndex( const QModelIndex& index ) const 0119 { 0120 if( index.isValid() && index.internalPointer() != 0 ) { 0121 MovixFileItem* item = static_cast<MovixFileItem*>( index.internalPointer() ); 0122 if( !item->isSubtitle() ) 0123 return item; 0124 } 0125 return 0; 0126 } 0127 0128 0129 QModelIndex MovixProjectModel::indexForItem( MovixFileItem* item ) const 0130 { 0131 if( item && !item->isSubtitle() ) { 0132 int row = d->project->indexOf( item ); 0133 if( row >= 0 && item != 0 ) 0134 return createIndex( row, NoColumn, item ); 0135 } 0136 return QModelIndex(); 0137 } 0138 0139 0140 MovixSubtitleItem* MovixProjectModel::subtitleForIndex( const QModelIndex& index ) const 0141 { 0142 if( index.isValid() && index.internalPointer() != 0 ) { 0143 MovixFileItem* item = static_cast<MovixFileItem*>( index.internalPointer() ); 0144 if( item->isSubtitle() ) { 0145 return dynamic_cast<MovixSubtitleItem*>( item ); 0146 } 0147 } 0148 return 0; 0149 } 0150 0151 0152 QModelIndex MovixProjectModel::indexForSubtitle( MovixSubtitleItem* sub ) const 0153 { 0154 if( sub ) 0155 return createIndex( 0, NoColumn, sub ); 0156 else 0157 return QModelIndex(); 0158 } 0159 0160 0161 QModelIndex MovixProjectModel::index( int row, int column, const QModelIndex& parent ) const 0162 { 0163 if( !hasIndex( row, column, parent ) ) { 0164 return QModelIndex(); 0165 } 0166 else if( !parent.isValid() ) { 0167 // just to make sure it won't crash when the model has no items 0168 if( row >= 0 && row < d->project->movixFileItems().count() ) 0169 return createIndex( row, column, d->project->movixFileItems().at(row) ); 0170 else 0171 return QModelIndex(); 0172 } 0173 else { 0174 // if the parent is valid, we are returning a subtitle item 0175 MovixFileItem* item = itemForIndex( parent ); 0176 if( row == 0 && parent.column() == NoColumn && item != 0 && item->subTitleItem() != 0 ) 0177 return createIndex( row, column, item->subTitleItem() ); 0178 else 0179 return QModelIndex(); 0180 } 0181 } 0182 0183 0184 QModelIndex MovixProjectModel::parent( const QModelIndex& index ) const 0185 { 0186 if( MovixSubtitleItem* sub = subtitleForIndex( index ) ) { 0187 // if it really is a subtitle, the parent is the movix item 0188 MovixFileItem* item = sub->parent(); 0189 const int row = d->project->indexOf( item ); 0190 if( item != 0 && row >= 0 ) 0191 return createIndex( row, NoColumn, item ); 0192 } 0193 return QModelIndex(); 0194 } 0195 0196 0197 int MovixProjectModel::rowCount( const QModelIndex& parent ) const 0198 { 0199 if( parent.isValid() ) { 0200 MovixFileItem* item = itemForIndex(parent); 0201 if( item && item->subTitleItem() != 0 && parent.column() == NoColumn ) 0202 return 1; 0203 else 0204 return 0; 0205 } 0206 else 0207 return d->project->movixFileItems().count(); 0208 } 0209 0210 0211 int MovixProjectModel::columnCount( const QModelIndex& /*parent*/ ) const 0212 { 0213 return NumColumns; 0214 } 0215 0216 0217 bool MovixProjectModel::setData( const QModelIndex& index, const QVariant& value, int role ) 0218 { 0219 if( MovixFileItem* item = itemForIndex( index ) ) { 0220 if( role == Qt::EditRole && index.column() == TitleColumn ) { 0221 if( item->k3bName() != value.toString() ) { 0222 item->setK3bName( value.toString() ); 0223 Q_EMIT dataChanged( index, index ); 0224 return true; 0225 } 0226 } 0227 } 0228 0229 return false; 0230 } 0231 0232 0233 QVariant MovixProjectModel::data( const QModelIndex& index, int role ) const 0234 { 0235 if ( index.isValid() ) { 0236 FileItem* item = static_cast<FileItem*>(index.internalPointer()); 0237 0238 switch( index.column() ) { 0239 case NoColumn: 0240 if( role == Qt::DisplayRole || 0241 role == Qt::EditRole ) 0242 { 0243 if( MovixFileItem* movixItem = itemForIndex(index) ) 0244 return d->project->indexOf( movixItem ) + 1; 0245 else 0246 return QVariant(); 0247 } 0248 break; 0249 case TitleColumn: 0250 if( role == Qt::DisplayRole || 0251 role == Qt::EditRole ) 0252 { 0253 return item->k3bName(); 0254 } 0255 else if ( role == Qt::DecorationRole ) 0256 { 0257 return QIcon::fromTheme( item->mimeType().iconName() ); 0258 } 0259 break; 0260 case TypeColumn: 0261 if( role == Qt::DisplayRole || 0262 role == Qt::EditRole ) 0263 { 0264 if( item->isSymLink() ) 0265 return i18n("Link to %1", item->mimeType().comment()); 0266 else 0267 return item->mimeType().comment(); 0268 } 0269 break; 0270 case SizeColumn: 0271 if( role == Qt::DisplayRole || 0272 role == Qt::EditRole ) 0273 { 0274 return KIO::convertSize( item->size() ); 0275 } 0276 break; 0277 case LocalPathColumn: 0278 if( role == Qt::DisplayRole || 0279 role == Qt::EditRole ) 0280 { 0281 return item->localPath(); 0282 } 0283 break; 0284 case LinkColumn: 0285 if( role == Qt::DisplayRole || 0286 role == Qt::EditRole ) 0287 { 0288 if(item->isValid()) 0289 return item->linkDest(); 0290 else 0291 return i18n( "%1 (broken)", item->linkDest() ); 0292 } 0293 break; 0294 } 0295 } 0296 0297 return QVariant(); 0298 } 0299 0300 0301 QVariant MovixProjectModel::headerData( int section, Qt::Orientation orientation, int role ) const 0302 { 0303 Q_UNUSED( orientation ); 0304 0305 if ( role == Qt::DisplayRole ) { 0306 switch( section ) { 0307 case NoColumn: 0308 return i18nc( "Movix File Position", "No." ); 0309 case TitleColumn: 0310 return i18nc( "Movix File Title", "Title" ); 0311 case TypeColumn: 0312 return i18nc( "Movix File Type(ie. MPEG)", "Type" ); 0313 case SizeColumn: 0314 return i18nc( "Movix File Size", "Size" ); 0315 case LocalPathColumn: 0316 return i18nc( "Movix File Path", "Local Path" ); 0317 case LinkColumn: 0318 return i18nc( "Movix File Link", "Link" ); 0319 } 0320 } 0321 0322 return QVariant(); 0323 } 0324 0325 0326 Qt::ItemFlags MovixProjectModel::flags( const QModelIndex& index ) const 0327 { 0328 if ( index.isValid() ) 0329 { 0330 Qt::ItemFlags f = Qt::ItemIsSelectable | 0331 Qt::ItemIsEnabled | 0332 Qt::ItemIsDropEnabled; 0333 0334 MovixFileItem* item = itemForIndex( index ); 0335 0336 if ( item ) { 0337 f |= Qt::ItemIsDragEnabled; 0338 0339 if ( index.column() == TitleColumn ) { 0340 f |= Qt::ItemIsEditable; 0341 } 0342 } 0343 0344 return f; 0345 } 0346 else { 0347 return QAbstractItemModel::flags( index )|Qt::ItemIsDropEnabled; 0348 } 0349 } 0350 0351 0352 Qt::DropActions MovixProjectModel::supportedDropActions() const 0353 { 0354 return Qt::CopyAction; 0355 } 0356 0357 0358 QMimeData* MovixProjectModel::mimeData( const QModelIndexList& indexes ) const 0359 { 0360 QMimeData* mime = new QMimeData(); 0361 0362 QList<MovixFileItem*> items; 0363 QList<QUrl> urls; 0364 0365 Q_FOREACH( const QModelIndex& index, indexes ) { 0366 MovixFileItem* item = itemForIndex( index ); 0367 if (item) { 0368 items << item; 0369 0370 if( !urls.contains( QUrl::fromLocalFile( item->localPath() ) ) ) { 0371 urls << QUrl::fromLocalFile( item->localPath() ); 0372 } 0373 } 0374 } 0375 mime->setUrls(urls); 0376 0377 // the easy road: encode the pointers 0378 QByteArray trackData; 0379 QDataStream trackDataStream( &trackData, QIODevice::WriteOnly ); 0380 0381 Q_FOREACH( MovixFileItem* item, items ) { 0382 trackDataStream << ( qint64 )item; 0383 } 0384 0385 mime->setData( "application/x-k3bmovixfileitem", trackData ); 0386 0387 return mime; 0388 } 0389 0390 QStringList MovixProjectModel::mimeTypes() const 0391 { 0392 QStringList s = KUrlMimeData::mimeDataTypes(); 0393 s += QString::fromLatin1( "application/x-k3bmovixfileitem" ); 0394 0395 return s; 0396 } 0397 0398 0399 bool MovixProjectModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent ) 0400 { 0401 Q_UNUSED( column ); 0402 0403 if (action == Qt::IgnoreAction) 0404 return true; 0405 0406 QList<MovixFileItem*> items; 0407 if ( data->hasFormat( "application/x-k3bmovixfileitem" ) ) 0408 { 0409 QByteArray itemData = data->data( "application/x-k3bmovixfileitem" ); 0410 QDataStream itemDataStream( itemData ); 0411 while ( !itemDataStream.atEnd() ) 0412 { 0413 qint64 p; 0414 itemDataStream >> p; 0415 items << ( MovixFileItem* )p; 0416 } 0417 0418 MovixFileItem *prev; 0419 if(parent.isValid()) 0420 { 0421 MovixFileItem *item = itemForIndex(parent); 0422 0423 // TODO: handle drop in subtitles 0424 if (!item) 0425 return false; 0426 0427 int index = d->project->indexOf(itemForIndex(parent)); 0428 if(index == 0) 0429 prev = 0; 0430 else 0431 prev = d->project->movixFileItems().at(index - 1); 0432 } 0433 else if(row >= 0) 0434 prev = d->project->movixFileItems().at(row - 1); 0435 else 0436 prev = d->project->movixFileItems().last(); 0437 0438 Q_FOREACH( MovixFileItem* item, items ) 0439 { 0440 d->project->moveMovixItem(item, prev); 0441 prev = item; 0442 } 0443 0444 return true; 0445 } 0446 0447 if ( data->hasUrls() ) 0448 { 0449 int pos; 0450 if(parent.isValid()) 0451 pos = d->project->indexOf(itemForIndex(parent)); 0452 else if(row >= 0) 0453 pos = row; 0454 else 0455 pos = d->project->movixFileItems().size(); 0456 0457 QList<QUrl> urls = KUrlMimeData::urlsFromMimeData( data ); 0458 0459 QMetaObject::invokeMethod( d->project, "addUrlsAt", Qt::QueuedConnection, Q_ARG( QList<QUrl>, urls ), Q_ARG( int, pos ) ); 0460 0461 return true; 0462 } 0463 0464 return false; 0465 } 0466 0467 0468 bool MovixProjectModel::removeRows( int row, int count, const QModelIndex& parent ) 0469 { 0470 // if the parent item is valid, we are removing a subtitle 0471 if (parent.isValid()) { 0472 MovixFileItem *item = itemForIndex(parent); 0473 d->project->removeSubTitleItem( item ); 0474 return true; 0475 } 0476 0477 // remove the indexes from the project 0478 while (count > 0) 0479 { 0480 QModelIndex i = index( row, 0, parent ); 0481 d->project->removeMovixItem( itemForIndex(i) ); 0482 0483 row++; 0484 count--; 0485 } 0486 0487 return true; 0488 } 0489 0490 } // namespace K3b 0491 0492 #include "moc_k3bmovixprojectmodel.cpp"