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"