|
|
|
/*
|
|
|
|
*
|
|
|
|
* $Id: sourceheader 511311 2006-02-19 14:51:05Z trueg $
|
|
|
|
* Copyright (C) 2006 Sebastian Trueg <trueg@k3b.org>
|
|
|
|
*
|
|
|
|
* This file is part of the K3b project.
|
|
|
|
* Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
* See the file "COPYING" for the exact licensing terms.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "k3baudiotrackaddingdialog.h"
|
|
|
|
|
|
|
|
#include <k3baudiodoc.h>
|
|
|
|
#include <k3baudiotrack.h>
|
|
|
|
#include <k3baudiofile.h>
|
|
|
|
#include <k3baudiodecoder.h>
|
|
|
|
#include <k3bbusywidget.h>
|
|
|
|
#include <k3bglobals.h>
|
|
|
|
#include <k3bthread.h>
|
|
|
|
#include <k3bthreadjob.h>
|
|
|
|
#include <k3bcuefileparser.h>
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
|
|
|
|
|
|
|
|
class K3bAudioTrackAddingDialog::AnalyserThread : public K3bThread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AnalyserThread()
|
|
|
|
: K3bThread(),
|
|
|
|
m_decoder(0) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void run() {
|
|
|
|
emitStarted();
|
|
|
|
m_decoder->analyseFile();
|
|
|
|
emitFinished( m_decoder->isValid() );
|
|
|
|
}
|
|
|
|
|
|
|
|
K3bAudioDecoder* m_decoder;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
K3bAudioTrackAddingDialog::K3bAudioTrackAddingDialog( TQWidget* parent, const char* name )
|
|
|
|
: KDialogBase( Plain,
|
|
|
|
i18n("Please be patient..."),
|
|
|
|
Cancel,
|
|
|
|
Cancel,
|
|
|
|
parent,
|
|
|
|
name,
|
|
|
|
true,
|
|
|
|
true ),
|
|
|
|
m_bCanceled(false)
|
|
|
|
{
|
|
|
|
TQWidget* page = plainPage();
|
|
|
|
TQGridLayout* grid = new TQGridLayout( page );
|
|
|
|
grid->setSpacing( spacingHint() );
|
|
|
|
grid->setMargin( marginHint() );
|
|
|
|
|
|
|
|
m_infoLabel = new TQLabel( page );
|
|
|
|
m_busyWidget = new K3bBusyWidget( page );
|
|
|
|
|
|
|
|
grid->addWidget( m_infoLabel, 0, 0 );
|
|
|
|
grid->addWidget( m_busyWidget, 1, 0 );
|
|
|
|
|
|
|
|
m_analyserThread = new AnalyserThread();
|
|
|
|
m_analyserJob = new K3bThreadJob( m_analyserThread, this, TQT_TQOBJECT(this) );
|
|
|
|
connect( m_analyserJob, TQT_SIGNAL(finished(bool)), this, TQT_SLOT(slotAnalysingFinished(bool)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
K3bAudioTrackAddingDialog::~K3bAudioTrackAddingDialog()
|
|
|
|
{
|
|
|
|
delete m_analyserThread;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int K3bAudioTrackAddingDialog::addUrls( const KURL::List& urls,
|
|
|
|
K3bAudioDoc* doc,
|
|
|
|
K3bAudioTrack* afterTrack,
|
|
|
|
K3bAudioTrack* parentTrack,
|
|
|
|
K3bAudioDataSource* afterSource,
|
|
|
|
TQWidget* parent )
|
|
|
|
{
|
|
|
|
if( urls.isEmpty() )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
K3bAudioTrackAddingDialog dlg( parent );
|
|
|
|
dlg.m_urls = extractUrlList( urls );
|
|
|
|
dlg.m_doc = doc;
|
|
|
|
dlg.m_trackAfter = afterTrack;
|
|
|
|
dlg.m_parentTrack = parentTrack;
|
|
|
|
dlg.m_sourceAfter = afterSource;
|
|
|
|
dlg.m_infoLabel->setText( i18n("Adding files to project \"%1\"...").arg(doc->URL().fileName()) );
|
|
|
|
|
|
|
|
dlg.m_busyWidget->showBusy(true);
|
|
|
|
TQTimer::singleShot( 0, &dlg, TQT_SLOT(slotAddUrls()) );
|
|
|
|
int ret = dlg.exec();
|
|
|
|
|
|
|
|
TQString message;
|
|
|
|
if( !dlg.m_unreadableFiles.isEmpty() )
|
|
|
|
message += TQString("<p><b>%1:</b><br>%2")
|
|
|
|
.arg( i18n("Insufficient permissions to read the following files") )
|
|
|
|
.arg( dlg.m_unreadableFiles.join( "<br>" ) );
|
|
|
|
if( !dlg.m_notFoundFiles.isEmpty() )
|
|
|
|
message += TQString("<p><b>%1:</b><br>%2")
|
|
|
|
.arg( i18n("Unable to find the following files") )
|
|
|
|
.arg( dlg.m_notFoundFiles.join( "<br>" ) );
|
|
|
|
if( !dlg.m_nonLocalFiles.isEmpty() )
|
|
|
|
message += TQString("<p><b>%1:</b><br>%2")
|
|
|
|
.arg( i18n("No non-local files supported") )
|
|
|
|
.arg( dlg.m_unreadableFiles.join( "<br>" ) );
|
|
|
|
if( !dlg.m_unsupportedFiles.isEmpty() )
|
|
|
|
message += TQString("<p><b>%1:</b><br><i>%2</i><br>%3")
|
|
|
|
.arg( i18n("Unable to handle the following files due to an unsupported format" ) )
|
|
|
|
.arg( i18n("You may manually convert these audio files to wave using another "
|
|
|
|
"application supporting the audio format and then add the wave files "
|
|
|
|
"to the K3b project.") )
|
|
|
|
.arg( dlg.m_unsupportedFiles.join( "<br>" ) );
|
|
|
|
|
|
|
|
if( !message.isEmpty() )
|
|
|
|
KMessageBox::detailedSorry( parent, i18n("Problems while adding files to the project."), message );
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void K3bAudioTrackAddingDialog::slotAddUrls()
|
|
|
|
{
|
|
|
|
if( m_bCanceled )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( m_urls.isEmpty() ) {
|
|
|
|
accept();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KURL url = m_urls.first();
|
|
|
|
bool valid = true;
|
|
|
|
|
|
|
|
if( url.path().right(3).lower() == "cue" ) {
|
|
|
|
// see if its a cue file
|
|
|
|
K3bCueFileParser parser( url.path() );
|
|
|
|
if( parser.isValid() && parser.toc().contentType() == K3bDevice::AUDIO ) {
|
|
|
|
// remember cue url and set the new audio file url
|
|
|
|
m_cueUrl = url;
|
|
|
|
url = m_urls[0] = KURL::fromPathOrURL( parser.imageFilename() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_infoLabel->setText( i18n("Analysing file '%1'...").arg( url.fileName() ) );
|
|
|
|
|
|
|
|
if( !url.isLocalFile() ) {
|
|
|
|
valid = false;
|
|
|
|
m_nonLocalFiles.append( url.path() );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
TQFileInfo fi( url.path() );
|
|
|
|
if( !fi.exists() ) {
|
|
|
|
valid = false;
|
|
|
|
m_notFoundFiles.append( url.path() );
|
|
|
|
}
|
|
|
|
else if( !fi.isReadable() ) {
|
|
|
|
valid = false;
|
|
|
|
m_unreadableFiles.append( url.path() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( valid ) {
|
|
|
|
bool reused;
|
|
|
|
K3bAudioDecoder* dec = m_doc->getDecoderForUrl( url, &reused );
|
|
|
|
if( dec ) {
|
|
|
|
m_analyserThread->m_decoder = dec;
|
|
|
|
if( reused )
|
|
|
|
slotAnalysingFinished( true );
|
|
|
|
else
|
|
|
|
m_analyserJob->start();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
valid = false;
|
|
|
|
m_unsupportedFiles.append( url.path() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// invalid file, next url
|
|
|
|
if( !valid ) {
|
|
|
|
m_urls.remove( m_urls.begin() );
|
|
|
|
TQTimer::singleShot( 0, this, TQT_SLOT(slotAddUrls()) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void K3bAudioTrackAddingDialog::slotAnalysingFinished( bool /*success*/ )
|
|
|
|
{
|
|
|
|
if( m_bCanceled ) {
|
|
|
|
// We only started the analyser thread in case the decoder was new
|
|
|
|
// thus, we can safely delete it since no other source needs it.
|
|
|
|
delete m_analyserThread->m_decoder;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KURL url = m_urls.first();
|
|
|
|
m_urls.remove( m_urls.begin() );
|
|
|
|
|
|
|
|
if( m_cueUrl.isValid() ) {
|
|
|
|
// import the cue file
|
|
|
|
m_doc->importCueFile( m_cueUrl.path(), m_trackAfter, m_analyserThread->m_decoder );
|
|
|
|
m_cueUrl = KURL();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// create the track and source items
|
|
|
|
K3bAudioDecoder* dec = m_analyserThread->m_decoder;
|
|
|
|
K3bAudioFile* file = new K3bAudioFile( dec, m_doc );
|
|
|
|
if( m_parentTrack ) {
|
|
|
|
if( m_sourceAfter )
|
|
|
|
file->moveAfter( m_sourceAfter );
|
|
|
|
else
|
|
|
|
file->moveAhead( m_parentTrack->firstSource() );
|
|
|
|
m_sourceAfter = file;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
K3bAudioTrack* track = new K3bAudioTrack( m_doc );
|
|
|
|
track->setFirstSource( file );
|
|
|
|
|
|
|
|
track->setTitle( dec->metaInfo( K3bAudioDecoder::META_TITLE ) );
|
|
|
|
track->setArtist( dec->metaInfo( K3bAudioDecoder::META_ARTIST ) );
|
|
|
|
track->setSongwriter( dec->metaInfo( K3bAudioDecoder::META_SONGWRITER ) );
|
|
|
|
track->setComposer( dec->metaInfo( K3bAudioDecoder::META_COMPOSER ) );
|
|
|
|
track->setCdTextMessage( dec->metaInfo( K3bAudioDecoder::META_COMMENT ) );
|
|
|
|
|
|
|
|
if( m_trackAfter )
|
|
|
|
track->moveAfter( m_trackAfter );
|
|
|
|
else
|
|
|
|
track->moveAfter( m_doc->lastTrack() );
|
|
|
|
|
|
|
|
m_trackAfter = track;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQTimer::singleShot( 0, this, TQT_SLOT(slotAddUrls()) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void K3bAudioTrackAddingDialog::slotCancel()
|
|
|
|
{
|
|
|
|
m_bCanceled = true;
|
|
|
|
m_analyserJob->cancel();
|
|
|
|
KDialogBase::slotCancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KURL::List K3bAudioTrackAddingDialog::extractUrlList( const KURL::List& urls )
|
|
|
|
{
|
|
|
|
KURL::List allUrls = urls;
|
|
|
|
KURL::List urlsFromPlaylist;
|
|
|
|
KURL::List::iterator it = allUrls.begin();
|
|
|
|
while( it != allUrls.end() ) {
|
|
|
|
|
|
|
|
const KURL& url = *it;
|
|
|
|
TQFileInfo fi( url.path() );
|
|
|
|
|
|
|
|
if( fi.isDir() ) {
|
|
|
|
it = allUrls.remove( it );
|
|
|
|
// add all files in the dir
|
|
|
|
TQDir dir(fi.filePath());
|
|
|
|
TQStringList entries = dir.entryList( TQDir::Files );
|
|
|
|
KURL::List::iterator oldIt = it;
|
|
|
|
// add all files into the list after the current item
|
|
|
|
for( TQStringList::iterator dirIt = entries.begin();
|
|
|
|
dirIt != entries.end(); ++dirIt )
|
|
|
|
it = allUrls.insert( oldIt, KURL::fromPathOrURL( dir.absPath() + "/" + *dirIt ) );
|
|
|
|
}
|
|
|
|
else if( K3bAudioDoc::readPlaylistFile( url, urlsFromPlaylist ) ) {
|
|
|
|
it = allUrls.remove( it );
|
|
|
|
KURL::List::iterator oldIt = it;
|
|
|
|
// add all files into the list after the current item
|
|
|
|
for( KURL::List::iterator dirIt = urlsFromPlaylist.begin();
|
|
|
|
dirIt != urlsFromPlaylist.end(); ++dirIt )
|
|
|
|
it = allUrls.insert( oldIt, *dirIt );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return allUrls;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "k3baudiotrackaddingdialog.moc"
|