File indexing completed on 2024-05-05 04:51:41

0001 /*
0002     SPDX-FileCopyrightText: 2006-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 #include "k3baudiotrackaddingdialog.h"
0010 #include "k3baudiofileanalyzerjob.h"
0011 
0012 #include "k3baudiodoc.h"
0013 #include "k3baudiotrack.h"
0014 #include "k3baudiofile.h"
0015 #include "k3baudiodecoder.h"
0016 #include "k3bbusywidget.h"
0017 #include "k3bglobals.h"
0018 #include "k3bcuefileparser.h"
0019 
0020 #include <KLocalizedString>
0021 #include <KMessageBox>
0022 
0023 #include <QDebug>
0024 #include <QDir>
0025 #include <QFileInfo>
0026 #include <QThread>
0027 #include <QDialogButtonBox>
0028 #include <QLabel>
0029 #include <QVBoxLayout>
0030 #include <QPushButton>
0031 
0032 
0033 K3b::AudioTrackAddingDialog::AudioTrackAddingDialog( const QList<QUrl>& urls,
0034                                                      AudioDoc* doc,
0035                                                      AudioTrack* afterTrack,
0036                                                      AudioTrack* parentTrack,
0037                                                      AudioDataSource* afterSource,
0038                                                      QWidget* parent )
0039     : QDialog( parent),
0040       m_urls( AudioDoc::extractUrlList( urls ) ),
0041       m_doc( doc ),
0042       m_trackAfter( afterTrack ),
0043       m_parentTrack( parentTrack ),
0044       m_sourceAfter( afterSource ),
0045       m_bCanceled( false )
0046 {
0047     setWindowTitle(i18n("Please be patient..."));
0048 
0049     m_infoLabel = new QLabel( this );
0050     m_infoLabel->setText( i18n("Adding files to project \"%1\"...",doc->URL().fileName()) );
0051     m_busyWidget = new K3b::BusyWidget( this );
0052     m_busyWidget->showBusy( true );
0053 
0054     QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Cancel, this );
0055     connect( buttonBox, SIGNAL(rejected()), SLOT(reject()) );
0056 
0057     QVBoxLayout* layout = new QVBoxLayout( this );
0058     layout->addWidget( m_infoLabel );
0059     layout->addWidget( m_busyWidget );
0060     layout->addWidget( buttonBox );
0061 
0062     m_analyserJob = new K3b::AudioFileAnalyzerJob( this, this );
0063     connect( m_analyserJob, SIGNAL(finished(bool)), this, SLOT(slotAnalysingFinished(bool)) );
0064     connect(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(slotCancelClicked()));
0065 }
0066 
0067 
0068 K3b::AudioTrackAddingDialog::~AudioTrackAddingDialog()
0069 {
0070     QString message;
0071     if( !m_unreadableFiles.isEmpty() )
0072         message += QString("<p><b>%1:</b><br>%2")
0073                    .arg( i18n("Insufficient permissions to read the following files") )
0074                    .arg( m_unreadableFiles.join( "<br>" ) );
0075     if( !m_notFoundFiles.isEmpty() )
0076         message += QString("<p><b>%1:</b><br>%2")
0077                    .arg( i18n("Unable to find the following files") )
0078                    .arg( m_notFoundFiles.join( "<br>" ) );
0079     if( !m_nonLocalFiles.isEmpty() )
0080         message += QString("<p><b>%1:</b><br>%2")
0081                    .arg( i18n("No non-local files supported") )
0082                    .arg( m_unreadableFiles.join( "<br>" ) );
0083     if( !m_unsupportedFiles.isEmpty() )
0084         message += QString("<p><b>%1:</b><br><i>%2</i><br>%3")
0085                    .arg( i18n("Unable to handle the following files due to an unsupported format" ) )
0086                    .arg( i18n("You may manually convert these audio files to wave using another "
0087                               "application supporting the audio format and then add the wave files "
0088                               "to the K3b project.") )
0089                    .arg( m_unsupportedFiles.join( "<br>" ) );
0090 
0091     if( !message.isEmpty() )
0092         KMessageBox::detailedError( parentWidget(), i18n("Problems while adding files to the project."), message );
0093 }
0094 
0095 
0096 void K3b::AudioTrackAddingDialog::addUrls( const QList<QUrl>& urls,
0097                                           K3b::AudioDoc* doc,
0098                                           K3b::AudioTrack* afterTrack,
0099                                           K3b::AudioTrack* parentTrack,
0100                                           K3b::AudioDataSource* afterSource,
0101                                           QWidget* parent )
0102 {
0103     if( !urls.isEmpty() )
0104     {
0105         K3b::AudioTrackAddingDialog* dlg = new K3b::AudioTrackAddingDialog(
0106             urls, doc, afterTrack, parentTrack, afterSource, parent );
0107         dlg->setAttribute( Qt::WA_DeleteOnClose );
0108         QMetaObject::invokeMethod( dlg, "exec", Qt::QueuedConnection );
0109         QMetaObject::invokeMethod( dlg, "slotAddUrls", Qt::QueuedConnection );
0110     }
0111 }
0112 
0113 
0114 void K3b::AudioTrackAddingDialog::slotAddUrls()
0115 {
0116     if( m_bCanceled )
0117         return;
0118 
0119     if( m_urls.isEmpty() ) {
0120         accept();
0121         return;
0122     }
0123 
0124     QUrl url = m_urls.first();
0125     bool valid = true;
0126 
0127     if( url.toLocalFile().right(3).toLower() == "cue" ) {
0128         // see if its a cue file
0129         K3b::CueFileParser parser( url.toLocalFile() );
0130         if( parser.isValid() && parser.toc().contentType() == K3b::Device::AUDIO ) {
0131             if ( parser.imageFileType() == QLatin1String( "bin" ) ) {
0132                 // no need to analyze -> raw audio data
0133                 m_doc->importCueFile( url.toLocalFile(), m_trackAfter, 0 );
0134                 m_urls.erase( m_urls.begin() );
0135                 QMetaObject::invokeMethod( this, "slotAddUrls", Qt::QueuedConnection );
0136                 return;
0137             }
0138             else {
0139                 // remember cue url and set the new audio file url
0140                 m_cueUrl = url;
0141                 url = m_urls[0] = QUrl::fromLocalFile( parser.imageFilename() );
0142             }
0143         }
0144     }
0145 
0146     m_infoLabel->setText( i18n("Analysing file '%1'..." , url.fileName() ) );
0147 
0148     if( !url.isLocalFile() ) {
0149         valid = false;
0150         m_nonLocalFiles.append( url.toLocalFile() );
0151     }
0152     else {
0153         QFileInfo fi( url.toLocalFile() );
0154         if( !fi.exists() ) {
0155             valid = false;
0156             m_notFoundFiles.append( url.toLocalFile() );
0157         }
0158         else if( !fi.isReadable() ) {
0159             valid = false;
0160             m_unreadableFiles.append( url.toLocalFile() );
0161         }
0162     }
0163 
0164     if( valid ) {
0165         bool reused;
0166         K3b::AudioDecoder* dec = m_doc->getDecoderForUrl( url, &reused );
0167         if( dec ) {
0168             m_analyserJob->setDecoder( dec );
0169             if( reused )
0170                 slotAnalysingFinished( true );
0171             else
0172                 m_analyserJob->start();
0173         }
0174         else {
0175             valid = false;
0176             m_unsupportedFiles.append( url.toLocalFile() );
0177         }
0178     }
0179 
0180     // invalid file, next url
0181     if( !valid ) {
0182         m_urls.erase( m_urls.begin() );
0183         QMetaObject::invokeMethod( this, "slotAddUrls", Qt::QueuedConnection );
0184     }
0185 }
0186 
0187 
0188 void K3b::AudioTrackAddingDialog::slotAnalysingFinished( bool /*success*/ )
0189 {
0190     if( m_bCanceled ) {
0191         // We only started the analyser thread in case the decoder was new
0192         // thus, we can safely delete it since no other source needs it.
0193         delete m_analyserJob->decoder();
0194         return;
0195     }
0196 
0197     QUrl url = m_urls.first();
0198     m_urls.erase( m_urls.begin() );
0199 
0200     if( m_cueUrl.isValid() ) {
0201         // import the cue file
0202         m_doc->importCueFile( m_cueUrl.toLocalFile(), m_trackAfter, m_analyserJob->decoder() );
0203         m_cueUrl = QUrl();
0204     }
0205     else {
0206         // create the track and source items
0207         K3b::AudioDecoder* dec = m_analyserJob->decoder();
0208         K3b::AudioFile* file = new K3b::AudioFile( dec, m_doc );
0209         if( m_parentTrack ) {
0210             if( m_sourceAfter )
0211                 file->moveAfter( m_sourceAfter );
0212             else
0213                 file->moveAhead( m_parentTrack->firstSource() );
0214             m_sourceAfter = file;
0215         }
0216         else {
0217             K3b::AudioTrack* track = new K3b::AudioTrack( m_doc );
0218             track->setFirstSource( file );
0219 
0220             track->setTitle( dec->metaInfo( K3b::AudioDecoder::META_TITLE ) );
0221             track->setArtist( dec->metaInfo( K3b::AudioDecoder::META_ARTIST ) );
0222             track->setSongwriter( dec->metaInfo( K3b::AudioDecoder::META_SONGWRITER ) );
0223             track->setComposer( dec->metaInfo( K3b::AudioDecoder::META_COMPOSER ) );
0224             track->setCdTextMessage( dec->metaInfo( K3b::AudioDecoder::META_COMMENT ) );
0225 
0226             if( m_trackAfter )
0227                 track->moveAfter( m_trackAfter );
0228             else if ( m_doc->lastTrack() )
0229                 track->moveAfter( m_doc->lastTrack() );
0230             else
0231                 m_doc->addTrack( track, 0 );
0232 
0233             m_trackAfter = track;
0234         }
0235     }
0236 
0237     QMetaObject::invokeMethod( this, "slotAddUrls", Qt::QueuedConnection );
0238 }
0239 
0240 
0241 void K3b::AudioTrackAddingDialog::slotCancelClicked()
0242 {
0243     m_bCanceled = true;
0244     m_analyserJob->cancel();
0245     m_analyserJob->wait();
0246 }
0247 
0248 #include "moc_k3baudiotrackaddingdialog.cpp"