File indexing completed on 2024-05-12 04:51:53

0001 /*
0002     SPDX-FileCopyrightText: 2009 Michal Malek <michalm@jabster.pl>
0003     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "k3bvideodvdtitlemodel.h"
0009 #include "k3bapplication.h"
0010 #include "k3bmediacache.h"
0011 #include "k3bmedium.h"
0012 #include "k3bvideodvd.h"
0013 #include "k3bvideodvdrippingpreview.h"
0014 #include "k3bvideodvdtitle.h"
0015 
0016 #include <KLocalizedString>
0017 
0018 #include <QHash>
0019 #include <QLocale>
0020 #include <QSet>
0021 #include <QStringList>
0022 #include <QImage>
0023 #include <QPixmap>
0024 
0025 namespace K3b {
0026 
0027 namespace
0028 {
0029 
0030 const unsigned int MAX_LINES = 2;
0031 const unsigned int TOOLTIP_MAX_LINES = 9999;
0032 
0033 
0034 QStringList audioStreamString( const K3b::VideoDVD::Title& title )
0035 {
0036     QStringList list;
0037 
0038     if( title.numAudioStreams() > 0 ) {
0039         for( unsigned int i = 0; i < qMin( title.numAudioStreams(), MAX_LINES ); ++i ) {
0040             list << QString::number(i+1) + ": "
0041                 + i18n("%1 %2Ch (%3)",
0042                         K3b::VideoDVD::audioFormatString( title.audioStream(i).format() ),
0043                         title.audioStream(i).channels(),
0044                         title.audioStream(i).langCode().isEmpty()
0045                             ? i18n("unknown language")
0046                             : QLocale( title.audioStream(i).langCode() ).nativeLanguageName() );
0047         }
0048         if( title.numAudioStreams() > MAX_LINES )
0049             list.last() += "...";
0050     }
0051     else {
0052         list << i18n("No audio streams");
0053     }
0054     return list;
0055 }
0056 
0057 
0058 QString audioStreamStringToolTip( const K3b::VideoDVD::Title& title )
0059 {
0060     QString s = "<p><b>" + i18n("Audio Streams") + "</b><p>";
0061     for( unsigned int i = 0; i < qMin( title.numAudioStreams(), TOOLTIP_MAX_LINES ); ++i ) {
0062         if( i > 0 )
0063             s += "<br>";
0064         s += QString::number(i+1) + ": "
0065              + i18n("%1 %2Ch (%3<em>%4</em>)",
0066                     K3b::VideoDVD::audioFormatString( title.audioStream(i).format() ),
0067                     title.audioStream(i).channels(),
0068                     title.audioStream(i).langCode().isEmpty()
0069                         ? i18n("unknown language")
0070                         : QLocale( title.audioStream(i).langCode() ).nativeLanguageName(),
0071                     title.audioStream(i).codeExtension() != K3b::VideoDVD::AUDIO_CODE_EXT_UNSPECIFIED
0072                         ? QString(" ") + K3b::VideoDVD::audioCodeExtensionString( title.audioStream(i).codeExtension() )
0073                         : QString() );
0074     }
0075     if( title.numAudioStreams() > TOOLTIP_MAX_LINES )
0076         s += "...";
0077 
0078     return s;
0079 }
0080 
0081 
0082 QStringList subpictureStreamString( const K3b::VideoDVD::Title& title )
0083 {
0084     QStringList list;
0085 
0086     if( title.numSubPictureStreams() > 0 ) {
0087         for( unsigned int i = 0; i < qMin( title.numSubPictureStreams(), MAX_LINES ); ++i ) {
0088             list << QString::number(i+1) + ": "
0089                 + QString("%1 (%2)")
0090                 .arg( title.subPictureStream(i).codeMode() == K3b::VideoDVD::SUBPIC_CODE_MODE_RLE
0091                     ? i18n("RLE")
0092                     : i18n("Extended") )
0093                 .arg( title.subPictureStream(i).langCode().isEmpty()
0094                     ? i18n("unknown language")
0095                     : QLocale( title.subPictureStream(i).langCode() ).nativeLanguageName() );
0096         }
0097         if( title.numSubPictureStreams() > MAX_LINES )
0098             list.last() += "...";
0099     }
0100     else {
0101         list << i18n("No Subpicture streams");
0102     }
0103     return list;
0104 }
0105 
0106 
0107 QString subpictureStreamStringToolTip( const K3b::VideoDVD::Title& title )
0108 {
0109     QString s = "<p><b>" + i18n("Subpicture Streams") + "</b><p>";
0110     for( unsigned int i = 0; i < qMin( title.numSubPictureStreams(), TOOLTIP_MAX_LINES ); ++i ) {
0111         if( i > 0 )
0112             s += "<br>";
0113         s += QString::number(i+1) + ": "
0114              + QString("%1 (%2<em>%3</em>)")
0115              .arg( title.subPictureStream(i).codeMode() == K3b::VideoDVD::SUBPIC_CODE_MODE_RLE
0116                    ? i18n("RLE")
0117                    : i18n("Extended") )
0118              .arg( title.subPictureStream(i).langCode().isEmpty()
0119                    ? i18n("unknown language")
0120                    : QLocale( title.subPictureStream(i).langCode() ).nativeLanguageName() )
0121              .arg( title.subPictureStream(i).codeExtension() != K3b::VideoDVD::SUBPIC_CODE_EXT_UNSPECIFIED
0122                    ? QString(" ") + K3b::VideoDVD::subPictureCodeExtensionString( title.subPictureStream(i).codeExtension() )
0123                    : QString() );
0124     }
0125     if( title.numSubPictureStreams() > TOOLTIP_MAX_LINES )
0126         s += "...";
0127 
0128     return s;
0129 }
0130 
0131 } // namespace
0132 
0133 
0134 class VideoDVDTitleModel::Private
0135 {
0136 public:
0137     typedef QSet<int> Titles;
0138     typedef QHash<const VideoDVD::Title*,QPixmap> Previews;
0139 
0140     VideoDVD::VideoDVD dvd;
0141     Titles selectedTitles;
0142     Previews previews;
0143     VideoDVDRippingPreview* previewGen;
0144     unsigned int currentPreviewTitle;
0145     bool previewGenStopped;
0146     Medium medium;
0147 };
0148 
0149 
0150 VideoDVDTitleModel::VideoDVDTitleModel( QObject* parent )
0151 :
0152     QAbstractTableModel( parent ),
0153     d( new Private )
0154 {
0155     d->currentPreviewTitle = 0;
0156     d->previewGen = new K3b::VideoDVDRippingPreview( this );
0157     d->previewGenStopped = true;
0158     connect( d->previewGen, SIGNAL(previewDone(bool)),
0159              this, SLOT(slotPreviewDone(bool)) );
0160 }
0161 
0162 
0163 VideoDVDTitleModel::~VideoDVDTitleModel()
0164 {
0165     delete d;
0166 }
0167 
0168 
0169 void VideoDVDTitleModel::setVideoDVD( const VideoDVD::VideoDVD& dvd )
0170 {
0171     beginResetModel();
0172     d->previewGen->cancel();
0173     d->dvd = dvd;
0174     d->selectedTitles.clear();
0175     d->previews.clear();
0176     d->currentPreviewTitle = 0;
0177     d->medium = k3bappcore->mediaCache()->medium( d->dvd.device() );
0178     d->previewGenStopped = false;
0179     d->previewGen->generatePreview( d->dvd, d->currentPreviewTitle+1 );
0180     endResetModel();
0181     checkAll();
0182 }
0183 
0184 
0185 QList<int> VideoDVDTitleModel::selectedTitles() const
0186 {
0187     return d->selectedTitles.values();
0188 }
0189 
0190 
0191 Qt::ItemFlags VideoDVDTitleModel::flags( const QModelIndex& index ) const
0192 {
0193     if( index.isValid() ) {
0194         if( index.column() == TitleColumn )
0195             return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
0196         else
0197             return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
0198     }
0199     else
0200         return QAbstractTableModel::flags( index );
0201 }
0202 
0203 
0204 QVariant VideoDVDTitleModel::data( const QModelIndex& index, int role ) const
0205 {
0206     if( !index.isValid() || index.row() >= static_cast<int>( d->dvd.numTitles() ) )
0207         return QVariant();
0208 
0209     const VideoDVD::Title& title = d->dvd.title( index.row() );
0210 
0211     if( Qt::DisplayRole == role || Qt::EditRole == role ) {
0212         switch( index.column() ) {
0213             case TitleColumn:
0214                 return i18n( "Title %1 (%2)",
0215                         QString::number( title.titleNumber() ).rightJustified( 2 ),
0216                         title.playbackTime().toString( false ) );
0217 
0218             case VideoColumn:
0219                 return QString("%1 %2x%3")
0220                     .arg( title.videoStream().mpegVersion() == 0 ? i18n("MPEG1") : i18n("MPEG2") )
0221                     .arg( title.videoStream().pictureWidth() )
0222                     .arg( title.videoStream().pictureHeight() );
0223 
0224             case AudioColumn:
0225                 return audioStreamString( title ).join( ", " );
0226 
0227             case SubpictureColumn:
0228                 return subpictureStreamString( title ).join( "," );
0229 
0230             default:
0231                 break;
0232         }
0233 
0234     }
0235     else if( Qt::ToolTipRole == role ) {
0236         if( AudioColumn == index.column() && title.numAudioStreams() > 0 ) {
0237             return audioStreamStringToolTip( title );
0238         }
0239         else if( SubpictureColumn == index.column() && title.numSubPictureStreams() > 0 ) {
0240             return subpictureStreamStringToolTip( title );
0241         }
0242     }
0243     else if( Qt::CheckStateRole == role && index.column() == TitleColumn ) {
0244         if( d->selectedTitles.contains( title.titleNumber() ) )
0245             return Qt::Checked;
0246         else
0247             return Qt::Unchecked;
0248     }
0249     else if( ChaptersRole == role ) {
0250         return i18np("%1 chapter", "%1 chapters", title.numPTTs() );
0251     }
0252     else if( PreviewRole == role ) {
0253         Private::Previews::const_iterator preview = d->previews.constFind( &title );
0254         if( preview != d->previews.constEnd() )
0255             return preview.value();
0256     }
0257     else if( AspectRatioRole == role ) {
0258         QString aspectRatio( title.videoStream().displayAspectRatio() == K3b::VideoDVD::VIDEO_ASPECT_RATIO_4_3 ? "4:3" : "16:9" );
0259         if( title.videoStream().letterboxed() )
0260             return QString::fromLatin1("%1 - %2").arg(aspectRatio).arg(i18n("letterboxed"));
0261         else if( title.videoStream().permittedDf() == K3b::VideoDVD::VIDEO_PERMITTED_DF_LETTERBOXED )
0262             return QString::fromLatin1("%1 - %2").arg(aspectRatio).arg(i18n("anamorph"));
0263         else
0264             return aspectRatio;
0265     }
0266     else if( AudioStreamsRole == role ) {
0267         return audioStreamString( title );
0268     }
0269     else if( SubpictureStreamsRole == role ) {
0270         return subpictureStreamString( title );
0271     }
0272     return QVariant();
0273 }
0274 
0275 
0276 bool VideoDVDTitleModel::setData( const QModelIndex& index, const QVariant& value, int role )
0277 {
0278     if( !index.isValid() || index.row() >= static_cast<int>( d->dvd.numTitles() ) || role != Qt::CheckStateRole )
0279         return false;
0280 
0281     const VideoDVD::Title& title = d->dvd.title( index.row() );
0282 
0283     if( value.toInt() == Qt::Checked )
0284         d->selectedTitles.insert( title.titleNumber() );
0285     else
0286         d->selectedTitles.remove( title.titleNumber() );
0287 
0288     emit dataChanged( index, index );
0289     return true;
0290 }
0291 
0292 
0293 QVariant VideoDVDTitleModel::headerData( int section, Qt::Orientation orientation, int role ) const
0294 {
0295     Q_UNUSED( orientation );
0296 
0297     if( Qt::DisplayRole == role ) {
0298         switch( section ) {
0299             case TitleColumn:
0300                 return i18n("Title");
0301             case PreviewColumn:
0302                 return i18n("Preview");
0303             case VideoColumn:
0304                 return i18n("Video");
0305             case AudioColumn:
0306                 return i18n("Audio");
0307             case SubpictureColumn:
0308                 return i18n("Subpicture");
0309             default:
0310                 break;
0311         }
0312     }
0313     return QVariant();
0314 }
0315 
0316 
0317 int VideoDVDTitleModel::rowCount( const QModelIndex& parent ) const
0318 {
0319     if( d->dvd.valid() && !parent.isValid() )
0320         return d->dvd.numTitles();
0321     else
0322         return 0;
0323 }
0324 
0325 
0326 int VideoDVDTitleModel::columnCount( const QModelIndex& parent ) const
0327 {
0328     Q_UNUSED( parent );
0329     return NumColumns;
0330 }
0331 
0332 
0333 QModelIndex VideoDVDTitleModel::buddy( const QModelIndex& index ) const
0334 {
0335     if( index.isValid() && index.column() != TitleColumn )
0336         return QAbstractTableModel::index( index.row(), TitleColumn );
0337     else
0338         return index;
0339 }
0340 
0341 
0342 void VideoDVDTitleModel::checkAll()
0343 {
0344     if( d->dvd.valid() ) {
0345         for( unsigned int i = 0; i < d->dvd.numTitles(); ++i ) {
0346             d->selectedTitles.insert( d->dvd.title(i).titleNumber() );
0347         }
0348         emit dataChanged( index(0,TitleColumn), index(d->dvd.numTitles()-1,TitleColumn) );
0349     }
0350 }
0351 
0352 
0353 void VideoDVDTitleModel::uncheckAll()
0354 {
0355     if( d->dvd.valid() ) {
0356         d->selectedTitles.clear();
0357         emit dataChanged( index(0,TitleColumn), index(d->dvd.numTitles()-1,TitleColumn) );
0358     }
0359 }
0360 
0361 
0362 void VideoDVDTitleModel::stopPreviewGen()
0363 {
0364     d->previewGenStopped = true;
0365     d->previewGen->cancel();
0366 }
0367 
0368 
0369 void VideoDVDTitleModel::slotPreviewDone( bool success )
0370 {
0371     const VideoDVD::Title& title = d->dvd.title( d->currentPreviewTitle );
0372 
0373     if( success )
0374         d->previews.insert( &title, QPixmap::fromImage( d->previewGen->preview() ) );
0375     else
0376         d->previews.remove( &title );
0377 
0378     emit dataChanged( index(d->currentPreviewTitle,PreviewColumn), index(d->currentPreviewTitle,PreviewColumn) );
0379 
0380     // cancel if we previously stopped preview generation or if the medium changed.
0381     if( !d->previewGenStopped && d->medium == k3bappcore->mediaCache()->medium( d->dvd.device() ) ) {
0382         ++d->currentPreviewTitle;
0383         if( d->currentPreviewTitle < d->dvd.numTitles() )
0384             d->previewGen->generatePreview( d->dvd, d->currentPreviewTitle+1 );
0385     }
0386 }
0387 
0388 } // namespace K3b
0389 
0390 #include "moc_k3bvideodvdtitlemodel.cpp"