1 /*
2     SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
3     SPDX-FileCopyrightText: 1998-2010 Sebastian Trueg <trueg@k3b.org>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "k3bvideodvdaudiomodel.h"
9 #include "k3bvideodvd.h"
10 #include "k3bvideodvdtitle.h"
11 
12 #include <KLocalizedString>
13 
14 #include <QHash>
15 #include <QLocale>
16 #include <QSize>
17 
18 namespace K3b {
19 
20 class VideoDVDAudioModel::Private
21 {
22 public:
Private(const VideoDVD::VideoDVD & d,const QList<int> & t)23     Private( const VideoDVD::VideoDVD& d, const QList<int>& t )
24         : dvd( d ), titles( t ) {}
25 
26     VideoDVD::VideoDVD dvd;
27     QList<int> titles;
28     QHash< const VideoDVD::AudioStream*, const VideoDVD::Title* > parents;
29     QHash< const VideoDVD::Title*, QSize > videoSizes;
30     QHash< const VideoDVD::Title*, KIO::filesize_t > fileSizes;
31     QHash< const VideoDVD::Title*, QString > fileNames;
32     QHash< const VideoDVD::Title*, int > chosenAudio;
33 };
34 
35 
VideoDVDAudioModel(const VideoDVD::VideoDVD & dvd,const QList<int> & titles,QObject * parent)36 VideoDVDAudioModel::VideoDVDAudioModel( const VideoDVD::VideoDVD& dvd, const QList<int>& titles, QObject* parent )
37     : QAbstractItemModel( parent ),
38       d( new Private( dvd, titles ) )
39 {
40     Q_FOREACH( int titleNum, titles ) {
41         if( titleNum > 0 && titleNum <= static_cast<int>( d->dvd.numTitles() ) ) {
42             const VideoDVD::Title& title = d->dvd[ titleNum-1 ];
43 
44             d->videoSizes.insert( &title, QSize( title.videoStream().realPictureWidth(),
45                                                  title.videoStream().realPictureHeight() ) );
46             d->fileSizes.insert( &title, 0 );
47             d->fileNames.insert( &title, QString() );
48             d->chosenAudio.insert( &title, 0 );
49 
50             for( int i = 0; i < static_cast<int>( title.numAudioStreams() ); ++i ) {
51                 const VideoDVD::AudioStream& audio = title.audioStream( i );
52                 d->parents.insert( &audio, &title );
53                 if( QLocale( audio.langCode() ).language() == QLocale().language() &&
54                     audio.format() != K3b::VideoDVD::AUDIO_FORMAT_DTS ) {
55                     d->chosenAudio[ &title ] = i;
56                 }
57             }
58         }
59     }
60 }
61 
62 
~VideoDVDAudioModel()63 VideoDVDAudioModel::~VideoDVDAudioModel()
64 {
65     delete d;
66 }
67 
68 
titleForIndex(const QModelIndex & index) const69 const VideoDVD::Title* VideoDVDAudioModel::titleForIndex( const QModelIndex& index ) const
70 {
71     if( index.isValid() && !index.internalPointer() && index.row() >= 0 && index.row() < d->titles.size() )
72     {
73         const int title = d->titles.at( index.row() ) - 1;
74         if( title >= 0 && title < static_cast<int>( d->dvd.numTitles() ) )
75             return &d->dvd[ title ];
76     }
77     return 0;
78 }
79 
80 
indexForTitle(const VideoDVD::Title & title,int column) const81 QModelIndex VideoDVDAudioModel::indexForTitle( const VideoDVD::Title& title, int column ) const
82 {
83     int row = d->titles.indexOf( title.titleNumber() );
84     if( row >= 0 )
85         return createIndex( row, column, nullptr );
86     else
87         return QModelIndex();
88 }
89 
90 
audioForIndex(const QModelIndex & index) const91 const VideoDVD::AudioStream* VideoDVDAudioModel::audioForIndex( const QModelIndex& index ) const
92 {
93     if( index.isValid() && index.internalPointer() )
94         return static_cast<VideoDVD::AudioStream*>( index.internalPointer() );
95     else
96         return 0;
97 }
98 
99 
indexForAudio(const VideoDVD::AudioStream & audio,int column) const100 QModelIndex VideoDVDAudioModel::indexForAudio( const VideoDVD::AudioStream& audio, int column ) const
101 {
102     if( const VideoDVD::Title* title = d->parents[ &audio ] ) {
103         for( int i = 0; i < static_cast<int>( title->numAudioStreams() ); ++i ) {
104             if( &title->audioStream( i ) == &audio ) {
105                 return createIndex( i, column, const_cast<void*>( reinterpret_cast<const void*>( &audio ) ) );
106             }
107         }
108     }
109     return QModelIndex();
110 }
111 
112 
setVideoSize(const VideoDVD::Title & title,const QSize & videoSize)113 void VideoDVDAudioModel::setVideoSize( const VideoDVD::Title& title, const QSize& videoSize )
114 {
115     d->videoSizes[ &title ] = videoSize;
116     QModelIndex index = indexForTitle( title, VideoSizeColumn );
117     Q_EMIT dataChanged( index, index );
118 }
119 
120 
setFileSize(const VideoDVD::Title & title,KIO::filesize_t fileSize)121 void VideoDVDAudioModel::setFileSize( const VideoDVD::Title& title, KIO::filesize_t fileSize )
122 {
123     d->fileSizes[ &title ] = fileSize;
124     QModelIndex index = indexForTitle( title, FileSizeColumn );
125     Q_EMIT dataChanged( index, index );
126 }
127 
128 
setFileName(const VideoDVD::Title & title,const QString & fileName)129 void VideoDVDAudioModel::setFileName( const VideoDVD::Title& title, const QString& fileName )
130 {
131     d->fileNames[ &title ] = fileName;
132     QModelIndex index = indexForTitle( title, FileNameColumn );
133     Q_EMIT dataChanged( index, index );
134 }
135 
136 
chosenAudio(const VideoDVD::Title & title) const137 int VideoDVDAudioModel::chosenAudio( const VideoDVD::Title& title ) const
138 {
139     return d->chosenAudio[ &title ];
140 }
141 
142 
data(const QModelIndex & index,int role) const143 QVariant VideoDVDAudioModel::data( const QModelIndex& index, int role ) const
144 {
145     if( const VideoDVD::Title* title = titleForIndex( index ) ) {
146         if( Qt::DisplayRole == role ) {
147             switch( index.column() ) {
148                 case TitleColumn:
149                     return i18n("Title %1 (%2)",
150                                 title->titleNumber(),
151                                 title->playbackTime().toString() );
152                 case VideoSizeColumn:
153                     return QString("%1x%2")
154                             .arg( d->videoSizes[ title ].width() )
155                             .arg( d->videoSizes[ title ].height() );
156                 case FileSizeColumn:
157                     return KIO::convertSize( d->fileSizes[ title ] );
158                 case FileNameColumn:
159                     return d->fileNames[ title ];
160                 default:
161                     break;
162             }
163         }
164         else if( Qt::ToolTipRole == role && index.column() == FileNameColumn ) {
165             return d->fileNames[ title ];
166         }
167     }
168     else if( const VideoDVD::AudioStream* audio = audioForIndex( index ) ) {
169         if( Qt::DisplayRole == role && index.column() == TitleColumn ) {
170             QString text = i18n("%1 %2Ch (%3%4)",
171                            K3b::VideoDVD::audioFormatString( audio->format() ),
172                            audio->channels(),
173                                 ( audio->langCode().isEmpty()
174                                   ? i18n("unknown language")
175                                   : QLocale( audio->langCode() ).nativeLanguageName() ),
176                                 ( audio->codeExtension() != K3b::VideoDVD::AUDIO_CODE_EXT_UNSPECIFIED
177                                   ? QString(" ") + K3b::VideoDVD::audioCodeExtensionString( audio->codeExtension() )
178                                   : QString() ) );
179 
180             if( audio->format() == K3b::VideoDVD::AUDIO_FORMAT_DTS )
181                 return i18n( "%1 (not supported)", text );
182             else
183                 return text;
184         }
185         else if( Qt::CheckStateRole == role && index.column() == TitleColumn ) {
186             if( d->chosenAudio[ d->parents[ audio ] ] == index.row() )
187                 return Qt::Checked;
188             else
189                 return Qt::Unchecked;
190         }
191     }
192     return QVariant();
193 }
194 
195 
columnCount(const QModelIndex &) const196 int VideoDVDAudioModel::columnCount( const QModelIndex& /*parent*/ ) const
197 {
198     return NumColumns;
199 }
200 
201 
rowCount(const QModelIndex & parent) const202 int VideoDVDAudioModel::rowCount( const QModelIndex& parent ) const
203 {
204     if( !parent.isValid() )
205         return d->titles.count();
206     else if( const VideoDVD::Title* title = titleForIndex( parent ) )
207         return title->numAudioStreams();
208     else
209         return 0;
210 }
211 
212 
parent(const QModelIndex & child) const213 QModelIndex VideoDVDAudioModel::parent( const QModelIndex& child ) const
214 {
215     if( const VideoDVD::AudioStream* audio = audioForIndex( child ) ) {
216         if( const VideoDVD::Title* title = d->parents[ audio ] ) {
217             return indexForTitle( *title );
218         }
219     }
220     return QModelIndex();
221 }
222 
223 
index(int row,int column,const QModelIndex & parent) const224 QModelIndex VideoDVDAudioModel::index( int row, int column, const QModelIndex& parent ) const
225 {
226     if( !hasIndex( row, column, parent ) ) {
227         return QModelIndex();
228     }
229     else if( !parent.isValid() ) {
230         if( row >= 0 && row < d->titles.size() )
231             return createIndex( row, column, nullptr );
232         else
233             return QModelIndex();
234     }
235     else if( const VideoDVD::Title* title = titleForIndex( parent ) ) {
236         if( row >= 0 && row < static_cast<int>( title->numAudioStreams() ) )
237             return createIndex( row, column, const_cast<void*>( reinterpret_cast<const void*>( &title->audioStream( row ) ) ) );
238         else
239             return QModelIndex();
240     }
241     else {
242         return QModelIndex();
243     }
244 }
245 
246 
headerData(int section,Qt::Orientation orientation,int role) const247 QVariant VideoDVDAudioModel::headerData( int section, Qt::Orientation orientation, int role ) const
248 {
249     if( orientation == Qt::Horizontal && Qt::DisplayRole == role ) {
250         switch( section ) {
251             case TitleColumn: return i18n("Title");
252             case VideoSizeColumn: return i18n("Video Size");
253             case FileSizeColumn: return i18n("File Size");
254             case FileNameColumn: return i18n("Filename");
255             default: break;
256         }
257     }
258     return QVariant();
259 }
260 
261 
setData(const QModelIndex & index,const QVariant & value,int role)262 bool VideoDVDAudioModel::setData( const QModelIndex& index, const QVariant& value, int role )
263 {
264     if( role == Qt::CheckStateRole && value.toBool() ) {
265         if( const VideoDVD::AudioStream* audio = audioForIndex( index ) ) {
266             if( const VideoDVD::Title* title = d->parents[ audio ] ) {
267                 d->chosenAudio[ title ] = index.row();
268                 QModelIndex titleIndex = indexForTitle( *title );
269                 Q_EMIT dataChanged( VideoDVDAudioModel::index( 0, TitleColumn, titleIndex ),
270                                     VideoDVDAudioModel::index( rowCount( titleIndex )-1, TitleColumn, titleIndex ) );
271             }
272         }
273     }
274     return false;
275 }
276 
277 
flags(const QModelIndex & index) const278 Qt::ItemFlags VideoDVDAudioModel::flags( const QModelIndex& index ) const
279 {
280     if( audioForIndex( index ) != 0 )
281         return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
282     else if( titleForIndex( index ) != 0 )
283         return Qt::ItemIsEnabled;
284     else
285         return Qt::NoItemFlags;
286 }
287 
288 } // namespace K3b
289 
290 
291 
292