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

0001 /*
0002     SPDX-FileCopyrightText: 2003-2005 Christian Kvasny <chris@k3b.org>
0003     SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
0004     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "k3bvcddoc.h"
0010 #include "k3bvcdtrack.h"
0011 #include "k3bvcdjob.h"
0012 #include "k3bglobals.h"
0013 #include "k3bmsf.h"
0014 #include "k3b_i18n.h"
0015 
0016 #include <KConfig>
0017 #include <KIO/Global>
0018 #include <KMessageBox>
0019 #include <KStandardGuiItem>
0020 
0021 #include <QDataStream>
0022 #include <QDebug>
0023 #include <QFile>
0024 #include <QTimer>
0025 #include <QImage>
0026 #include <QApplication>
0027 #include <QDomElement>
0028 
0029 
0030 #if 0
0031 bool desperate_mode = false;
0032 bool preserve_header = false;
0033 bool print_progress = true;
0034 bool aspect_correction = false;
0035 byte forced_sequence_header = 0;
0036 #endif
0037 
0038 K3b::VcdDoc::VcdDoc( QObject* parent )
0039     : K3b::Doc( parent )
0040 {
0041     m_tracks = 0L;
0042     m_vcdOptions = new K3b::VcdOptions();
0043 
0044     m_vcdType = NONE;
0045 
0046     m_urlAddingTimer = new QTimer( this );
0047     connect( m_urlAddingTimer, SIGNAL(timeout()), this, SLOT(slotWorkUrlQueue()) );
0048 
0049     // FIXME: remove the newTracks() signal and replace it with the changed signal
0050     connect( this, SIGNAL(newTracks()), this, SIGNAL(changed()) );
0051     connect( this, SIGNAL(trackRemoved(K3b::VcdTrack*)), this, SIGNAL(changed()) );
0052 }
0053 
0054 K3b::VcdDoc::~VcdDoc()
0055 {
0056     if ( m_tracks ) {
0057         qDeleteAll( *m_tracks );
0058         delete m_tracks;
0059     }
0060 
0061     delete m_vcdOptions;
0062 }
0063 
0064 bool K3b::VcdDoc::newDocument()
0065 {
0066     clear();
0067     if ( !m_tracks )
0068         m_tracks = new QList<K3b::VcdTrack*>;
0069 
0070     return K3b::Doc::newDocument();
0071 }
0072 
0073 
0074 void K3b::VcdDoc::clear()
0075 {
0076     if ( m_tracks )
0077         while ( !m_tracks->isEmpty() )
0078             removeTrack( m_tracks->first() );
0079 }
0080 
0081 
0082 QString K3b::VcdDoc::name() const
0083 {
0084     return m_vcdOptions->volumeId();
0085 }
0086 
0087 
0088 KIO::filesize_t K3b::VcdDoc::calcTotalSize() const
0089 {
0090     unsigned long long sum = 0;
0091     if ( m_tracks ) {
0092         Q_FOREACH( K3b::VcdTrack* track, *m_tracks ) {
0093             sum += track->size();
0094         }
0095     }
0096     return sum;
0097 }
0098 
0099 KIO::filesize_t K3b::VcdDoc::size() const
0100 {
0101     // mode2 -> mode1 int(( n+2047 ) / 2048) * 2352
0102     // mode1 -> mode2 int(( n+2351 ) / 2352) * 2048
0103     long tracksize = long( ( calcTotalSize() + 2351 ) / 2352 ) * 2048;
0104     return tracksize + ISOsize();
0105 }
0106 
0107 KIO::filesize_t K3b::VcdDoc::ISOsize() const
0108 {
0109     // 136000b for vcd iso reserved
0110     long long iso_size = 136000;
0111     if ( vcdOptions() ->CdiSupport() ) {
0112         iso_size += vcdOptions() ->CDIsize();
0113     }
0114 
0115     return iso_size;
0116 }
0117 
0118 K3b::Msf K3b::VcdDoc::length() const
0119 {
0120     return K3b::Msf( size() / 2048 );
0121 }
0122 
0123 
0124 bool K3b::VcdDoc::isImage( const QUrl& url )
0125 {
0126     QImage p;
0127     return p.load( QFile::encodeName( url.toLocalFile() ) );
0128 }
0129 
0130 void K3b::VcdDoc::addUrls( const QList<QUrl>& urls )
0131 {
0132     // make sure we add them at the end even if urls are in the queue
0133     addTracks( urls, 99 );
0134 }
0135 
0136 void K3b::VcdDoc::addTracks( const QList<QUrl>& urls, uint position )
0137 {
0138     QList<QUrl>::ConstIterator end( urls.end() );
0139     for ( QList<QUrl>::ConstIterator it = urls.begin(); it != end; ++it ) {
0140         urlsToAdd.enqueue( new PrivateUrlToAdd( K3b::convertToLocalUrl(*it), position++ ) );
0141     }
0142 
0143     m_urlAddingTimer->start( 0 );
0144 }
0145 
0146 void K3b::VcdDoc::slotWorkUrlQueue()
0147 {
0148     if ( !urlsToAdd.isEmpty() ) {
0149         PrivateUrlToAdd * item = urlsToAdd.dequeue();
0150         lastAddedPosition = item->position;
0151 
0152         // append at the end by default
0153         if ( lastAddedPosition > m_tracks->count() )
0154             lastAddedPosition = m_tracks->count();
0155 
0156         if ( !item->url.isLocalFile() ) {
0157             qDebug() << item->url.toLocalFile() << " no local file";
0158             return ;
0159         }
0160 
0161         if ( !QFile::exists( item->url.toLocalFile() ) ) {
0162             qDebug() << "(K3b::VcdDoc) file not found: " << item->url.toLocalFile();
0163             m_notFoundFiles.append( item->url.toLocalFile() );
0164             return ;
0165         }
0166 
0167         if ( K3b::VcdTrack * newTrack = createTrack( item->url ) )
0168             addTrack( newTrack, lastAddedPosition );
0169 
0170         delete item;
0171 
0172         emit newTracks();
0173     } else {
0174         m_urlAddingTimer->stop();
0175 
0176         emit newTracks();
0177 
0178         // reorder pbc tracks
0179         setPbcTracks();
0180 
0181         informAboutNotFoundFiles();
0182     }
0183 }
0184 
0185 K3b::VcdTrack* K3b::VcdDoc::createTrack( const QUrl& url )
0186 {
0187     char filename[ 255 ];
0188     QString error_string = "";
0189     strcpy( filename, QFile::encodeName( url.toLocalFile() ) );
0190     K3b::MpegInfo* Mpeg = new K3b::MpegInfo( filename );
0191 
0192     if ( Mpeg ) {
0193         int mpegVersion = Mpeg->version();
0194         if ( mpegVersion > 0 ) {
0195 
0196             if ( vcdType() == NONE && mpegVersion < 2 ) {
0197                 m_urlAddingTimer->stop();
0198                 setVcdType( vcdTypes( mpegVersion ) );
0199                 // FIXME: properly convert the mpeg version
0200                 vcdOptions() ->setMpegVersion( ( K3b::VcdOptions::MPEGVersion )mpegVersion );
0201                 KMessageBox::information( qApp->activeWindow(),
0202                                           i18n( "K3b will create a %1 image from the given MPEG "
0203                                                 "files, but these files must already be in %1 "
0204                                                 "format. K3b does not yet resample MPEG files.",
0205                                                  i18n( "VCD" ) ),
0206                                           i18n( "Information" ) );
0207                 m_urlAddingTimer->start( 0 );
0208             } else if ( vcdType() == NONE ) {
0209                 m_urlAddingTimer->stop();
0210                 vcdOptions() ->setMpegVersion( ( K3b::VcdOptions::MPEGVersion )mpegVersion );
0211                 bool force = KMessageBox::questionTwoActions(qApp->activeWindow(),
0212                                                              i18n( "K3b will create a %1 image from the given MPEG "
0213                                                                    "files, but these files must already be in %1 "
0214                                                                    "format. K3b does not yet resample MPEG files.",
0215                                                                    i18n( "SVCD" ) )
0216                                                              + "\n\n"
0217                                                              + i18n( "Note: Forcing MPEG2 as VCD is not supported by "
0218                                                                      "some standalone DVD players." ),
0219                                                              i18n( "Information" ),
0220                                                              KGuiItem( i18n( "Force VCD" ) ),
0221                                                              KGuiItem( i18n( "Do not force VCD" ) ) ) == KMessageBox::PrimaryAction;
0222                 if ( force ) {
0223                     setVcdType( vcdTypes( 1 ) );
0224                     vcdOptions() ->setAutoDetect( false );
0225                 } else
0226                     setVcdType( vcdTypes( mpegVersion ) );
0227 
0228                 m_urlAddingTimer->start( 0 );
0229             }
0230 
0231 
0232             if ( numOfTracks() > 0 && vcdOptions() ->mpegVersion() != mpegVersion ) {
0233                 KMessageBox::error( qApp->activeWindow(), '(' + url.toLocalFile() + ")\n" +
0234                                     i18n( "You cannot mix MPEG1 and MPEG2 video files.\nPlease start a new Project for this filetype.\nResample not implemented in K3b yet." ),
0235                                     i18n( "Wrong File Type for This Project" ) );
0236 
0237                 delete Mpeg;
0238                 return 0;
0239             }
0240 
0241             K3b::VcdTrack* newTrack = new K3b::VcdTrack( m_tracks, url.toLocalFile() );
0242             *( newTrack->mpeg_info ) = *( Mpeg->mpeg_info );
0243 
0244             if ( newTrack->isSegment() && !vcdOptions()->PbcEnabled() ) {
0245                 KMessageBox::information( qApp->activeWindow(),
0246                                           i18n( "PBC (Playback control) enabled.\n"
0247                                                 "Video players cannot reach Segments (MPEG Still Pictures) without Playback control." ) ,
0248                                           i18n( "Information" ) );
0249 
0250                 vcdOptions()->setPbcEnabled( true );
0251             }
0252 
0253             // set defaults;
0254             newTrack->setPlayTime( vcdOptions() ->PbcPlayTime() );
0255             newTrack->setWaitTime( vcdOptions() ->PbcWaitTime() );
0256             newTrack->setPbcNumKeys( vcdOptions() ->PbcNumkeysEnabled() );
0257             delete Mpeg;
0258 
0259             // debugging output
0260             newTrack->PrintInfo();
0261 
0262             return newTrack;
0263         }
0264     } else if ( isImage( url ) ) { // image track
0265         // working on ...
0266         // for future use
0267         // photoalbum starts here
0268         // return here the new photoalbum track
0269     }
0270 
0271     if ( Mpeg ) {
0272         error_string = Mpeg->error_string();
0273         delete Mpeg;
0274     }
0275 
0276     // error (unsupported files)
0277     KMessageBox::error( qApp->activeWindow(), '(' + url.toLocalFile() + ")\n" +
0278                         i18n( "Only MPEG1 and MPEG2 video files are supported.\n" ) + error_string ,
0279                         i18n( "Wrong File Format" ) );
0280 
0281 
0282     return 0;
0283 }
0284 
0285 void K3b::VcdDoc::addTrack( const QUrl& url, uint position )
0286 {
0287     urlsToAdd.enqueue( new PrivateUrlToAdd( url, position ) );
0288 
0289     m_urlAddingTimer->start( 0 );
0290 }
0291 
0292 
0293 void K3b::VcdDoc::addTrack( K3b::VcdTrack* track, uint position )
0294 {
0295     if ( m_tracks->count() >= 98 ) {
0296         qDebug() << "(K3b::VcdDoc) VCD Green Book only allows 98 tracks.";
0297         // TODO: show some messagebox
0298         delete track;
0299         return ;
0300     }
0301 
0302     lastAddedPosition = position;
0303 
0304     emit aboutToAddVCDTracks( position, 1);
0305 
0306     m_tracks->insert( position, track );
0307 
0308     if ( track->isSegment() )
0309         vcdOptions() ->increaseSegments( );
0310     else
0311         vcdOptions() ->increaseSequence( );
0312 
0313     emit addedVCDTracks();
0314 
0315     emit newTracks();
0316 
0317     setModified( true );
0318 }
0319 
0320 
0321 void K3b::VcdDoc::removeTrack( K3b::VcdTrack* track )
0322 {
0323     if ( !track ) {
0324         return ;
0325     }
0326 
0327     // set the current item to track
0328     if ( m_tracks->lastIndexOf( track ) >= 0 ) {
0329         // take the current item
0330         int removedPos = m_tracks->lastIndexOf( track );
0331 
0332         emit aboutToRemoveVCDTracks(removedPos, 1);
0333 
0334         track = m_tracks->takeAt( removedPos );
0335 
0336         emit removedVCDTracks();
0337 
0338         // remove all pbc references to us?
0339         if ( track->hasRevRef() )
0340             track->delRefToUs();
0341 
0342         // remove all pbc references from us?
0343         track->delRefFromUs();
0344 
0345         // emit signal before deleting the track to avoid crashes
0346         // when the view tries to call some of the tracks' methods
0347         emit trackRemoved( track );
0348 
0349         if ( track->isSegment() )
0350             vcdOptions() ->decreaseSegments( );
0351         else
0352             vcdOptions() ->decreaseSequence( );
0353 
0354         delete track;
0355 
0356         if ( numOfTracks() == 0 ) {
0357             setVcdType( NONE );
0358             vcdOptions() ->setAutoDetect( true );
0359         }
0360 
0361         // reorder pbc tracks
0362         setPbcTracks();
0363     }
0364 }
0365 
0366 void K3b::VcdDoc::moveTrack( K3b::VcdTrack* track, K3b::VcdTrack* before )
0367 {
0368     if ( track == before )
0369         return ;
0370 
0371     // take the current item
0372     int removedPos = m_tracks->lastIndexOf( track );
0373 
0374     emit aboutToRemoveVCDTracks(removedPos, 1);
0375 
0376     m_tracks->removeAt(removedPos);
0377 
0378     emit removedVCDTracks();
0379 
0380     if( before != 0 ) {
0381         int pos = m_tracks->lastIndexOf( before );
0382         emit aboutToAddVCDTracks(pos, 1);
0383         m_tracks->insert( pos, track );
0384     }
0385     else {
0386         emit aboutToAddVCDTracks( m_tracks->count(), 1 );
0387         m_tracks->append( track );
0388     }
0389 
0390     emit addedVCDTracks();
0391 
0392     // reorder pbc tracks
0393     setPbcTracks();
0394 
0395     emit changed();
0396 }
0397 
0398 
0399 K3b::BurnJob* K3b::VcdDoc::newBurnJob( K3b::JobHandler* hdl, QObject* parent )
0400 {
0401     return new K3b::VcdJob( this, hdl, parent );
0402 }
0403 
0404 void K3b::VcdDoc::informAboutNotFoundFiles()
0405 {
0406     if ( !m_notFoundFiles.isEmpty() ) {
0407         KMessageBox::informationList( view(), i18n( "Could not find the following files:" ),
0408                                       m_notFoundFiles, i18n( "Not Found" ) );
0409 
0410         m_notFoundFiles.clear();
0411     }
0412 }
0413 
0414 void K3b::VcdDoc::setVcdType( int type )
0415 {
0416     m_vcdType = type;
0417     switch ( type ) {
0418     case 0:
0419         //vcd 1.1
0420         vcdOptions() ->setVcdClass( "vcd" );
0421         vcdOptions() ->setVcdVersion( "1.1" );
0422         break;
0423     case 1:
0424         //vcd 2.0
0425         vcdOptions() ->setVcdClass( "vcd" );
0426         vcdOptions() ->setVcdVersion( "2.0" );
0427         break;
0428     case 2:
0429         //svcd 1.0
0430         vcdOptions() ->setVcdClass( "svcd" );
0431         vcdOptions() ->setVcdVersion( "1.0" );
0432         break;
0433     case 3:
0434         //hqvcd 1.0
0435         vcdOptions() ->setVcdClass( "hqvcd" );
0436         vcdOptions() ->setVcdVersion( "1.0" );
0437         break;
0438 
0439     }
0440 }
0441 
0442 void K3b::VcdDoc::setPbcTracks()
0443 {
0444     // reorder pbc tracks
0445     /*
0446       if ( !vcdOptions()->PbcEnabled() )
0447       return;
0448     */
0449 
0450     if ( m_tracks ) {
0451         int count = m_tracks->count();
0452         qDebug() << QString( "K3b::VcdDoc::setPbcTracks() - we have %1 tracks in list." ).arg( count );
0453 
0454         Q_FOREACH( K3b::VcdTrack* track, *m_tracks ) {
0455             Q_FOREACH( VcdTrack::PbcTracks pbc, VcdTrack::trackPlaybackValues() ) {
0456                 // do not change userdefined tracks
0457                 if ( !track->isPbcUserDefined( pbc ) ) {
0458                     if ( track->getPbcTrack( pbc ) )
0459                         track->getPbcTrack( pbc ) ->delFromRevRefList( track );
0460 
0461                     K3b::VcdTrack* t = 0L;
0462                     int index = track->index();
0463 
0464                     // we are the last track
0465                     if ( index == count - 1 ) {
0466                         switch ( pbc ) {
0467                         case K3b::VcdTrack::PREVIOUS:
0468                             // we are not alone :)
0469                             if ( count > 1 ) {
0470                                 t = m_tracks->at( index - 1 );
0471                                 t->addToRevRefList( track );
0472                                 track->setPbcTrack( pbc, t );
0473                             } else {
0474                                 track->setPbcTrack( pbc );
0475                                 track->setPbcNonTrack( pbc, K3b::VcdTrack::VIDEOEND );
0476                             }
0477                             break;
0478                         case K3b::VcdTrack::AFTERTIMEOUT:
0479                         case K3b::VcdTrack::NEXT:
0480                             track->setPbcTrack( pbc );
0481                             track->setPbcNonTrack( pbc, K3b::VcdTrack::VIDEOEND );
0482                             break;
0483                         case K3b::VcdTrack::RETURN:
0484                             track->setPbcTrack( pbc );
0485                             track->setPbcNonTrack( pbc, K3b::VcdTrack::VIDEOEND );
0486                             break;
0487                         case K3b::VcdTrack::DEFAULT:
0488                             track->setPbcTrack( pbc );
0489                             track->setPbcNonTrack( pbc, K3b::VcdTrack::DISABLED );
0490                             break;
0491                         }
0492                     }
0493                     // we are the first track
0494                     else if ( index == 0 ) {
0495                         switch ( pbc ) {
0496                         case K3b::VcdTrack::PREVIOUS:
0497                             track->setPbcTrack( pbc );
0498                             track->setPbcNonTrack( pbc, K3b::VcdTrack::VIDEOEND );
0499                             break;
0500                         case K3b::VcdTrack::AFTERTIMEOUT:
0501                         case K3b::VcdTrack::NEXT:
0502                             t = m_tracks->at( index + 1 );
0503                             t->addToRevRefList( track );
0504                             track->setPbcTrack( pbc, t );
0505                             break;
0506                         case K3b::VcdTrack::RETURN:
0507                             track->setPbcTrack( pbc );
0508                             track->setPbcNonTrack( pbc, K3b::VcdTrack::VIDEOEND );
0509                             break;
0510                         case K3b::VcdTrack::DEFAULT:
0511                             track->setPbcTrack( pbc );
0512                             track->setPbcNonTrack( pbc, K3b::VcdTrack::DISABLED );
0513                             break;
0514                         }
0515                     }
0516                     // we are one of the other tracks and have PREVIOUS and NEXT Track
0517                     else {
0518                         switch ( pbc ) {
0519                         case K3b::VcdTrack::PREVIOUS:
0520                             t = m_tracks->at( index - 1 );
0521                             t->addToRevRefList( track );
0522                             track->setPbcTrack( pbc, t );
0523                             break;
0524                         case K3b::VcdTrack::AFTERTIMEOUT:
0525                         case K3b::VcdTrack::NEXT:
0526                             t = m_tracks->at( index + 1 );
0527                             t->addToRevRefList( track );
0528                             track->setPbcTrack( pbc, t );
0529                             break;
0530                         case K3b::VcdTrack::RETURN:
0531                             track->setPbcTrack( pbc );
0532                             track->setPbcNonTrack( pbc, K3b::VcdTrack::VIDEOEND );
0533                             break;
0534                         case K3b::VcdTrack::DEFAULT:
0535                             track->setPbcTrack( pbc );
0536                             track->setPbcNonTrack( pbc, K3b::VcdTrack::DISABLED );
0537                             break;
0538                         }
0539                     }
0540                 }
0541             }
0542         }
0543     }
0544 }
0545 
0546 
0547 bool K3b::VcdDoc::loadDocumentData( QDomElement* root )
0548 {
0549     newDocument();
0550 
0551     QDomNodeList nodes = root->childNodes();
0552 
0553     if ( nodes.length() < 3 )
0554         return false;
0555 
0556     if ( nodes.item( 0 ).nodeName() != "general" )
0557         return false;
0558     if ( !readGeneralDocumentData( nodes.item( 0 ).toElement() ) )
0559         return false;
0560 
0561     if ( nodes.item( 1 ).nodeName() != "vcd" )
0562         return false;
0563 
0564     if ( nodes.item( 2 ).nodeName() != "contents" )
0565         return false;
0566 
0567 
0568     // vcd Label
0569     QDomNodeList vcdNodes = nodes.item( 1 ).childNodes();
0570 
0571     for ( int i = 0; i < vcdNodes.count(); i++ ) {
0572         QDomNode item = vcdNodes.item( i );
0573         QString name = item.nodeName();
0574 
0575         qDebug() << QString( "(K3b::VcdDoc::loadDocumentData) nodeName = '%1'" ).arg( name );
0576 
0577         if ( name == "volumeId" )
0578             vcdOptions() ->setVolumeId( item.toElement().text() );
0579         else if ( name == "albumId" )
0580             vcdOptions() ->setAlbumId( item.toElement().text() );
0581         else if ( name == "volumeSetId" )
0582             vcdOptions() ->setVolumeSetId( item.toElement().text() );
0583         else if ( name == "preparer" )
0584             vcdOptions() ->setPreparer( item.toElement().text() );
0585         else if ( name == "publisher" )
0586             vcdOptions() ->setPublisher( item.toElement().text() );
0587         else if ( name == "vcdType" )
0588             setVcdType( vcdTypes( item.toElement().text().toInt() ) );
0589         else if ( name == "mpegVersion" )
0590             vcdOptions() ->setMpegVersion( ( K3b::VcdOptions::MPEGVersion )item.toElement().text().toInt() );
0591         else if ( name == "PreGapLeadout" )
0592             vcdOptions() ->setPreGapLeadout( item.toElement().text().toInt() );
0593         else if ( name == "PreGapTrack" )
0594             vcdOptions() ->setPreGapTrack( item.toElement().text().toInt() );
0595         else if ( name == "FrontMarginTrack" )
0596             vcdOptions() ->setFrontMarginTrack( item.toElement().text().toInt() );
0597         else if ( name == "RearMarginTrack" )
0598             vcdOptions() ->setRearMarginTrack( item.toElement().text().toInt() );
0599         else if ( name == "FrontMarginTrackSVCD" )
0600             vcdOptions() ->setFrontMarginTrackSVCD( item.toElement().text().toInt() );
0601         else if ( name == "RearMarginTrackSVCD" )
0602             vcdOptions() ->setRearMarginTrackSVCD( item.toElement().text().toInt() );
0603         else if ( name == "volumeCount" )
0604             vcdOptions() ->setVolumeCount( item.toElement().text().toInt() );
0605         else if ( name == "volumeNumber" )
0606             vcdOptions() ->setVolumeNumber( item.toElement().text().toInt() );
0607         else if ( name == "AutoDetect" )
0608             vcdOptions() ->setAutoDetect( item.toElement().text().toInt() );
0609         else if ( name == "CdiSupport" )
0610             vcdOptions() ->setCdiSupport( item.toElement().text().toInt() );
0611         else if ( name == "NonCompliantMode" )
0612             vcdOptions() ->setNonCompliantMode( item.toElement().text().toInt() );
0613         else if ( name == "Sector2336" )
0614             vcdOptions() ->setSector2336( item.toElement().text().toInt() );
0615         else if ( name == "UpdateScanOffsets" )
0616             vcdOptions() ->setUpdateScanOffsets( item.toElement().text().toInt() );
0617         else if ( name == "RelaxedAps" )
0618             vcdOptions() ->setRelaxedAps( item.toElement().text().toInt() );
0619         else if ( name == "UseGaps" )
0620             vcdOptions() ->setUseGaps( item.toElement().text().toInt() );
0621         else if ( name == "PbcEnabled" )
0622             vcdOptions() ->setPbcEnabled( item.toElement().text().toInt() );
0623         else if ( name == "SegmentFolder" )
0624             vcdOptions() ->setSegmentFolder( item.toElement().text().toInt() );
0625         else if ( name == "Restriction" )
0626             vcdOptions() ->setRestriction( item.toElement().text().toInt() );
0627     }
0628 
0629     // vcd Tracks
0630     QDomNodeList trackNodes = nodes.item( 2 ).childNodes();
0631 
0632     for ( int i = 0; i < trackNodes.length(); i++ ) {
0633 
0634         // check if url is available
0635         QDomElement trackElem = trackNodes.item( i ).toElement();
0636         QString url = trackElem.attributeNode( "url" ).value();
0637         if ( !QFile::exists( url ) )
0638             m_notFoundFiles.append( url );
0639         else {
0640             QUrl k;
0641             k.setPath( url );
0642             if ( K3b::VcdTrack * track = createTrack( k ) ) {
0643                 track ->setPlayTime( trackElem.attribute( "playtime", "1" ).toInt() );
0644                 track ->setWaitTime( trackElem.attribute( "waittime", "2" ).toInt() );
0645                 track ->setReactivity( trackElem.attribute( "reactivity", "0" ).toInt() );
0646                 track -> setPbcNumKeys( ( trackElem.attribute( "numkeys", "yes" ).contains( "yes" ) ) ? true : false );
0647                 track -> setPbcNumKeysUserdefined( ( trackElem.attribute( "userdefinednumkeys", "no" ).contains( "yes" ) ) ? true : false );
0648 
0649                 addTrack( track, m_tracks->count() );
0650             }
0651         }
0652     }
0653 
0654     emit newTracks();
0655 
0656     // do not add saved pbcTrack links when one ore more files missing.
0657     // TODO: add info message to informAboutNotFoundFiles();
0658     if ( m_notFoundFiles.isEmpty() ) {
0659         VcdTrack::PbcTracks type;
0660         VcdTrack::PbcTypes val;
0661         bool pbctrack;
0662         for ( int trackId = 0; trackId < trackNodes.length(); trackId++ ) {
0663             QDomElement trackElem = trackNodes.item( trackId ).toElement();
0664             QDomNodeList trackNodes = trackElem.childNodes();
0665             for ( int i = 0; i < trackNodes.length(); i++ ) {
0666                 QDomElement trackElem = trackNodes.item( i ).toElement();
0667                 QString name = trackElem.tagName();
0668                 if ( name.contains( "pbc" ) ) {
0669                     if ( trackElem.hasAttribute ( "type" ) ) {
0670                         type = static_cast<VcdTrack::PbcTracks>( trackElem.attribute ( "type" ).toInt() );
0671                         if ( trackElem.hasAttribute ( "pbctrack" ) ) {
0672                             pbctrack = ( trackElem.attribute ( "pbctrack" ) == "yes" );
0673                             if ( trackElem.hasAttribute ( "val" ) ) {
0674                                 val = static_cast<VcdTrack::PbcTypes>( trackElem.attribute ( "val" ).toInt() );
0675                                 K3b::VcdTrack* track = m_tracks->at( trackId );
0676                                 K3b::VcdTrack* pbcTrack = m_tracks->at( val );
0677                                 if ( pbctrack ) {
0678                                     pbcTrack->addToRevRefList( track );
0679                                     track->setPbcTrack( type, pbcTrack );
0680                                     track->setUserDefined( type, true );
0681                                 } else {
0682                                     track->setPbcTrack( type );
0683                                     track->setPbcNonTrack( type, val );
0684                                     track->setUserDefined( type, true );
0685                                 }
0686                             }
0687                         }
0688                     }
0689                 } else if ( name.contains( "numkeys" ) ) {
0690                     if ( trackElem.hasAttribute ( "key" ) ) {
0691                         int key = trackElem.attribute ( "key" ).toInt();
0692                         if ( trackElem.hasAttribute ( "val" ) ) {
0693                             int val = trackElem.attribute ( "val" ).toInt() - 1;
0694                             K3b::VcdTrack* track = m_tracks->at( trackId );
0695                             if ( val >= 0 ) {
0696                                 K3b::VcdTrack * numkeyTrack = m_tracks->at( val );
0697                                 track->setDefinedNumKey( key, numkeyTrack );
0698                             } else {
0699                                 track->setDefinedNumKey( key, 0L );
0700                             }
0701                         }
0702                     }
0703                 }
0704 
0705             }
0706 
0707         }
0708         setPbcTracks();
0709         setModified( false );
0710     }
0711 
0712     informAboutNotFoundFiles();
0713     return true;
0714 }
0715 
0716 
0717 
0718 bool K3b::VcdDoc::saveDocumentData( QDomElement * docElem )
0719 {
0720     QDomDocument doc = docElem->ownerDocument();
0721     saveGeneralDocumentData( docElem );
0722 
0723     // save Vcd Label
0724     QDomElement vcdMain = doc.createElement( "vcd" );
0725 
0726     QDomElement vcdElem = doc.createElement( "volumeId" );
0727     vcdElem.appendChild( doc.createTextNode( vcdOptions() ->volumeId() ) );
0728     vcdMain.appendChild( vcdElem );
0729 
0730     vcdElem = doc.createElement( "albumId" );
0731     vcdElem.appendChild( doc.createTextNode( vcdOptions() ->albumId() ) );
0732     vcdMain.appendChild( vcdElem );
0733 
0734     vcdElem = doc.createElement( "volumeSetId" );
0735     vcdElem.appendChild( doc.createTextNode( vcdOptions() ->volumeSetId() ) );
0736     vcdMain.appendChild( vcdElem );
0737 
0738     vcdElem = doc.createElement( "preparer" );
0739     vcdElem.appendChild( doc.createTextNode( vcdOptions() ->preparer() ) );
0740     vcdMain.appendChild( vcdElem );
0741 
0742     vcdElem = doc.createElement( "publisher" );
0743     vcdElem.appendChild( doc.createTextNode( vcdOptions() ->publisher() ) );
0744     vcdMain.appendChild( vcdElem );
0745 
0746     // applicationId()
0747     // systemId()
0748 
0749     vcdElem = doc.createElement( "vcdType" );
0750     vcdElem.appendChild( doc.createTextNode( QString::number( vcdType() ) ) );
0751     vcdMain.appendChild( vcdElem );
0752 
0753     vcdElem = doc.createElement( "mpegVersion" );
0754     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->mpegVersion() ) ) );
0755     vcdMain.appendChild( vcdElem );
0756 
0757     vcdElem = doc.createElement( "PreGapLeadout" );
0758     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PreGapLeadout() ) ) );
0759     vcdMain.appendChild( vcdElem );
0760 
0761     vcdElem = doc.createElement( "PreGapTrack" );
0762     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PreGapTrack() ) ) );
0763     vcdMain.appendChild( vcdElem );
0764 
0765     vcdElem = doc.createElement( "FrontMarginTrack" );
0766     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->FrontMarginTrack() ) ) );
0767     vcdMain.appendChild( vcdElem );
0768 
0769     vcdElem = doc.createElement( "RearMarginTrack" );
0770     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RearMarginTrack() ) ) );
0771     vcdMain.appendChild( vcdElem );
0772 
0773     vcdElem = doc.createElement( "FrontMarginTrackSVCD" );
0774     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->FrontMarginTrackSVCD() ) ) );
0775     vcdMain.appendChild( vcdElem );
0776 
0777     vcdElem = doc.createElement( "RearMarginTrackSVCD" );
0778     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RearMarginTrackSVCD() ) ) );
0779     vcdMain.appendChild( vcdElem );
0780 
0781     vcdElem = doc.createElement( "volumeCount" );
0782     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->volumeCount() ) ) );
0783     vcdMain.appendChild( vcdElem );
0784 
0785     vcdElem = doc.createElement( "volumeNumber" );
0786     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->volumeNumber() ) ) );
0787     vcdMain.appendChild( vcdElem );
0788 
0789     vcdElem = doc.createElement( "AutoDetect" );
0790     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->AutoDetect() ) ) );
0791     vcdMain.appendChild( vcdElem );
0792 
0793     vcdElem = doc.createElement( "CdiSupport" );
0794     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->CdiSupport() ) ) );
0795     vcdMain.appendChild( vcdElem );
0796 
0797     vcdElem = doc.createElement( "NonCompliantMode" );
0798     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->NonCompliantMode() ) ) );
0799     vcdMain.appendChild( vcdElem );
0800 
0801     vcdElem = doc.createElement( "Sector2336" );
0802     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->Sector2336() ) ) );
0803     vcdMain.appendChild( vcdElem );
0804 
0805     vcdElem = doc.createElement( "UpdateScanOffsets" );
0806     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->UpdateScanOffsets() ) ) );
0807     vcdMain.appendChild( vcdElem );
0808 
0809     vcdElem = doc.createElement( "RelaxedAps" );
0810     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->RelaxedAps() ) ) );
0811     vcdMain.appendChild( vcdElem );
0812 
0813     vcdElem = doc.createElement( "UseGaps" );
0814     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->UseGaps() ) ) );
0815     vcdMain.appendChild( vcdElem );
0816 
0817     vcdElem = doc.createElement( "PbcEnabled" );
0818     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->PbcEnabled() ) ) );
0819     vcdMain.appendChild( vcdElem );
0820 
0821     vcdElem = doc.createElement( "SegmentFolder" );
0822     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->SegmentFolder() ) ) );
0823     vcdMain.appendChild( vcdElem );
0824 
0825     vcdElem = doc.createElement( "Restriction" );
0826     vcdElem.appendChild( doc.createTextNode( QString::number( vcdOptions() ->Restriction() ) ) );
0827     vcdMain.appendChild( vcdElem );
0828 
0829     docElem->appendChild( vcdMain );
0830 
0831     // save the tracks
0832     // -------------------------------------------------------------
0833     QDomElement contentsElem = doc.createElement( "contents" );
0834 
0835     Q_FOREACH( K3b::VcdTrack* track, *m_tracks ) {
0836         QDomElement trackElem = doc.createElement( "track" );
0837         trackElem.setAttribute( "url", KIO::decodeFileName( track->absolutePath() ) );
0838         trackElem.setAttribute( "playtime", track->getPlayTime() );
0839         trackElem.setAttribute( "waittime", track->getWaitTime() );
0840         trackElem.setAttribute( "reactivity", track->Reactivity() );
0841         trackElem.setAttribute( "numkeys", ( track->PbcNumKeys() ) ? "yes" : "no" );
0842         trackElem.setAttribute( "userdefinednumkeys", ( track->PbcNumKeysUserdefined() ) ? "yes" : "no" );
0843 
0844         Q_FOREACH( VcdTrack::PbcTracks pbc, VcdTrack::trackPlaybackValues() ) {
0845             if ( track->isPbcUserDefined( pbc ) ) {
0846                 // save pbcTracks
0847                 QDomElement pbcElem = doc.createElement( "pbc" );
0848                 pbcElem.setAttribute( "type", pbc );
0849                 if ( track->getPbcTrack( pbc ) ) {
0850                     pbcElem.setAttribute( "pbctrack", "yes" );
0851                     pbcElem.setAttribute( "val", track->getPbcTrack( pbc ) ->index() );
0852                 } else {
0853                     pbcElem.setAttribute( "pbctrack", "no" );
0854                     pbcElem.setAttribute( "val", track->getNonPbcTrack( pbc ) );
0855                 }
0856                 trackElem.appendChild( pbcElem );
0857             }
0858         }
0859         QMap<int, K3b::VcdTrack*> numKeyMap = track->DefinedNumKey();
0860         QMap<int, K3b::VcdTrack*>::const_iterator trackIt;
0861 
0862         for ( trackIt = numKeyMap.constBegin();
0863               trackIt != numKeyMap.constEnd();
0864               ++trackIt ) {
0865             QDomElement numElem = doc.createElement( "numkeys" );
0866             if ( *trackIt ) {
0867                 numElem.setAttribute( "key", trackIt.key() );
0868                 numElem.setAttribute( "val", trackIt.value() ->index() + 1 );
0869             } else {
0870                 numElem.setAttribute( "key", trackIt.key() );
0871                 numElem.setAttribute( "val", 0 );
0872             }
0873             trackElem.appendChild( numElem );
0874         }
0875 
0876         contentsElem.appendChild( trackElem );
0877     }
0878     // -------------------------------------------------------------
0879 
0880     docElem->appendChild( contentsElem );
0881 
0882     return true;
0883 }
0884 
0885 
0886 K3b::Device::MediaTypes K3b::VcdDoc::supportedMediaTypes() const
0887 {
0888     return K3b::Device::MEDIA_WRITABLE_CD;
0889 }
0890 
0891 #include "moc_k3bvcddoc.cpp"