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"