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

0001 /*
0002     SPDX-FileCopyrightText: 2003-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
0004     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 
0010 #include "k3baudioprojectconvertingdialog.h"
0011 #include "k3baudioprojectconvertingjob.h"
0012 #include "k3bpatternparser.h"
0013 #include "k3bcddbpatternwidget.h"
0014 #include "k3baudioconvertingoptionwidget.h"
0015 
0016 #include "k3baudiodoc.h"
0017 #include "k3baudioview.h"
0018 #include "k3baudiotrack.h"
0019 #include "k3bjobprogressdialog.h"
0020 #include "k3bcore.h"
0021 #include "k3bglobals.h"
0022 #include "k3baudioencoder.h"
0023 
0024 #include <KComboBox>
0025 #include <KConfig>
0026 #include <KLocalizedString>
0027 #include <KIO/Global>
0028 #include <KUrlRequester>
0029 #include <KMessageBox>
0030 
0031 #include <QDebug>
0032 #include <QDir>
0033 #include <QStringList>
0034 #include <QCheckBox>
0035 #include <QGridLayout>
0036 #include <QHeaderView>
0037 #include <QLabel>
0038 #include <QLayout>
0039 #include <QTabWidget>
0040 #include <QTreeWidget>
0041 
0042 #include <KCDDB/CDInfo>
0043 
0044 
0045 namespace {
0046     KCDDB::CDInfo createCddbEntryFromDoc( K3b::AudioDoc* doc )
0047     {
0048         KCDDB::CDInfo e;
0049 
0050         // global
0051         e.set( KCDDB::Title, doc->title() );
0052         e.set( KCDDB::Artist, doc->artist() );
0053         e.set( KCDDB::Comment, doc->cdTextMessage() );
0054 
0055         // tracks
0056         int i = 0;
0057         K3b::AudioTrack* track = doc->firstTrack();
0058         while( track ) {
0059             e.track( i ).set( KCDDB::Title, track->title() );
0060             e.track( i ).set( KCDDB::Artist, track->artist() );
0061             e.track( i ).set( KCDDB::Comment, track->cdTextMessage() );
0062 
0063             track = track->next();
0064             ++i;
0065         }
0066 
0067         return e;
0068     }
0069 }
0070 
0071 class K3b::AudioProjectConvertingDialog::Private
0072 {
0073 public:
0074     Private() {
0075     }
0076 
0077     QTreeWidget* viewTracks;
0078     QVector<QString> filenames;
0079     QString playlistFilename;
0080 };
0081 
0082 
0083 K3b::AudioProjectConvertingDialog::AudioProjectConvertingDialog( K3b::AudioDoc* doc, QWidget *parent )
0084     : K3b::InteractionDialog( parent,
0085                             QString(),
0086                             QString(),
0087                             START_BUTTON|CANCEL_BUTTON,
0088                             START_BUTTON,
0089                             "Audio Project Converting" ), // config group
0090       m_doc(doc)
0091 {
0092     d = new Private();
0093 
0094     setupGui();
0095 
0096     setTitle( i18n("Audio Project Conversion"),
0097               i18np("1 track (%2)", "%1 tracks (%2)",
0098                     m_doc->numOfTracks(),m_doc->length().toString()) );
0099 
0100     refresh();
0101 }
0102 
0103 
0104 K3b::AudioProjectConvertingDialog::~AudioProjectConvertingDialog()
0105 {
0106     delete d;
0107 }
0108 
0109 
0110 void K3b::AudioProjectConvertingDialog::setupGui()
0111 {
0112     QWidget *frame = mainWidget();
0113     QGridLayout* Form1Layout = new QGridLayout( frame );
0114     Form1Layout->setContentsMargins( 0, 0, 0, 0 );
0115 
0116     QTreeWidgetItem* header = new QTreeWidgetItem;
0117     header->setText( 0, i18n( "Filename (relative to base folder)") );
0118     header->setText( 1, i18n( "Length") );
0119     header->setText( 2, i18n( "File Size") );
0120 
0121     d->viewTracks = new QTreeWidget( frame );
0122     d->viewTracks->setSortingEnabled( false );
0123     d->viewTracks->setAllColumnsShowFocus( true );
0124     d->viewTracks->setRootIsDecorated( false );
0125     d->viewTracks->setSelectionMode( QAbstractItemView::NoSelection );
0126     d->viewTracks->setFocusPolicy( Qt::NoFocus );
0127     d->viewTracks->setHeaderItem( header );
0128     d->viewTracks->header()->setStretchLastSection( false );
0129     d->viewTracks->header()->setSectionResizeMode( 0, QHeaderView::Stretch );
0130     d->viewTracks->header()->setSectionResizeMode( 1, QHeaderView::ResizeToContents );
0131     d->viewTracks->header()->setSectionResizeMode( 2, QHeaderView::ResizeToContents );
0132 
0133     QTabWidget* mainTab = new QTabWidget( frame );
0134 
0135     m_optionWidget = new K3b::AudioConvertingOptionWidget( mainTab );
0136     mainTab->addTab( m_optionWidget, i18n("Settings") );
0137 
0138 
0139     // setup filename pattern page
0140     // -------------------------------------------------------------------------------------------
0141     m_patternWidget = new K3b::CddbPatternWidget( mainTab );
0142     mainTab->addTab( m_patternWidget, i18n("File Naming") );
0143     connect( m_patternWidget, SIGNAL(changed()), this, SLOT(refresh()) );
0144 
0145     Form1Layout->addWidget( d->viewTracks, 0, 0 );
0146     Form1Layout->addWidget( mainTab, 1, 0 );
0147     Form1Layout->setRowStretch( 0, 1 );
0148 
0149     connect( m_optionWidget, SIGNAL(changed()), this, SLOT(refresh()) );
0150 }
0151 
0152 
0153 void K3b::AudioProjectConvertingDialog::slotStartClicked()
0154 {
0155     // check if all filenames differ
0156     if( d->filenames.count() > 1 ) {
0157         bool differ = true;
0158         // the most stupid version to compare but most cds have about 12 tracks
0159         // that's a size where algorithms do not need any optimization! ;)
0160         for( int i = 0; i < d->filenames.count(); ++i ) {
0161             for( int j = i+1; j < d->filenames.count(); ++j )
0162                 if( d->filenames[i] == d->filenames[j] ) {
0163                     differ = false;
0164                     break;
0165                 }
0166         }
0167 
0168         if( !differ ) {
0169             KMessageBox::error( this, i18n("Please check the naming pattern. All filenames need to be unique.") );
0170             return;
0171         }
0172     }
0173 
0174     // check if we need to overwrite some files...
0175     QStringList filesToOverwrite;
0176     for( int i = 0; i < d->filenames.count(); ++i ) {
0177         if( QFile::exists( d->filenames[i] ) )
0178             filesToOverwrite.append( d->filenames[i] );
0179     }
0180 
0181     if( m_optionWidget->createPlaylist() && QFile::exists( d->playlistFilename ) )
0182         filesToOverwrite.append( d->playlistFilename );
0183 
0184     if( !filesToOverwrite.isEmpty() )
0185         if( KMessageBox::warningContinueCancelList( this,
0186                                                     i18n("Do you want to overwrite these files?"),
0187                                                     filesToOverwrite,
0188                                                     i18n("Files Exist"), KStandardGuiItem::overwrite() )
0189             == KMessageBox::Cancel )
0190             return;
0191 
0192 
0193     // just generate a fake m_tracks list for now so we can keep most of the methods
0194     // like they are in K3b::AudioRipJob. This way future combination is easier
0195     AudioProjectConvertingJob::Tracks tracksToRip;
0196     if( m_optionWidget->createSingleFile() && !d->filenames.isEmpty() ) {
0197         // Since QMultiMap stores multiple values "from most recently to least recently inserted"
0198         // we will add it in reverse order to rip in ascending order
0199         for( AudioTrack* track = m_doc->lastTrack(); track != 0; track = track->prev() )
0200             tracksToRip.insert( d->filenames.front(), track->trackNumber() );
0201     }
0202     else {
0203         for( AudioTrack* track = m_doc->firstTrack(); track != 0; track = track->next() )
0204             tracksToRip.insert( d->filenames[ track->trackNumber()-1 ], track->trackNumber() );
0205     }
0206 
0207     K3b::AudioEncoder* encoder = m_optionWidget->encoder();
0208 
0209     K3b::JobProgressDialog progressDialog( parentWidget() );
0210     K3b::AudioProjectConvertingJob job( m_doc, &progressDialog, 0 );
0211     job.setCddbEntry( createCddbEntryFromDoc( m_doc ) );
0212     job.setTrackList( tracksToRip );
0213     job.setEncoder( encoder );
0214     job.setWriteCueFile( m_optionWidget->createSingleFile() && m_optionWidget->createCueFile() );
0215     if( m_optionWidget->createPlaylist() )
0216         job.setWritePlaylist( d->playlistFilename, m_optionWidget->playlistRelativePath() );
0217     if( encoder )
0218         job.setFileType( m_optionWidget->extension() );
0219 
0220     hide();
0221     progressDialog.startJob(&job);
0222 
0223     close();
0224 }
0225 
0226 
0227 void K3b::AudioProjectConvertingDialog::refresh()
0228 {
0229 #ifdef __GNUC__
0230 #warning Reuse the code from AudioRippingDialog
0231 #endif
0232     d->viewTracks->clear();
0233     d->filenames.clear();
0234 
0235     // FIXME: this is bad and needs to be improved
0236     // create a cddb entry from the doc to use in the patternparser
0237     KCDDB::CDInfo cddbEntry = createCddbEntryFromDoc( m_doc );
0238 
0239     QString baseDir = K3b::prepareDir( m_optionWidget->baseDir() );
0240 
0241     QString extension = m_optionWidget->extension();
0242 
0243     KIO::filesize_t overallSize = 0;
0244 
0245     if( m_optionWidget->createSingleFile() ) {
0246         QString filename;
0247         long long filesize = 0;
0248         if( m_optionWidget->encoder() == 0 ) {
0249             filesize = m_doc->length().audioBytes() + 44;
0250         }
0251         else {
0252             filesize = m_optionWidget->encoder()->fileSize( extension, m_doc->length() );
0253         }
0254 
0255         if( filesize > 0 )
0256             overallSize = filesize;
0257 
0258         filename = K3b::PatternParser::parsePattern( cddbEntry, 1,
0259                                                      extension,
0260                                                      m_patternWidget->playlistPattern(),
0261                                                      m_patternWidget->replaceBlanks(),
0262                                                      m_patternWidget->blankReplaceString() );
0263 
0264         QTreeWidgetItem* item = new QTreeWidgetItem( d->viewTracks );
0265         item->setText( 0, filename );
0266         item->setText( 1, m_doc->length().toString() );
0267         item->setText( 2, filesize < 0 ? i18n("unknown") : KIO::convertSize( filesize ) );
0268 
0269         d->filenames.append( K3b::fixupPath( baseDir + '/' + filename ) );
0270 
0271         if( m_optionWidget->createCueFile() ) {
0272             QString cueFilename = K3b::PatternParser::parsePattern( cddbEntry, 1,
0273                                                                QLatin1String( "cue" ),
0274                                                                m_patternWidget->playlistPattern(),
0275                                                                m_patternWidget->replaceBlanks(),
0276                                                                m_patternWidget->blankReplaceString() );
0277             item = new QTreeWidgetItem( d->viewTracks );
0278             item->setText( 0, cueFilename );
0279             item->setText( 1, "-" );
0280             item->setText( 2, "-" );
0281         }
0282     }
0283     else {
0284         d->filenames.resize( m_doc->numOfTracks() );
0285         for( AudioTrack* track = m_doc->firstTrack(); track != 0; track = track->next() ) {
0286             long long filesize = 0;
0287             if( m_optionWidget->encoder() == 0 ) {
0288                 filesize = track->length().audioBytes() + 44;
0289             }
0290             else {
0291                 filesize = m_optionWidget->encoder()->fileSize( extension, track->length() );
0292             }
0293 
0294             if( filesize > 0 )
0295                 overallSize += filesize;
0296 
0297             QString filename = K3b::PatternParser::parsePattern( cddbEntry, track->trackNumber(),
0298                                                                  extension,
0299                                                                  m_patternWidget->filenamePattern(),
0300                                                                  m_patternWidget->replaceBlanks(),
0301                                                                  m_patternWidget->blankReplaceString() );
0302 
0303             QTreeWidgetItem* item = new QTreeWidgetItem( d->viewTracks );
0304             item->setText( 0, filename );
0305             item->setText( 1, track->length().toString() );
0306             item->setText( 2, filesize < 0 ? i18n("unknown") : KIO::convertSize( filesize ) );
0307 
0308             d->filenames[ track->trackNumber()-1 ] = K3b::fixupPath( baseDir + '/' + filename );
0309         }
0310     }
0311 
0312     // create playlist item
0313     if( m_optionWidget->createPlaylist() ) {
0314         QString filename = K3b::PatternParser::parsePattern( cddbEntry, 1,
0315                                                              QLatin1String( "m3u" ),
0316                                                              m_patternWidget->playlistPattern(),
0317                                                              m_patternWidget->replaceBlanks(),
0318                                                              m_patternWidget->blankReplaceString() );
0319 
0320         QTreeWidgetItem* item = new QTreeWidgetItem( d->viewTracks );
0321         item->setText( 0, filename );
0322         item->setText( 1, "-" );
0323         item->setText( 2, "-" );
0324 
0325         d->playlistFilename = K3b::fixupPath( baseDir + '/' + filename );
0326     }
0327 
0328     if( overallSize > 0 )
0329         m_optionWidget->setNeededSize( overallSize );
0330     else
0331         m_optionWidget->setNeededSize( 0 );
0332 }
0333 
0334 
0335 void K3b::AudioProjectConvertingDialog::setBaseDir( const QString& path )
0336 {
0337     m_optionWidget->setBaseDir( path );
0338 }
0339 
0340 
0341 void K3b::AudioProjectConvertingDialog::loadSettings( const KConfigGroup& c )
0342 {
0343     m_optionWidget->loadConfig( c );
0344     m_patternWidget->loadConfig( c );
0345 
0346     refresh();
0347 }
0348 
0349 
0350 void K3b::AudioProjectConvertingDialog::saveSettings( KConfigGroup c )
0351 {
0352     m_optionWidget->saveConfig( c );
0353     m_patternWidget->saveConfig( c );
0354 }
0355 
0356 #include "moc_k3baudioprojectconvertingdialog.cpp"