File indexing completed on 2024-04-28 04:50:23

0001 /*
0002     SPDX-FileCopyrightText: 2003 Christian Kvasny <chris@k3b.org>
0003     SPDX-FileCopyrightText: 2010-2011 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 "k3bvideocdview.h"
0010 #include "k3bvideocdrippingdialog.h"
0011 #include "k3bvideocdinfo.h"
0012 #include "k3bappdevicemanager.h"
0013 #include "k3bapplication.h"
0014 #include "k3bdevice.h"
0015 #include "k3bmsf.h"
0016 #include "k3btoc.h"
0017 #include "k3bcore.h"
0018 #include "k3bmedium.h"
0019 #include "k3bstdguiitems.h"
0020 
0021 #include <KStandardAction>
0022 #include <KLocalizedString>
0023 #include <KActionMenu>
0024 #include <KMessageBox>
0025 #include <KToolBarSpacerAction>
0026 #include <KToolBar>
0027 #include <KActionCollection>
0028 
0029 #include <QDebug>
0030 #include <QList>
0031 #include <QCursor>
0032 #include <QFont>
0033 #include <QApplication>
0034 #include <QAction>
0035 #include <QHeaderView>
0036 #include <QMenu>
0037 #include <QLabel>
0038 #include <QStyle>
0039 #include <QTreeWidget>
0040 #include <QTreeWidgetItem>
0041 #include <QVBoxLayout>
0042 #include <QDomElement>
0043 
0044 namespace {
0045 
0046     class VideoTrackViewItem : public QTreeWidgetItem
0047     {
0048     public:
0049         VideoTrackViewItem( QTreeWidgetItem* parent, QTreeWidgetItem* preceding )
0050             : QTreeWidgetItem( parent, preceding )
0051         {
0052             setFlags( flags() & ~Qt::ItemIsUserCheckable );
0053         }
0054 
0055         VideoTrackViewItem( QTreeWidget* parent, QTreeWidgetItem* preceding )
0056             : QTreeWidgetItem( parent, preceding )
0057         {
0058             setFlags( flags() & ~Qt::ItemIsUserCheckable );
0059         }
0060 
0061         VideoTrackViewItem( QTreeWidgetItem* parent,
0062                             const QString& name,
0063                             const QString& id,
0064                             int _trackNumber,
0065                             const K3b::Msf& length )
0066             : QTreeWidgetItem( parent )
0067         {
0068             setFlags( flags() & ~Qt::ItemIsUserCheckable );
0069 
0070             setText( 0, QString( "%1. %2" ).arg( _trackNumber ).arg( id ) );
0071             setText( 1, name );
0072             if ( length > 0 ) {
0073                 setText( 2, length.toString() );
0074                 setText( 3, KIO::convertSize( length.mode2Form2Bytes() ) );
0075             }
0076 
0077             trackNumber = _trackNumber;
0078         }
0079 
0080         int trackNumber;
0081 
0082         void updateData( const K3b::VideoCdInfoResultEntry& resultEntry )
0083         {
0084             setText( 0, QString( "%1. %2" ).arg( trackNumber ).arg( resultEntry.id ) );
0085             setText( 1, resultEntry.name );
0086         }
0087 
0088     };
0089 
0090     class VideoTrackViewCheckItem : public QTreeWidgetItem
0091     {
0092     public:
0093         VideoTrackViewCheckItem( QTreeWidgetItem* parent,
0094                                 const QString& desc )
0095             : QTreeWidgetItem( parent )
0096         {
0097             setText( 0, desc );
0098             setFlags( flags() | Qt::ItemIsUserCheckable );
0099             setCheckState( 0, Qt::Checked );
0100         }
0101 
0102         VideoTrackViewCheckItem( QTreeWidget* parent,
0103                                   const QString& desc )
0104             : QTreeWidgetItem( parent )
0105         {
0106             setText( 0, desc );
0107             setFlags( flags() | Qt::ItemIsUserCheckable );
0108             setCheckState( 0, Qt::Checked );
0109         }
0110 
0111         VideoTrackViewCheckItem( VideoTrackViewCheckItem* parent,
0112                                 const QString& desc )
0113             : QTreeWidgetItem( parent )
0114         {
0115             setText( 0, desc );
0116             setFlags( flags() | Qt::ItemIsUserCheckable );
0117             setCheckState( 0, Qt::Checked );
0118         }
0119 
0120         void updateData( const K3b::Msf& length, bool form2 = false )
0121         {
0122             setText( 2, length.toString() );
0123             if ( form2 )
0124                 setText( 3, KIO::convertSize( length.mode2Form2Bytes() ) );
0125             else
0126                 setText( 3, KIO::convertSize( length.mode2Form1Bytes() ) );
0127         }
0128 
0129     };
0130 
0131     void setCheckState( QTreeWidgetItem* item, Qt::CheckState checkState )
0132     {
0133         if( item->flags() & Qt::ItemIsUserCheckable ) {
0134             item->setCheckState( 0, checkState );
0135         }
0136 
0137         for( int i = 0; i < item->childCount(); ++i ) {
0138             setCheckState( item->child( i ), checkState );
0139         }
0140     }
0141 
0142 } // namespace
0143 
0144 class K3b::VideoCdView::Private
0145 {
0146 public:
0147     Device::Toc toc;
0148 
0149     KActionCollection* actionCollection;
0150     KActionMenu* popupMenu;
0151 
0152     VideoCdInfoResult videocdinfoResult;
0153     VideoCdInfo* videocdinfo;
0154     VideoCdRippingOptions* videooptions;
0155 
0156     QTreeWidget* trackView;
0157     KToolBar* toolBox;
0158     QLabel* labelLength;
0159 
0160     QDomDocument domTree;
0161 
0162     QList<VideoTrackViewCheckItem *> contentList;
0163 
0164     unsigned long videocddatasize;
0165     unsigned long videocdmpegsize;
0166 };
0167 
0168 
0169 K3b::VideoCdView::VideoCdView( QWidget* parent )
0170     : K3b::MediaContentsView( true,
0171                             K3b::Medium::ContentVideoCD,
0172                             K3b::Device::MEDIA_CD_ALL,
0173                             K3b::Device::STATE_INCOMPLETE|K3b::Device::STATE_COMPLETE,
0174                             parent ),
0175       d( new Private )
0176 {
0177     // toolbox
0178     // ----------------------------------------------------------------------------------
0179     d->toolBox = new KToolBar( mainWidget() );
0180     d->labelLength = new QLabel( mainWidget() );
0181     d->labelLength->setAlignment( Qt::AlignVCenter | Qt::AlignRight );
0182     d->labelLength->setContentsMargins( 0, 0, style()->pixelMetric( QStyle::PM_LayoutRightMargin ), 0 );
0183 
0184     // the track view
0185     // ----------------------------------------------------------------------------------
0186     d->trackView = new QTreeWidget( mainWidget() );
0187     d->trackView->setAllColumnsShowFocus( true );
0188     d->trackView->setContextMenuPolicy( Qt::CustomContextMenu );
0189     d->trackView->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
0190 
0191     QTreeWidgetItem* header = d->trackView->headerItem();
0192     header->setText( 0, i18n( "Item Name" ) );
0193     header->setText( 1, i18n( "Extracted Name" ) );
0194     header->setText( 2, i18n( "Length" ) );
0195     header->setText( 3, i18n( "Size" ) );
0196 
0197     connect( d->trackView, SIGNAL(customContextMenuRequested(QPoint)),
0198              this, SLOT(slotContextMenu(QPoint)) );
0199     connect( d->trackView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
0200              this, SLOT(slotTrackSelectionChanged(QTreeWidgetItem*,QTreeWidgetItem*)) );
0201     connect( d->trackView, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
0202              this, SLOT(slotStateChanged(QTreeWidgetItem*,int)) );
0203 
0204     QVBoxLayout * mainGrid = new QVBoxLayout( mainWidget() );
0205     mainGrid->addWidget( d->toolBox );
0206     mainGrid->addWidget( d->trackView );
0207     mainGrid->setSpacing( 0 );
0208     mainGrid->setContentsMargins( 0, 0, 0, 0 );
0209 
0210     initActions();
0211 
0212     // setup the toolbox
0213     d->toolBox->addAction( d->actionCollection->action( "start_rip" ) );
0214     d->toolBox->addSeparator();
0215     d->toolBox->addAction( d->actionCollection->action( "view_files" ) );
0216     d->toolBox->addAction( new KToolBarSpacerAction( d->toolBox ) );
0217     d->toolBox->addWidget( d->labelLength );
0218 
0219     slotTrackSelectionChanged( 0, 0 );
0220 
0221     d->videocdinfo = 0L;
0222     d->videooptions = new K3b::VideoCdRippingOptions();
0223 
0224     d->contentList.clear();
0225 }
0226 
0227 
0228 K3b::VideoCdView::~VideoCdView()
0229 {
0230     delete d->videocdinfo;
0231     delete d->videooptions;
0232     delete d;
0233 }
0234 
0235 
0236 KActionCollection* K3b::VideoCdView::actionCollection() const
0237 {
0238     return d->actionCollection;
0239 }
0240 
0241 
0242 void K3b::VideoCdView::reloadMedium()
0243 {
0244     d->toc = medium().toc();
0245 
0246     d->trackView->clear();
0247 
0248     d->trackView->setEnabled( false );
0249     d->toolBox->setEnabled( false );
0250     QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
0251 
0252     d->contentList.clear();
0253     d->contentList.append( new VideoTrackViewCheckItem( d->trackView, i18n("Video CD MPEG tracks") ) );
0254     d->contentList.append( new VideoTrackViewCheckItem( d->trackView, i18n("Video CD DATA track" ) ) );
0255 
0256     // create a listviewItem for every video track
0257     int index = 0;
0258     d->videocddatasize = 0;
0259     d->videocdmpegsize = 0;
0260 
0261     K3b::Msf sequenceSize;
0262 
0263     for ( K3b::Device::Toc::const_iterator it = d->toc.constBegin();
0264           it != d->toc.constEnd(); ++it ) {
0265 
0266         if ( index > 0 ) {
0267             K3b::Msf length( ( *it ).length() );
0268             sequenceSize += length;
0269             d->videocdmpegsize += length.mode2Form2Bytes();
0270             ( void ) new VideoTrackViewItem( d->contentList[ 0 ], i18n( "Sequence-%1" , index ), "", index, length );
0271         } else {
0272             K3b::Msf length( ( *it ).length() );
0273             d->videocddatasize += length.mode2Form1Bytes();
0274             ( ( VideoTrackViewCheckItem* ) d->contentList[ 1 ] ) ->updateData( length );
0275             ( void ) new VideoTrackViewCheckItem( d->contentList[ 1 ], i18n( "Files" ) );
0276             ( void ) new VideoTrackViewCheckItem( d->contentList[ 1 ], i18n( "Segments" ) );
0277         }
0278 
0279         index++;
0280     }
0281 
0282     ( ( VideoTrackViewCheckItem* ) d->contentList[ 0 ] ) ->updateData( sequenceSize, true );
0283 
0284     d->videooptions ->setVideoCdSource( device()->blockDeviceName() );
0285 
0286     d->videocdinfo = new K3b::VideoCdInfo( this );
0287     d->videocdinfo->info( device()->blockDeviceName() );
0288 
0289     connect( d->videocdinfo, SIGNAL(infoFinished(bool)),
0290              this, SLOT(slotVideoCdInfoFinished(bool)) );
0291 }
0292 
0293 void K3b::VideoCdView::slotVideoCdInfoFinished( bool success )
0294 {
0295     if ( success ) {
0296         d->videocdinfoResult = d->videocdinfo->result();
0297         updateDisplay();
0298     }
0299 
0300     d->trackView->expandAll();
0301     d->trackView->setEnabled( true );
0302     d->toolBox->setEnabled( true );
0303     QApplication::restoreOverrideCursor();
0304 
0305 }
0306 
0307 void K3b::VideoCdView::updateDisplay()
0308 {
0309     // update the listview
0310 
0311     for( int i = 0; i < d->contentList[ 0 ]->childCount(); ++i ) {
0312         VideoTrackViewItem* child = dynamic_cast<VideoTrackViewItem*>( d->contentList[ 0 ]->child( i ) );
0313         child->updateData( d->videocdinfoResult.entry( i, K3b::VideoCdInfoResult::SEQUENCE ) );
0314     }
0315 
0316     for( int i = 0; i < d->contentList[ 1 ]->childCount(); ++i ) {
0317         QTreeWidgetItem* child = d->contentList[ 1 ]->child( i );
0318         if ( child->text( 0 ) == i18n( "Files" ) ) {
0319             if ( d->domTree.setContent( d->videocdinfoResult.xmlData ) ) {
0320 
0321                 QDomElement root = d->domTree.documentElement();
0322                 QDomNode node;
0323                 node = root.firstChild();
0324                 while ( !node.isNull() ) {
0325                     if ( node.isElement() && node.nodeName() == "filesystem" ) {
0326                         QDomElement body = node.toElement();
0327                         buildTree( child, body );
0328                         break;
0329                     }
0330                     node = node.nextSibling();
0331                 }
0332             }
0333         } else {
0334             for ( int j = 0; j < d->videocdinfoResult.foundEntries( K3b::VideoCdInfoResult::SEGMENT ); j++ ) {
0335                 ( void ) new VideoTrackViewItem( child,
0336                                                  d->videocdinfoResult.entry( j, K3b::VideoCdInfoResult::SEGMENT ).name,
0337                                                  d->videocdinfoResult.entry( j, K3b::VideoCdInfoResult::SEGMENT ).id , j + 1, 0 );
0338             }
0339         }
0340     }
0341 
0342     if ( !d->videocdinfoResult.volumeId.isEmpty() ) {
0343         QString description = d->videocdinfoResult.volumeId + " (" + d->videocdinfoResult.type + ' ' + d->videocdinfoResult.version + ')' ;
0344         setTitle( description );
0345         d->videooptions ->setVideoCdDescription( description );
0346     }
0347     else
0348         setTitle( i18n( "Video CD" ) );
0349 
0350     d->labelLength->setText( i18np( "1 track (%2)", "%1 tracks (%2)", d->toc.count(), K3b::Msf( d->toc.length() ).toString() ) );
0351 }
0352 
0353 
0354 void K3b::VideoCdView::initActions()
0355 {
0356     d->actionCollection = new KActionCollection( this );
0357 
0358     QAction *actionCheckAll = new QAction(i18n("Check All"), this);
0359     d->actionCollection->addAction("check_all", actionCheckAll);
0360     connect(actionCheckAll, SIGNAL(triggered(bool)), this, SLOT(slotCheckAll()));
0361 
0362     QAction *actionUncheckAll = new QAction(i18n("Uncheck All"), this);
0363     d->actionCollection->addAction("decheck_all", actionUncheckAll);
0364     connect(actionUncheckAll, SIGNAL(triggered(bool)), this, SLOT(slotUncheckAll()));
0365 
0366     QAction *actionCheckTrack = new QAction(i18n("Check Track"), this);
0367     d->actionCollection->addAction("check_track", actionCheckTrack);
0368     connect(actionCheckTrack, SIGNAL(triggered(bool)), this, SLOT(slotCheck()));
0369 
0370     QAction *actionUncheckTrack = new QAction(i18n("Uncheck Track"), this);
0371     d->actionCollection->addAction("decheck_track", actionUncheckTrack);
0372     connect(actionUncheckTrack, SIGNAL(triggered(bool)), this, SLOT(slotUncheck()));
0373 
0374     QAction *actionStartRipping = new QAction(QIcon::fromTheme("tools-rip-video-cd"), i18n("Start Ripping"), this);
0375     d->actionCollection->addAction("start_rip", actionStartRipping);
0376     connect(actionStartRipping, SIGNAL(triggered(bool)), this, SLOT(startRip()));
0377 
0378     QAction* actionShowDataPart = new QAction(QIcon::fromTheme("media-optical-data"), i18n("View Files"), this);
0379     actionShowDataPart->setToolTip(i18n("View plain data files"));
0380     actionShowDataPart->setStatusTip(actionShowDataPart->toolTip());
0381     d->actionCollection->addAction("view_files", actionShowDataPart);
0382     connect(actionShowDataPart, SIGNAL(triggered(bool)), this, SLOT(slotViewFiles()));
0383 
0384     // TODO: set the actions tooltips and whatsthis infos
0385 
0386     // setup the popup menu
0387     d->popupMenu = new KActionMenu( actionCollection() );
0388     d->popupMenu->addAction( actionCheckTrack );
0389     d->popupMenu->addAction( actionUncheckTrack );
0390     d->popupMenu->addAction( actionCheckAll );
0391     d->popupMenu->addAction( actionUncheckTrack );
0392     d->popupMenu->addSeparator();
0393     d->popupMenu->addAction( actionStartRipping );
0394 }
0395 
0396 
0397 void K3b::VideoCdView::slotContextMenu( const QPoint& pos )
0398 {
0399     d->popupMenu->menu()->popup( d->trackView->viewport()->mapToGlobal( pos ) );
0400 }
0401 
0402 
0403 void K3b::VideoCdView::slotTrackSelectionChanged( QTreeWidgetItem* current, QTreeWidgetItem* /*previous*/ )
0404 {
0405     actionCollection() ->action( "check_track" ) ->setEnabled( current != 0 );
0406     actionCollection() ->action( "decheck_track" ) ->setEnabled( current != 0 );
0407 }
0408 
0409 
0410 void K3b::VideoCdView::slotStateChanged( QTreeWidgetItem* item, int column )
0411 {
0412     if( item && column == 0 ) {
0413         for( int i = 0; i < item->childCount(); ++i )
0414             setCheckState( item->child( i ), item->checkState( 0 ) );
0415     }
0416 }
0417 
0418 
0419 void K3b::VideoCdView::startRip()
0420 {
0421     int selectedItems  = 0;
0422     QList<QTreeWidgetItem*> children;
0423 
0424     children = d->trackView->findItems( i18n("Video CD MPEG tracks" ), Qt::MatchExactly, 0 );
0425     if( !children.isEmpty() && children.first()->checkState( 0 ) == Qt::Checked ) {
0426         d->videooptions ->setVideoCdRipSequences( true );
0427         ++selectedItems;
0428     }
0429 
0430     children = d->trackView->findItems( i18n("Files" ), Qt::MatchExactly, 0 );
0431     if( !children.isEmpty() && children.first()->checkState( 0 ) == Qt::Checked ) {
0432         d->videooptions ->setVideoCdRipFiles( true );
0433         ++selectedItems;
0434     }
0435 
0436     children = d->trackView->findItems( i18n("Segments" ), Qt::MatchExactly, 0 );
0437     if( !children.isEmpty() && children.first()->checkState( 0 ) == Qt::Checked ) {
0438         d->videooptions ->setVideoCdRipSegments( true );
0439         ++selectedItems;
0440     }
0441 
0442     if( selectedItems == 0 ) {
0443         KMessageBox::error( this, i18n("Please select the tracks to rip."), i18n("No Tracks Selected") );
0444     }
0445     else {
0446         unsigned long videocdsize = 0;
0447         // TODO: split SegmentSize and FileSize. Have no infos now
0448         if ( d->videooptions ->getVideoCdRipSegments() || d->videooptions ->getVideoCdRipFiles())
0449             videocdsize += d->videocddatasize;
0450         if ( d->videooptions ->getVideoCdRipSequences() )
0451             videocdsize += d->videocdmpegsize;
0452 
0453         qDebug() << QString("(K3b::VideoCdView::startRip())  d->videooptions ->setVideoCdSize( %1)").arg( videocdsize );
0454         d->videooptions ->setVideoCdSize( videocdsize );
0455         K3b::VideoCdRippingDialog rip( d->videooptions, this );
0456         rip.exec();
0457     }
0458 }
0459 
0460 
0461 void K3b::VideoCdView::slotCheckAll()
0462 {
0463     for( int i = 0; i < d->trackView->topLevelItemCount(); ++i ) {
0464         setCheckState( d->trackView->topLevelItem( i ), Qt::Checked );
0465     }
0466 }
0467 
0468 
0469 void K3b::VideoCdView::slotUncheckAll()
0470 {
0471     for( int i = 0; i < d->trackView->topLevelItemCount(); ++i ) {
0472         setCheckState( d->trackView->topLevelItem( i ), Qt::Unchecked );
0473     }
0474 }
0475 
0476 
0477 void K3b::VideoCdView::slotViewFiles()
0478 {
0479     k3bappcore->appDeviceManager()->mountDisk( device() );
0480 }
0481 
0482 
0483 void K3b::VideoCdView::slotCheck()
0484 {
0485     if( QTreeWidgetItem* current = d->trackView->currentItem() ) {
0486         setCheckState( current, Qt::Checked );
0487     }
0488 }
0489 
0490 
0491 void K3b::VideoCdView::slotUncheck()
0492 {
0493     if( QTreeWidgetItem* current = d->trackView->currentItem() ) {
0494         setCheckState( current, Qt::Unchecked );
0495     }
0496 }
0497 
0498 
0499 void K3b::VideoCdView::enableInteraction( bool b )
0500 {
0501     actionCollection()->action( "start_rip" )->setEnabled( b );
0502 }
0503 
0504 
0505 void K3b::VideoCdView::buildTree( QTreeWidgetItem* parentItem, const QDomElement& parentElement, const QString& pname )
0506 {
0507     VideoTrackViewItem * thisItem = 0;
0508     QDomNode node = parentElement.firstChild();
0509 
0510     while ( !node.isNull() ) {
0511         if ( (node.isElement() && node.nodeName() == "folder") || node.nodeName() == "file" ) {
0512             if ( parentItem == 0 )
0513                 thisItem = new VideoTrackViewItem( d->trackView, thisItem );
0514             else
0515                 thisItem = new VideoTrackViewItem( parentItem, thisItem );
0516 
0517             QString txt = node.firstChild().toElement().text();
0518             thisItem->setText( 0, txt);
0519             if ( node.nodeName() == "folder" ) {
0520                 buildTree( thisItem, node.toElement(), pname + '_' + txt.toLower() );
0521             }
0522             else {
0523                 thisItem->setText( 1, pname + '_' + txt.toLower() );
0524                 buildTree( thisItem, node.toElement(), pname );
0525             }
0526         } else if ( (node.isElement() && node.nodeName() == "segment-item") || node.nodeName() == "sequence-item" ) {
0527             if ( parentItem == 0 )
0528                 thisItem = new VideoTrackViewItem( d->trackView, thisItem );
0529             else
0530                 thisItem = new VideoTrackViewItem( parentItem, thisItem );
0531 
0532             thisItem->setText( 0, node.toElement().attribute( "src" ) );
0533 
0534             buildTree( thisItem, node.toElement() );
0535         }
0536 
0537         node = node.nextSibling();
0538     }
0539 }
0540 
0541 #include "moc_k3bvideocdview.cpp"