/* * * $Id: k3bdatajob.cpp 690187 2007-07-20 09:18:03Z trueg $ * Copyright (C) 2003 Sebastian Trueg * * This file is part of the K3b project. * Copyright (C) 1998-2007 Sebastian Trueg * * 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 "k3bdatajob.h" #include "k3bdatadoc.h" #include "k3bisoimager.h" #include "k3bmsinfofetcher.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class K3bDataJob::Private { public: Private() : usedWritingApp(K3b::CDRECORD), verificationJob(0) { } K3bDataDoc* doc; bool initializingImager; bool imageFinished; bool canceled; KTempFile* tocFile; int usedDataMode; int usedWritingApp; int usedWritingMode; K3bDataDoc::MultiSessionMode usedMultiSessionMode; int copies; int copiesDone; K3bVerificationJob* verificationJob; K3bFileSplitter imageFile; K3bActivePipe pipe; }; K3bDataJob::K3bDataJob( K3bDataDoc* doc, K3bJobHandler* hdl, TQObject* parent ) : K3bBurnJob( hdl, parent ) { d = new Private; d->doc = doc; m_writerJob = 0; d->tocFile = 0; m_isoImager = 0; m_msInfoFetcher = new K3bMsInfoFetcher( this, this ); connect( m_msInfoFetcher, TQT_SIGNAL(finished(bool)), this, TQT_SLOT(slotMsInfoFetched(bool)) ); connect( m_msInfoFetcher, TQT_SIGNAL(infoMessage(const TQString&, int)), this, TQT_SIGNAL(infoMessage(const TQString&, int)) ); connect( m_msInfoFetcher, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)), this, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)) ); d->imageFinished = true; } K3bDataJob::~K3bDataJob() { delete d->tocFile; delete d; } K3bDoc* K3bDataJob::doc() const { return d->doc; } K3bDevice::Device* K3bDataJob::writer() const { if( doc()->onlyCreateImages() ) return 0; // no writer needed -> no blocking on K3bBurnJob else return doc()->burner(); } void K3bDataJob::start() { jobStarted(); d->canceled = false; d->imageFinished = false; d->copies = d->doc->copies(); d->copiesDone = 0; d->usedMultiSessionMode = d->doc->multiSessionMode(); prepareImager(); if( d->doc->dummy() ) { d->doc->setVerifyData( false ); d->copies = 1; } emit newTask( i18n("Preparing data") ); // there is no harm in setting these even if we write on-the-fly d->imageFile.setName( d->doc->tempDir() ); d->pipe.readFromIODevice( &d->imageFile ); if( d->usedMultiSessionMode == K3bDataDoc::AUTO && !d->doc->onlyCreateImages() ) determineMultiSessionMode(); else prepareWriting(); } void K3bDataJob::prepareWriting() { if( !d->doc->onlyCreateImages() && ( d->usedMultiSessionMode == K3bDataDoc::CONTINUE || d->usedMultiSessionMode == K3bDataDoc::FINISH ) ) { // no sense continuing the same session twice // FIXME: why not? d->copies = 1; m_msInfoFetcher->setDevice( d->doc->burner() ); if( !waitForMedium() ) { cancel(); return; } if( K3b::isMounted( d->doc->burner() ) ) { emit infoMessage( i18n("Unmounting disk"), INFO ); K3b::unmount( d->doc->burner() ); } m_msInfoFetcher->start(); } else { m_isoImager->setMultiSessionInfo( TQString() ); prepareData(); d->initializingImager = true; m_isoImager->init(); } } void K3bDataJob::slotMsInfoFetched(bool success) { if( success ) { // we call this here since in ms mode we might want to check // the last track's datamode prepareData(); if( d->usedWritingApp == K3b::CDRDAO ) // cdrdao seems to write a 150 blocks pregap that is not used by cdrecord m_isoImager->setMultiSessionInfo( TQString("%1,%2").arg(m_msInfoFetcher->lastSessionStart()).arg(m_msInfoFetcher->nextSessionStart()+150), d->doc->burner() ); else m_isoImager->setMultiSessionInfo( m_msInfoFetcher->msInfo(), d->doc->burner() ); d->initializingImager = true; m_isoImager->init(); } else { // the MsInfoFetcher already emitted failure info cancelAll(); jobFinished( false ); } } void K3bDataJob::writeImage() { d->initializingImager = false; emit burning(false); // get image file path if( d->doc->tempDir().isEmpty() ) d->doc->setTempDir( K3b::findUniqueFilePrefix( d->doc->isoOptions().volumeID() ) + ".iso" ); // TODO: check if the image file is part of the project and if so warn the user // and append some number to make the path unique. emit newTask( i18n("Creating image file") ); emit newSubTask( i18n("Track 1 of 1") ); emit infoMessage( i18n("Creating image file in %1").arg(d->doc->tempDir()), INFO ); m_isoImager->writeToImageFile( d->doc->tempDir() ); m_isoImager->start(); } bool K3bDataJob::startOnTheFlyWriting() { if( prepareWriterJob() ) { if( startWriterJob() ) { // try a direct connection between the processes if( m_writerJob->fd() != -1 ) m_isoImager->writeToFd( m_writerJob->fd() ); d->initializingImager = false; m_isoImager->start(); return true; } } return false; } void K3bDataJob::cancel() { emit infoMessage( i18n("Writing canceled."), K3bJob::ERROR ); emit canceled(); if( m_writerJob && m_writerJob->active() ) { // // lets wait for the writer job to finish // and let it finish the job for good. // cancelAll(); } else { // // Just cancel all and return // This is bad design as we should wait for all subjobs to finish // cancelAll(); jobFinished( false ); } } void K3bDataJob::slotIsoImagerPercent( int p ) { if( d->doc->onlyCreateImages() ) { emit subPercent( p ); emit percent( p ); } else if( !d->doc->onTheFly() ) { double totalTasks = d->copies; double tasksDone = d->copiesDone; // =0 when creating an image if( d->doc->verifyData() ) { totalTasks*=2; tasksDone*=2; } if( !d->doc->onTheFly() ) { totalTasks+=1.0; } emit subPercent( p ); emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); } } void K3bDataJob::slotIsoImagerFinished( bool success ) { if( d->initializingImager ) { if( success ) { if( d->doc->onTheFly() && !d->doc->onlyCreateImages() ) { if( !startOnTheFlyWriting() ) { cancelAll(); jobFinished( false ); } } else { writeImage(); } } else { if( m_isoImager->hasBeenCanceled() ) emit canceled(); jobFinished( false ); } } else { // tell the writer that there won't be more data if( d->doc->onTheFly() && m_writerJob ) m_writerJob->closeFd(); if( !d->doc->onTheFly() || d->doc->onlyCreateImages() ) { if( success ) { emit infoMessage( i18n("Image successfully created in %1").arg(d->doc->tempDir()), K3bJob::SUCCESS ); d->imageFinished = true; if( d->doc->onlyCreateImages() ) { jobFinished( true ); } else { if( prepareWriterJob() ) { startWriterJob(); d->pipe.writeToFd( m_writerJob->fd(), true ); d->pipe.open(true); } } } else { if( m_isoImager->hasBeenCanceled() ) emit canceled(); else emit infoMessage( i18n("Error while creating ISO image"), ERROR ); cancelAll(); jobFinished( false ); } } else if( !success ) { // on-the-fly // // In case the imager failed let's make sure the writer does not emit an unusable // error message. // if( m_writerJob && m_writerJob->active() ) m_writerJob->setSourceUnreadable( true ); // there is one special case which we need to handle here: the iso imager might be canceled // FIXME: the iso imager should not be able to cancel itself if( m_isoImager->hasBeenCanceled() && !this->hasBeenCanceled() ) cancel(); } } } bool K3bDataJob::startWriterJob() { if( d->doc->dummy() ) emit newTask( i18n("Simulating") ); else if( d->copies > 1 ) emit newTask( i18n("Writing Copy %1").arg(d->copiesDone+1) ); else emit newTask( i18n("Writing") ); // if we append a new session we asked for an appendable cd already if( d->usedMultiSessionMode == K3bDataDoc::NONE || d->usedMultiSessionMode == K3bDataDoc::START ) { if( !waitForMedium() ) { return false; } } emit burning(true); m_writerJob->start(); return true; } void K3bDataJob::slotWriterJobPercent( int p ) { double totalTasks = d->copies; double tasksDone = d->copiesDone; if( d->doc->verifyData() ) { totalTasks*=2; tasksDone*=2; } if( !d->doc->onTheFly() ) { totalTasks+=1.0; tasksDone+=1.0; } emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); } void K3bDataJob::slotWriterNextTrack( int t, int tt ) { emit newSubTask( i18n("Writing Track %1 of %2").arg(t).arg(tt) ); } void K3bDataJob::slotWriterJobFinished( bool success ) { d->pipe.close(); // // This is a little workaround for the bad cancellation handling in this job // see cancel() // if( d->canceled ) { if( active() ) jobFinished( false ); } if( success ) { // allright // the writerJob should have emited the "simulation/writing successful" signal if( d->doc->verifyData() ) { if( !d->verificationJob ) { d->verificationJob = new K3bVerificationJob( this, this ); connect( d->verificationJob, TQT_SIGNAL(infoMessage(const TQString&, int)), this, TQT_SIGNAL(infoMessage(const TQString&, int)) ); connect( d->verificationJob, TQT_SIGNAL(newTask(const TQString&)), this, TQT_SIGNAL(newSubTask(const TQString&)) ); connect( d->verificationJob, TQT_SIGNAL(newSubTask(const TQString&)), this, TQT_SIGNAL(newSubTask(const TQString&)) ); connect( d->verificationJob, TQT_SIGNAL(percent(int)), this, TQT_SLOT(slotVerificationProgress(int)) ); connect( d->verificationJob, TQT_SIGNAL(percent(int)), this, TQT_SIGNAL(subPercent(int)) ); connect( d->verificationJob, TQT_SIGNAL(finished(bool)), this, TQT_SLOT(slotVerificationFinished(bool)) ); connect( d->verificationJob, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)), this, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)) ); } d->verificationJob->clear(); d->verificationJob->setDevice( d->doc->burner() ); d->verificationJob->setGrownSessionSize( m_isoImager->size() ); d->verificationJob->addTrack( 0, m_isoImager->checksum(), m_isoImager->size() ); emit burning(false); emit newTask( i18n("Verifying written data") ); d->verificationJob->start(); } else { d->copiesDone++; if( d->copiesDone < d->copies ) { K3bDevice::eject( d->doc->burner() ); bool failed = false; if( d->doc->onTheFly() ) failed = !startOnTheFlyWriting(); else failed = !startWriterJob(); if( failed ) { cancel(); } else if( !d->doc->onTheFly() ) { d->pipe.writeToFd( m_writerJob->fd(), true ); d->pipe.open(true); } } else { cleanup(); jobFinished(true); } } } else { cancelAll(); jobFinished( false ); } } void K3bDataJob::slotVerificationProgress( int p ) { double totalTasks = d->copies*2; double tasksDone = d->copiesDone*2 + 1; // the writing of the current copy has already been finished if( !d->doc->onTheFly() ) { totalTasks+=1.0; tasksDone+=1.0; } emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); } void K3bDataJob::slotVerificationFinished( bool success ) { d->copiesDone++; // reconnect our imager which we deconnected for the verification connectImager(); if( k3bcore->globalSettings()->ejectMedia() || d->copiesDone < d->copies ) K3bDevice::eject( d->doc->burner() ); if( !d->canceled && d->copiesDone < d->copies ) { bool failed = false; if( d->doc->onTheFly() ) failed = !startOnTheFlyWriting(); else failed = !startWriterJob(); if( failed ) cancel(); else if( !d->doc->onTheFly() ) { d->pipe.writeToFd( m_writerJob->fd(), true ); d->pipe.open(true); } } else { cleanup(); jobFinished( success ); } } void K3bDataJob::setWriterJob( K3bAbstractWriter* writer ) { // FIXME: progressedsize for multiple copies m_writerJob = writer; connect( m_writerJob, TQT_SIGNAL(infoMessage(const TQString&, int)), this, TQT_SIGNAL(infoMessage(const TQString&, int)) ); connect( m_writerJob, TQT_SIGNAL(percent(int)), this, TQT_SLOT(slotWriterJobPercent(int)) ); connect( m_writerJob, TQT_SIGNAL(processedSize(int, int)), this, TQT_SIGNAL(processedSize(int, int)) ); connect( m_writerJob, TQT_SIGNAL(subPercent(int)), this, TQT_SIGNAL(subPercent(int)) ); connect( m_writerJob, TQT_SIGNAL(processedSubSize(int, int)), this, TQT_SIGNAL(processedSubSize(int, int)) ); connect( m_writerJob, TQT_SIGNAL(nextTrack(int, int)), this, TQT_SLOT(slotWriterNextTrack(int, int)) ); connect( m_writerJob, TQT_SIGNAL(buffer(int)), this, TQT_SIGNAL(bufferStatus(int)) ); connect( m_writerJob, TQT_SIGNAL(deviceBuffer(int)), this, TQT_SIGNAL(deviceBuffer(int)) ); connect( m_writerJob, TQT_SIGNAL(writeSpeed(int, int)), this, TQT_SIGNAL(writeSpeed(int, int)) ); connect( m_writerJob, TQT_SIGNAL(finished(bool)), this, TQT_SLOT(slotWriterJobFinished(bool)) ); connect( m_writerJob, TQT_SIGNAL(newSubTask(const TQString&)), this, TQT_SIGNAL(newSubTask(const TQString&)) ); connect( m_writerJob, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)), this, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)) ); } void K3bDataJob::setImager( K3bIsoImager* imager ) { if( m_isoImager != imager ) { delete m_isoImager; m_isoImager = imager; connectImager(); } } void K3bDataJob::connectImager() { m_isoImager->disconnect( this ); connect( m_isoImager, TQT_SIGNAL(infoMessage(const TQString&, int)), this, TQT_SIGNAL(infoMessage(const TQString&, int)) ); connect( m_isoImager, TQT_SIGNAL(percent(int)), this, TQT_SLOT(slotIsoImagerPercent(int)) ); connect( m_isoImager, TQT_SIGNAL(finished(bool)), this, TQT_SLOT(slotIsoImagerFinished(bool)) ); connect( m_isoImager, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)), this, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)) ); } void K3bDataJob::prepareImager() { if( !m_isoImager ) setImager( new K3bIsoImager( d->doc, this, this ) ); } bool K3bDataJob::prepareWriterJob() { if( m_writerJob ) return true; // It seems as if cdrecord is not able to append sessions in dao mode whereas cdrdao is if( d->usedWritingApp == K3b::CDRECORD ) { K3bCdrecordWriter* writer = new K3bCdrecordWriter( d->doc->burner(), this, this ); // cdrecord manpage says that "not all" writers are able to write // multisession disks in dao mode. That means there are writers that can. // Does it really make sence to write DAta ms cds in DAO mode since writing the // first session of a cd-extra in DAO mode is no problem with my writer while // writing the second data session is only possible in TAO mode. if( d->usedWritingMode == K3b::DAO && d->usedMultiSessionMode != K3bDataDoc::NONE ) emit infoMessage( i18n("Most writers do not support writing " "multisession CDs in DAO mode."), INFO ); writer->setWritingMode( d->usedWritingMode ); writer->setSimulate( d->doc->dummy() ); writer->setBurnSpeed( d->doc->speed() ); // multisession if( d->usedMultiSessionMode == K3bDataDoc::START || d->usedMultiSessionMode == K3bDataDoc::CONTINUE ) { writer->addArgument("-multi"); } if( d->doc->onTheFly() && ( d->usedMultiSessionMode == K3bDataDoc::CONTINUE || d->usedMultiSessionMode == K3bDataDoc::FINISH ) ) writer->addArgument("-waiti"); if( d->usedDataMode == K3b::MODE1 ) writer->addArgument( "-data" ); else { if( k3bcore->externalBinManager()->binObject("cdrecord") && k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "xamix" ) ) writer->addArgument( "-xa" ); else writer->addArgument( "-xa1" ); } writer->addArgument( TQString("-tsize=%1s").arg(m_isoImager->size()) )->addArgument("-"); setWriterJob( writer ); } else { // create cdrdao job K3bCdrdaoWriter* writer = new K3bCdrdaoWriter( d->doc->burner(), this, this ); writer->setCommand( K3bCdrdaoWriter::WRITE ); writer->setSimulate( d->doc->dummy() ); writer->setBurnSpeed( d->doc->speed() ); // multisession writer->setMulti( d->usedMultiSessionMode == K3bDataDoc::START || d->usedMultiSessionMode == K3bDataDoc::CONTINUE ); // now write the tocfile if( d->tocFile ) delete d->tocFile; d->tocFile = new KTempFile( TQString(), "toc" ); d->tocFile->setAutoDelete(true); if( TQTextStream* s = d->tocFile->textStream() ) { if( d->usedDataMode == K3b::MODE1 ) { *s << "CD_ROM" << "\n"; *s << "\n"; *s << "TRACK MODE1" << "\n"; } else { *s << "CD_ROM_XA" << "\n"; *s << "\n"; *s << "TRACK MODE2_FORM1" << "\n"; } *s << "DATAFILE \"-\" " << m_isoImager->size()*2048 << "\n"; d->tocFile->close(); } else { kdDebug() << "(K3bDataJob) could not write tocfile." << endl; emit infoMessage( i18n("IO Error"), ERROR ); cancelAll(); return false; } writer->setTocFile( d->tocFile->name() ); setWriterJob( writer ); } return true; } void K3bDataJob::prepareData() { // we don't need this when only creating image and it is possible // that the burn device is null if( d->doc->onlyCreateImages() ) return; // first of all we determine the data mode if( d->doc->dataMode() == K3b::DATA_MODE_AUTO ) { if( !d->doc->onlyCreateImages() && ( d->usedMultiSessionMode == K3bDataDoc::CONTINUE || d->usedMultiSessionMode == K3bDataDoc::FINISH ) ) { // try to get the last track's datamode // we already asked for an appendable cdr when fetching // the ms info kdDebug() << "(K3bDataJob) determining last track's datamode..." << endl; // FIXME: use a devicethread K3bDevice::Toc toc = d->doc->burner()->readToc(); if( toc.isEmpty() ) { kdDebug() << "(K3bDataJob) could not retrieve toc." << endl; emit infoMessage( i18n("Unable to determine the last track's datamode. Using default."), ERROR ); d->usedDataMode = K3b::MODE2; } else { if( toc[toc.count()-1].mode() == K3bDevice::Track::MODE1 ) d->usedDataMode = K3b::MODE1; else d->usedDataMode = K3b::MODE2; kdDebug() << "(K3bDataJob) using datamode: " << (d->usedDataMode == K3b::MODE1 ? "mode1" : "mode2") << endl; } } else if( d->usedMultiSessionMode == K3bDataDoc::NONE ) d->usedDataMode = K3b::MODE1; else d->usedDataMode = K3b::MODE2; } else d->usedDataMode = d->doc->dataMode(); // determine the writing mode if( d->doc->writingMode() == K3b::WRITING_MODE_AUTO ) { // TODO: put this into the cdreocrdwriter and decide based on the size of the // track if( writer()->dao() && d->usedDataMode == K3b::MODE1 && d->usedMultiSessionMode == K3bDataDoc::NONE ) d->usedWritingMode = K3b::DAO; else d->usedWritingMode = K3b::TAO; } else d->usedWritingMode = d->doc->writingMode(); // cdrecord seems to have problems writing xa 1 disks in dao mode? At least on my system! if( writingApp() == K3b::DEFAULT ) { if( d->usedWritingMode == K3b::DAO ) { if( d->usedMultiSessionMode != K3bDataDoc::NONE ) d->usedWritingApp = K3b::CDRDAO; else if( d->usedDataMode == K3b::MODE2 ) d->usedWritingApp = K3b::CDRDAO; else d->usedWritingApp = K3b::CDRECORD; } else d->usedWritingApp = K3b::CDRECORD; } else d->usedWritingApp = writingApp(); } void K3bDataJob::determineMultiSessionMode() { // // THIS IS ONLY CALLED IF d->doc->multiSessionMode() == K3bDataDoc::AUTO! // if( d->doc->writingMode() == K3b::WRITING_MODE_AUTO || d->doc->writingMode() == K3b::TAO ) { emit newSubTask( i18n("Searching for old session") ); // // Wait for the medium. // In case an old session was imported we always want to continue or finish a multisession CD/DVD. // Otherwise we wait for everything we could handle and decide what to do in // determineMultiSessionMode( K3bDevice::DeviceHandler* ) below. // int wantedMediaState = K3bDevice::STATE_INCOMPLETE|K3bDevice::STATE_EMPTY; if( d->doc->sessionImported() ) wantedMediaState = K3bDevice::STATE_INCOMPLETE; int m = waitForMedia( d->doc->burner(), wantedMediaState, K3bDevice::MEDIA_WRITABLE_CD ); if( m < 0 ) cancel(); else { // now we need to determine the media's size connect( K3bDevice::sendCommand( K3bDevice::DeviceHandler::NG_DISKINFO, d->doc->burner() ), TQT_SIGNAL(finished(K3bDevice::DeviceHandler*)), this, TQT_SLOT(slotDetermineMultiSessionMode(K3bDevice::DeviceHandler*)) ); } } else { // we need TAO for multisession d->usedMultiSessionMode = K3bDataDoc::NONE; // carry on with the writing prepareWriting(); } } void K3bDataJob::slotDetermineMultiSessionMode( K3bDevice::DeviceHandler* dh ) { // // This is a little workaround for the bad cancellation handling in this job // see cancel() // if( d->canceled ) { if( active() ) { cleanup(); jobFinished( false ); } } else { d->usedMultiSessionMode = getMultiSessionMode( dh->diskInfo() ); // carry on with the writing prepareWriting(); } } K3bDataDoc::MultiSessionMode K3bDataJob::getMultiSessionMode( const K3bDevice::DiskInfo& info ) { if( info.appendable() ) { // // 3 cases: // 1. the project does not fit -> no multisession (resulting in asking for another media above) // 2. the project does fit and fills up the CD -> finish multisession // 3. the project does fit and does not fill up the CD -> continue multisession // // In case a session has been imported we do not consider NONE at all. // if( d->doc->size() > info.remainingSize().mode1Bytes() && !d->doc->sessionImported() ) d->usedMultiSessionMode = K3bDataDoc::NONE; else if( d->doc->size() >= info.remainingSize().mode1Bytes()*9/10 ) d->usedMultiSessionMode = K3bDataDoc::FINISH; else d->usedMultiSessionMode = K3bDataDoc::CONTINUE; } else if( info.empty() ) { // // We only close the CD if the project fills up the CD almost completely (90%) // if( d->doc->size() >= info.capacity().mode1Bytes()*9/10 || d->doc->writingMode() == K3b::DAO ) d->usedMultiSessionMode = K3bDataDoc::NONE; else d->usedMultiSessionMode = K3bDataDoc::START; } else { // complete (WE SHOULD ACTUALLY NEVER GET HERE SINCE WE WAIT FOR AN EMPTY/APPENDABLE CD ABOVE!) // // Now we decide only based on the project size. // let's just use a 680 MB CD as our reference // if( d->doc->size()/1024/1024 >= 680*9/10 || d->doc->writingMode() == K3b::DAO ) d->usedMultiSessionMode = K3bDataDoc::NONE; else d->usedMultiSessionMode = K3bDataDoc::START; } return d->usedMultiSessionMode; } void K3bDataJob::cancelAll() { d->canceled = true; m_isoImager->cancel(); m_msInfoFetcher->cancel(); if( m_writerJob ) m_writerJob->cancel(); if( d->verificationJob ) d->verificationJob->cancel(); d->pipe.close(); cleanup(); } bool K3bDataJob::waitForMedium() { emit newSubTask( i18n("Waiting for a medium") ); if( waitForMedia( d->doc->burner(), d->usedMultiSessionMode == K3bDataDoc::CONTINUE || d->usedMultiSessionMode == K3bDataDoc::FINISH ? K3bDevice::STATE_INCOMPLETE : K3bDevice::STATE_EMPTY, K3bDevice::MEDIA_WRITABLE_CD ) < 0 ) { return false; } else return !d->canceled; } TQString K3bDataJob::jobDescription() const { if( d->doc->onlyCreateImages() ) { return i18n("Creating Data Image File"); } else if( d->doc->multiSessionMode() == K3bDataDoc::NONE || d->doc->multiSessionMode() == K3bDataDoc::AUTO ) { return i18n("Writing Data CD") + ( d->doc->isoOptions().volumeID().isEmpty() ? TQString() : TQString( " (%1)" ).arg(d->doc->isoOptions().volumeID()) ); } else { return i18n("Writing Multisession CD") + ( d->doc->isoOptions().volumeID().isEmpty() ? TQString() : TQString( " (%1)" ).arg(d->doc->isoOptions().volumeID()) ); } } TQString K3bDataJob::jobDetails() const { if( d->doc->copies() > 1 && !d->doc->dummy() && !(d->doc->multiSessionMode() == K3bDataDoc::CONTINUE || d->doc->multiSessionMode() == K3bDataDoc::FINISH) ) return i18n("ISO9660 Filesystem (Size: %1) - %n copy", "ISO9660 Filesystem (Size: %1) - %n copies", d->doc->copies() ) .arg(KIO::convertSize( d->doc->size() )); else return i18n("ISO9660 Filesystem (Size: %1)") .arg(KIO::convertSize( d->doc->size() )); } K3bDataDoc::MultiSessionMode K3bDataJob::usedMultiSessionMode() const { return d->usedMultiSessionMode; } void K3bDataJob::cleanup() { if( !d->doc->onTheFly() && d->doc->removeImages() ) { if( TQFile::exists( d->doc->tempDir() ) ) { d->imageFile.remove(); emit infoMessage( i18n("Removed image file %1").arg(d->doc->tempDir()), K3bJob::SUCCESS ); } } if( d->tocFile ) { delete d->tocFile; d->tocFile = 0; } } bool K3bDataJob::hasBeenCanceled() const { return d->canceled; } #include "k3bdatajob.moc"