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"