File indexing completed on 2024-05-12 04:51:52
0001 /* 0002 SPDX-FileCopyrightText: 2009-2011 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 "k3bvideodvdrippingview.h" 0009 #include "k3bvideodvd.h" 0010 #include "k3bvideodvdrippingdialog.h" 0011 #include "k3bvideodvdtitletranscodingjob.h" 0012 #include "k3bvideodvdtitledelegate.h" 0013 #include "k3bvideodvdtitlemodel.h" 0014 0015 #include "k3bthememanager.h" 0016 #include "k3bglobals.h" 0017 #include "k3blibdvdcss.h" 0018 #include "k3bcore.h" 0019 #include "k3bexternalbinmanager.h" 0020 #include "k3bmediacache.h" 0021 #include "k3bmedium.h" 0022 #include "k3bmodelutils.h" 0023 0024 #include <KConfig> 0025 #include <KLocalizedString> 0026 #include <KMessageBox> 0027 #include <KToolBarSpacerAction> 0028 #include <KUrlLabel> 0029 #include <KActionCollection> 0030 #include <KToolBar> 0031 0032 #include <QCursor> 0033 #include <QGuiApplication> 0034 #include <QDesktopServices> 0035 #include <QKeyEvent> 0036 #include <QAction> 0037 #include <QVBoxLayout> 0038 #include <QHeaderView> 0039 #include <QLabel> 0040 #include <QLayout> 0041 #include <QMenu> 0042 #include <QStyle> 0043 #include <QTreeView> 0044 0045 0046 namespace mu = K3b::ModelUtils; 0047 0048 0049 class K3b::VideoDVDRippingView::Private 0050 { 0051 public: 0052 KActionCollection* actionCollection; 0053 QMenu* popupMenu; 0054 0055 KToolBar* toolBox; 0056 QLabel* labelLength; 0057 VideoDVDTitleDelegate* delegate; 0058 VideoDVDTitleModel* model; 0059 QTreeView* view; 0060 0061 VideoDVD::VideoDVD dvd; 0062 }; 0063 0064 K3b::VideoDVDRippingView::VideoDVDRippingView( QWidget* parent ) 0065 : K3b::MediaContentsView( true, 0066 K3b::Medium::ContentVideoDVD, 0067 K3b::Device::MEDIA_DVD_ALL, 0068 K3b::Device::STATE_INCOMPLETE|K3b::Device::STATE_COMPLETE, 0069 parent ), 0070 d( new Private ) 0071 { 0072 // toolbox 0073 // ---------------------------------------------------------------------------------- 0074 d->toolBox = new KToolBar( mainWidget() ); 0075 0076 KUrlLabel* showFilesLabel = new KUrlLabel( d->toolBox ); 0077 showFilesLabel->setContentsMargins( style()->pixelMetric( QStyle::PM_LayoutLeftMargin ), 0, 0078 style()->pixelMetric( QStyle::PM_LayoutRightMargin ), 0 ); 0079 showFilesLabel->setText( i18n("Show files") ); 0080 showFilesLabel->setWhatsThis( i18n("Shows plain Video DVD vob files from the DVD " 0081 "(including decryption) for further processing with another application") ); 0082 connect( showFilesLabel, SIGNAL(leftClickedUrl()), this, SLOT(slotShowFiles()) ); 0083 0084 d->labelLength = new QLabel( d->toolBox ); 0085 d->labelLength->setAlignment( Qt::AlignVCenter | Qt::AlignRight ); 0086 d->labelLength->setContentsMargins( style()->pixelMetric( QStyle::PM_LayoutLeftMargin ), 0, 0087 style()->pixelMetric( QStyle::PM_LayoutRightMargin ), 0 ); 0088 0089 d->delegate = new VideoDVDTitleDelegate( this ); 0090 d->model = new VideoDVDTitleModel( this ); 0091 0092 // the title view 0093 // ---------------------------------------------------------------------------------- 0094 d->view = new QTreeView( mainWidget() ); 0095 d->view->setItemDelegate( d->delegate ); 0096 d->view->setSelectionMode( QAbstractItemView::ExtendedSelection ); 0097 d->view->setModel( d->model ); 0098 d->view->setRootIsDecorated( false ); 0099 d->view->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); 0100 d->view->setContextMenuPolicy( Qt::CustomContextMenu ); 0101 d->view->installEventFilter( this ); 0102 connect( d->view, SIGNAL(customContextMenuRequested(QPoint)), 0103 this, SLOT(slotContextMenu(QPoint)) ); 0104 0105 // general layout 0106 // ---------------------------------------------------------------------------------- 0107 QVBoxLayout* mainGrid = new QVBoxLayout( mainWidget() ); 0108 mainGrid->addWidget( d->toolBox ); 0109 mainGrid->addWidget( d->view ); 0110 mainGrid->setContentsMargins( 0, 0, 0, 0 ); 0111 mainGrid->setSpacing( 0 ); 0112 0113 setLeftPixmap( K3b::Theme::MEDIA_LEFT ); 0114 setRightPixmap( K3b::Theme::MEDIA_VIDEO ); 0115 0116 initActions(); 0117 0118 d->toolBox->addAction( actionCollection()->action("start_rip") ); 0119 d->toolBox->addSeparator(); 0120 d->toolBox->addWidget( showFilesLabel ); 0121 d->toolBox->addAction( new KToolBarSpacerAction( d->toolBox ) ); 0122 d->toolBox->addWidget( d->labelLength ); 0123 } 0124 0125 0126 K3b::VideoDVDRippingView::~VideoDVDRippingView() 0127 { 0128 delete d; 0129 } 0130 0131 0132 KActionCollection* K3b::VideoDVDRippingView::actionCollection() const 0133 { 0134 return d->actionCollection; 0135 } 0136 0137 0138 bool K3b::VideoDVDRippingView::eventFilter( QObject* obj, QEvent* event ) 0139 { 0140 if( event->type() == QEvent::KeyPress ) { 0141 // Due to limitation of default implementation of QTreeView 0142 // checking items with Space key doesn't work for columns other than first. 0143 // Using below code a user can do that. 0144 QKeyEvent* keyEvent = static_cast<QKeyEvent*>( event ); 0145 if( keyEvent->key() == Qt::Key_Space ) { 0146 if( keyEvent->modifiers().testFlag( Qt::ControlModifier ) ) { 0147 QItemSelectionModel* selectionModel = d->view->selectionModel(); 0148 QModelIndex current = d->view->currentIndex(); 0149 selectionModel->select( current, QItemSelectionModel::Toggle | QItemSelectionModel::Rows ); 0150 } else { 0151 slotToggle(); 0152 } 0153 return true; 0154 } 0155 } 0156 return MediaContentsView::eventFilter( obj, event ); 0157 } 0158 0159 0160 void K3b::VideoDVDRippingView::slotStartRipping() 0161 { 0162 QList<int> titles = d->model->selectedTitles(); 0163 0164 if( titles.isEmpty() ) { 0165 KMessageBox::error( this, i18n("Please select the titles to rip."), 0166 i18n("No Titles Selected") ); 0167 } 0168 else { 0169 K3b::VideoDVDRippingDialog dlg( d->dvd, titles, this ); 0170 dlg.exec(); 0171 } 0172 } 0173 0174 0175 void K3b::VideoDVDRippingView::slotContextMenu( const QPoint& pos ) 0176 { 0177 d->popupMenu->popup( d->view->viewport()->mapToGlobal( pos ) ); 0178 } 0179 0180 0181 void K3b::VideoDVDRippingView::slotContextMenuAboutToShow() 0182 { 0183 QAction *actionCheckTracks = actionCollection()->action("check_tracks"); 0184 QAction *actionUncheckTracks = actionCollection()->action("uncheck_tracks"); 0185 const QModelIndexList selectedRows = d->view->selectionModel()->selectedRows(); 0186 0187 if ( !selectedRows.empty() ) { 0188 const Qt::CheckState commonState = mu::commonCheckState( selectedRows ); 0189 actionCheckTracks->setVisible( commonState != Qt::Checked ); 0190 actionCheckTracks->setText( selectedRows.count() == 1 ? i18n("Check Track") : i18n("Check Tracks") ); 0191 actionUncheckTracks->setVisible( commonState != Qt::Unchecked ); 0192 actionUncheckTracks->setText( selectedRows.count() == 1 ? i18n("Uncheck Track") : i18n("Uncheck Tracks") ); 0193 } else { 0194 actionCheckTracks->setVisible( false ); 0195 actionUncheckTracks->setVisible( false ); 0196 } 0197 } 0198 0199 0200 void K3b::VideoDVDRippingView::slotCheck() 0201 { 0202 Q_FOREACH( const QModelIndex& index, d->view->selectionModel()->selectedRows() ) 0203 { 0204 d->model->setData( index, Qt::Checked, Qt::CheckStateRole ); 0205 } 0206 } 0207 0208 0209 void K3b::VideoDVDRippingView::slotUncheck() 0210 { 0211 Q_FOREACH( const QModelIndex& index, d->view->selectionModel()->selectedRows() ) 0212 { 0213 d->model->setData( index, Qt::Unchecked, Qt::CheckStateRole ); 0214 } 0215 } 0216 0217 0218 void K3b::VideoDVDRippingView::slotToggle() 0219 { 0220 mu::toggleCommonCheckState( d->model, d->view->selectionModel()->selectedRows() ); 0221 } 0222 0223 0224 void K3b::VideoDVDRippingView::slotShowFiles() 0225 { 0226 QUrl url; 0227 url.setScheme( "videodvd" ); 0228 if( d->dvd.valid() ) { 0229 url.setPath( '/' + d->dvd.volumeIdentifier() ); 0230 } 0231 QDesktopServices::openUrl( url ); 0232 } 0233 0234 0235 void K3b::VideoDVDRippingView::reloadMedium() 0236 { 0237 // 0238 // For VideoDVD reading it is important that the DVD is not mounted 0239 // 0240 if( K3b::isMounted( device() ) && !K3b::unmount( device() ) ) { 0241 KMessageBox::error( this, 0242 i18n("K3b was unable to unmount device '%1' containing medium '%2'. " 0243 "Video DVD ripping will not work if the device is mounted. " 0244 "Please unmount manually.", 0245 device()->blockDeviceName(), 0246 k3bcore->mediaCache()->medium( device() ).shortString() ), 0247 i18n("Unmounting failed") ); 0248 } 0249 0250 // 0251 // K3b::VideoDVD::open does not necessarily fail on encrypted DVDs if dvdcss is not 0252 // available. Thus, we test the availability of libdvdcss here 0253 // 0254 if( device()->copyrightProtectionSystemType() == K3b::Device::COPYRIGHT_PROTECTION_CSS ) { 0255 K3b::LibDvdCss* css = K3b::LibDvdCss::create(); 0256 if( !css ) { 0257 KMessageBox::error( this, i18n("<p>Unable to read Video DVD contents: Found encrypted Video DVD." 0258 "<p>Install <i>libdvdcss</i> to get Video DVD decryption support.") ); 0259 return; 0260 } 0261 else 0262 delete css; 0263 } 0264 0265 QGuiApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); 0266 0267 if( d->dvd.open( device() ) ) { 0268 setTitle( i18n( "%1 (Video DVD)", medium().beautifiedVolumeId() ) ); 0269 d->labelLength->setText( i18np("%1 title", "%1 titles", d->dvd.numTitles() ) ); 0270 d->model->setVideoDVD( d->dvd ); 0271 QGuiApplication::restoreOverrideCursor(); 0272 0273 bool transcodeUsable = true; 0274 0275 if( !k3bcore ->externalBinManager() ->foundBin( "transcode" ) ) { 0276 KMessageBox::error( this, 0277 i18n("K3b uses transcode to rip Video DVDs. " 0278 "Please make sure it is installed.") ); 0279 transcodeUsable = false; 0280 } 0281 else { 0282 int vc = 0, ac = 0; 0283 for( int i = 0; i < K3b::VideoDVDTitleTranscodingJob::VIDEO_CODEC_NUM_ENTRIES; ++i ) 0284 if( K3b::VideoDVDTitleTranscodingJob::transcodeBinaryHasSupportFor( (K3b::VideoDVDTitleTranscodingJob::VideoCodec)i ) ) 0285 ++vc; 0286 for( int i = 0; i < K3b::VideoDVDTitleTranscodingJob::AUDIO_CODEC_NUM_ENTRIES; ++i ) 0287 if( K3b::VideoDVDTitleTranscodingJob::transcodeBinaryHasSupportFor( (K3b::VideoDVDTitleTranscodingJob::AudioCodec)i ) ) 0288 ++ac; 0289 if( !ac || !vc ) { 0290 KMessageBox::error( this, 0291 i18n("<p>K3b uses transcode to rip Video DVDs. " 0292 "Your installation of transcode lacks support for any of the " 0293 "codecs supported by K3b." 0294 "<p>Please make sure it is installed properly.") ); 0295 transcodeUsable = false; 0296 } 0297 } 0298 0299 actionCollection()->action("start_rip")->setEnabled( transcodeUsable ); 0300 } 0301 else { 0302 QGuiApplication::restoreOverrideCursor(); 0303 0304 KMessageBox::error( this, i18n("Unable to read Video DVD contents.") ); 0305 } 0306 } 0307 0308 0309 void K3b::VideoDVDRippingView::enableInteraction( bool enable ) 0310 { 0311 actionCollection()->action( "start_rip" )->setEnabled( enable ); 0312 } 0313 0314 0315 void K3b::VideoDVDRippingView::activate( bool active ) 0316 { 0317 if( !active ) 0318 { 0319 // 0320 // For now we do it the easy way: just stop the preview generation 0321 // once this view is no longer selected one 0322 // 0323 d->model->stopPreviewGen(); 0324 } 0325 0326 MediaContentsView::activate( active ); 0327 } 0328 0329 0330 void K3b::VideoDVDRippingView::initActions() 0331 { 0332 d->actionCollection = new KActionCollection( this ); 0333 0334 QAction* actionCheck = new QAction( this ); 0335 connect( actionCheck, SIGNAL(triggered()), this, SLOT(slotCheck()) ); 0336 actionCollection()->addAction( "check_tracks", actionCheck ); 0337 0338 QAction* actionUncheck = new QAction( this ); 0339 connect( actionUncheck, SIGNAL(triggered()), this, SLOT(slotUncheck()) ); 0340 actionCollection()->addAction( "uncheck_tracks", actionUncheck ); 0341 0342 QAction* actionStartRip = new QAction( QIcon::fromTheme( "tools-rip-video-dvd" ), i18n("Start Ripping"), this ); 0343 actionStartRip->setToolTip( i18n("Open the Video DVD ripping dialog") ); 0344 actionStartRip->setStatusTip(actionStartRip->toolTip()); 0345 actionStartRip->setWhatsThis( i18n("<p>Rips single titles from a video DVD " 0346 "into a compressed format such as XviD. Menu structures are completely ignored." 0347 "<p>If you intend to copy the plain Video DVD vob files from the DVD " 0348 "(including decryption) for further processing with another application, " 0349 "please use \"Show files\" button." 0350 "<p>If you intend to make a copy of the entire Video DVD including all menus " 0351 "and extras it is recommended to use the K3b Copy tool.") ); 0352 connect( actionStartRip, SIGNAL(triggered()), this, SLOT(slotStartRipping()) ); 0353 actionCollection()->addAction( "start_rip", actionStartRip ); 0354 0355 QAction* actionSelectAll = KStandardAction::selectAll( d->view, SLOT(selectAll()), actionCollection() ); 0356 0357 // setup the popup menu 0358 d->popupMenu = new QMenu( this ); 0359 d->popupMenu->addAction( actionCheck ); 0360 d->popupMenu->addAction( actionUncheck ); 0361 d->popupMenu->addSeparator(); 0362 d->popupMenu->addAction( actionSelectAll ); 0363 d->popupMenu->addSeparator(); 0364 d->popupMenu->addAction( actionStartRip ); 0365 connect( d->popupMenu, SIGNAL(aboutToShow()), this, SLOT(slotContextMenuAboutToShow()) ); 0366 } 0367 0368 #include "moc_k3bvideodvdrippingview.cpp"