File indexing completed on 2024-10-06 04:26:02
0001 /* 0002 SPDX-FileCopyrightText: 1998-2007 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "k3bprojectmanager.h" 0007 0008 #include <config-k3b.h> 0009 #include "k3bapplication.h" 0010 #include "k3binteractiondialog.h" 0011 #include "k3baudiodoc.h" 0012 #include "k3baudiodatasourceiterator.h" 0013 #include "k3baudiocdtracksource.h" 0014 #include "k3baudioprojectinterface.h" 0015 #include "k3bdatadoc.h" 0016 #include "k3bdataprojectinterface.h" 0017 #include "k3bvideodvddoc.h" 0018 #include "k3bmixeddoc.h" 0019 #include "k3bmixedprojectinterface.h" 0020 #include "k3bvcddoc.h" 0021 #include "k3bmovixdoc.h" 0022 #include "k3bglobals.h" 0023 #include "k3bisooptions.h" 0024 #include "k3bdevicemanager.h" 0025 #include "k3bprojectinterface.h" 0026 #include <KoStore.h> 0027 #include <KoStoreDevice.h> 0028 0029 #include <KConfig> 0030 #include <KSharedConfig> 0031 #include <KLocalizedString> 0032 #include <KIO/StoredTransferJob> 0033 #include <KIO/FileCopyJob> 0034 #include <KMessageBox> 0035 0036 #include <QDebug> 0037 #include <QFile> 0038 #include <QHash> 0039 #include <QList> 0040 #include <QTemporaryFile> 0041 #include <QTextStream> 0042 #include <QUrl> 0043 #include <QDomDocument> 0044 #include <QDomElement> 0045 #include <QCursor> 0046 #include <QApplication> 0047 0048 namespace 0049 { 0050 typedef QHash<K3b::Doc*, K3b::ProjectInterface*> ProjectInterfaces; 0051 0052 K3b::ProjectInterface* createProjectInterface( K3b::Doc* doc ) 0053 { 0054 if( K3b::AudioDoc* audioDoc = dynamic_cast<K3b::AudioDoc*>( doc ) ) 0055 return new K3b::AudioProjectInterface( audioDoc ); 0056 else if( K3b::DataDoc* dataDoc = dynamic_cast<K3b::DataDoc*>( doc ) ) 0057 return new K3b::DataProjectInterface( dataDoc ); 0058 else if( K3b::MixedDoc* mixedDoc = dynamic_cast<K3b::MixedDoc*>( doc ) ) 0059 return new K3b::MixedProjectInterface( mixedDoc ); 0060 else 0061 return new K3b::ProjectInterface( doc ); 0062 } 0063 } 0064 0065 class K3b::ProjectManager::Private 0066 { 0067 public: 0068 QList<Doc*> projects; 0069 Doc* activeProject; 0070 ProjectInterfaces projectInterfaces; 0071 0072 int audioUntitledCount; 0073 int dataUntitledCount; 0074 int mixedUntitledCount; 0075 int vcdUntitledCount; 0076 int movixUntitledCount; 0077 int videoDvdUntitledCount; 0078 }; 0079 0080 0081 0082 0083 K3b::ProjectManager::ProjectManager( QObject* parent ) 0084 : QObject( parent ) 0085 { 0086 d = new Private(); 0087 d->activeProject = 0; 0088 0089 d->audioUntitledCount = 0; 0090 d->dataUntitledCount = 0; 0091 d->mixedUntitledCount = 0; 0092 d->vcdUntitledCount = 0; 0093 d->movixUntitledCount = 0; 0094 d->videoDvdUntitledCount = 0; 0095 } 0096 0097 K3b::ProjectManager::~ProjectManager() 0098 { 0099 delete d; 0100 } 0101 0102 0103 QList<K3b::Doc*> K3b::ProjectManager::projects() const 0104 { 0105 return d->projects; 0106 } 0107 0108 0109 void K3b::ProjectManager::addProject( K3b::Doc* doc ) 0110 { 0111 qDebug() << doc; 0112 0113 if( !d->projects.contains( doc ) ) { 0114 qDebug() << "adding doc " << doc->URL().toLocalFile(); 0115 0116 d->projects.append( doc ); 0117 d->projectInterfaces.insert( doc, createProjectInterface( doc ) ); 0118 0119 connect( doc, SIGNAL(changed(K3b::Doc*)), 0120 this, SLOT(slotProjectChanged(K3b::Doc*)) ); 0121 0122 emit newProject( doc ); 0123 } 0124 } 0125 0126 0127 void K3b::ProjectManager::removeProject( K3b::Doc* docRemove ) 0128 { 0129 // 0130 // QPtrList.findRef seems to be buggy. Every time we search for the 0131 // first added item it is not found! 0132 // 0133 Q_FOREACH( K3b::Doc* doc, d->projects ) { 0134 if( docRemove == doc ) { 0135 ProjectInterfaces::iterator interface = d->projectInterfaces.find( doc ); 0136 if( interface != d->projectInterfaces.end() ) { 0137 delete interface.value(); 0138 d->projectInterfaces.erase( interface ); 0139 } 0140 d->projects.removeAll(doc); 0141 emit closingProject(doc); 0142 0143 return; 0144 } 0145 } 0146 qDebug() << "(K3b::ProjectManager) unable to find doc: " << docRemove->URL().toLocalFile(); 0147 } 0148 0149 0150 K3b::Doc* K3b::ProjectManager::findByUrl( const QUrl& url ) 0151 { 0152 Q_FOREACH( K3b::Doc* doc, d->projects ) { 0153 if( doc->URL() == url ) 0154 return doc; 0155 } 0156 return 0; 0157 } 0158 0159 0160 bool K3b::ProjectManager::isEmpty() const 0161 { 0162 return d->projects.isEmpty(); 0163 } 0164 0165 0166 void K3b::ProjectManager::setActive( K3b::Doc* docActive ) 0167 { 0168 if( !docActive ) { 0169 d->activeProject = 0L; 0170 emit activeProjectChanged( 0L ); 0171 return; 0172 } 0173 0174 // 0175 // QPtrList.findRef seems to be buggy. Every time we search for the 0176 // first added item it is not found! 0177 // 0178 Q_FOREACH( K3b::Doc* doc, d->projects ) { 0179 if( docActive == doc ) { 0180 d->activeProject = doc; 0181 emit activeProjectChanged(doc); 0182 } 0183 } 0184 } 0185 0186 0187 K3b::Doc* K3b::ProjectManager::activeProject() const 0188 { 0189 return d->activeProject; 0190 } 0191 0192 0193 K3b::Doc* K3b::ProjectManager::createEmptyProject( K3b::Doc::Type type ) 0194 { 0195 qDebug() << type; 0196 0197 K3b::Doc* doc = 0; 0198 QString fileName; 0199 0200 switch( type ) { 0201 case K3b::Doc::AudioProject: { 0202 doc = new K3b::AudioDoc( this ); 0203 fileName = i18n("AudioCD%1",d->audioUntitledCount++); 0204 break; 0205 } 0206 0207 case K3b::Doc::DataProject: { 0208 doc = new K3b::DataDoc( this ); 0209 fileName = i18n("Data%1",d->dataUntitledCount++); 0210 break; 0211 } 0212 0213 case K3b::Doc::MixedProject: { 0214 doc = new K3b::MixedDoc( this ); 0215 fileName=i18n("MixedCD%1",d->mixedUntitledCount++); 0216 break; 0217 } 0218 0219 case K3b::Doc::VcdProject: { 0220 doc = new K3b::VcdDoc( this ); 0221 fileName=i18n("VideoCD%1",d->vcdUntitledCount++); 0222 break; 0223 } 0224 0225 case K3b::Doc::MovixProject: { 0226 doc = new K3b::MovixDoc( this ); 0227 fileName=i18n("eMovix%1",d->movixUntitledCount++); 0228 break; 0229 } 0230 0231 #ifdef ENABLE_DVD_RIPPING 0232 case K3b::Doc::VideoDvdProject: { 0233 doc = new K3b::VideoDvdDoc( this ); 0234 fileName = i18n("VideoDVD%1",d->videoDvdUntitledCount++); 0235 break; 0236 } 0237 #endif 0238 } 0239 0240 doc->setURL(QUrl::fromLocalFile(fileName)); 0241 0242 doc->newDocument(); 0243 0244 loadDefaults( doc ); 0245 0246 return doc; 0247 } 0248 0249 0250 K3b::Doc* K3b::ProjectManager::createProject( K3b::Doc::Type type ) 0251 { 0252 qDebug() << type; 0253 0254 K3b::Doc* doc = createEmptyProject( type ); 0255 0256 addProject( doc ); 0257 0258 return doc; 0259 } 0260 0261 0262 void K3b::ProjectManager::loadDefaults( K3b::Doc* doc ) 0263 { 0264 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0265 0266 QString cg = "default " + doc->typeString() + " settings"; 0267 0268 // earlier K3b versions loaded the saved settings 0269 // so that is what we do as a default 0270 int i = KConfigGroup( config, QStringLiteral("General Options") ).readEntry( "action dialog startup settings", 0271 int(K3b::InteractionDialog::LOAD_SAVED_SETTINGS) ); 0272 if( i == K3b::InteractionDialog::LOAD_K3B_DEFAULTS ) 0273 return; // the default k3b settings are the ones everyone starts with 0274 else if( i == K3b::InteractionDialog::LOAD_LAST_SETTINGS ) 0275 cg = "last used " + cg; 0276 KConfigGroup c(config,cg); 0277 0278 QString mode = c.readEntry( "writing_mode" ); 0279 if ( mode == "dao" ) 0280 doc->setWritingMode( K3b::WritingModeSao ); 0281 else if( mode == "tao" ) 0282 doc->setWritingMode( K3b::WritingModeTao ); 0283 else if( mode == "raw" ) 0284 doc->setWritingMode( K3b::WritingModeRaw ); 0285 else 0286 doc->setWritingMode( K3b::WritingModeAuto ); 0287 0288 doc->setDummy( c.readEntry( "simulate", false ) ); 0289 doc->setOnTheFly( c.readEntry( "on_the_fly", true ) ); 0290 doc->setRemoveImages( c.readEntry( "remove_image", true ) ); 0291 doc->setOnlyCreateImages( c.readEntry( "only_create_image", false ) ); 0292 doc->setBurner( k3bcore->deviceManager()->findDevice( c.readEntry( "writer_device" ) ) ); 0293 // Default = 0 (Auto) 0294 doc->setSpeed( c.readEntry( "writing_speed", 0 ) ); 0295 doc->setWritingApp( K3b::writingAppFromString( c.readEntry( "writing_app" ) ) ); 0296 0297 0298 switch( doc->type() ) { 0299 case K3b::Doc::AudioProject: { 0300 K3b::AudioDoc* audioDoc = static_cast<K3b::AudioDoc*>(doc); 0301 0302 audioDoc->writeCdText( c.readEntry( "cd_text", true ) ); 0303 audioDoc->setHideFirstTrack( c.readEntry( "hide_first_track", false ) ); 0304 audioDoc->setNormalize( c.readEntry( "normalize", false ) ); 0305 audioDoc->setAudioRippingParanoiaMode( c.readEntry( "paranoia mode", 0 ) ); 0306 audioDoc->setAudioRippingRetries( c.readEntry( "read retries", 128 ) ); 0307 audioDoc->setAudioRippingIgnoreReadErrors( c.readEntry( "ignore read errors", false ) ); 0308 0309 break; 0310 } 0311 0312 case K3b::Doc::MovixProject: { 0313 K3b::MovixDoc* movixDoc = static_cast<K3b::MovixDoc*>(doc); 0314 0315 movixDoc->setSubtitleFontset( c.readEntry("subtitle_fontset") ); 0316 0317 movixDoc->setLoopPlaylist( c.readEntry("loop", 1 ) ); 0318 movixDoc->setAdditionalMPlayerOptions( c.readEntry( "additional_mplayer_options" ) ); 0319 movixDoc->setUnwantedMPlayerOptions( c.readEntry( "unwanted_mplayer_options" ) ); 0320 0321 movixDoc->setBootMessageLanguage( c.readEntry("boot_message_language") ); 0322 0323 movixDoc->setDefaultBootLabel( c.readEntry( "default_boot_label" ) ); 0324 0325 movixDoc->setShutdown( c.readEntry( "shutdown", false) ); 0326 movixDoc->setReboot( c.readEntry( "reboot", false ) ); 0327 movixDoc->setEjectDisk( c.readEntry( "eject", false ) ); 0328 movixDoc->setRandomPlay( c.readEntry( "random_play", false ) ); 0329 movixDoc->setNoDma( c.readEntry( "no_dma", false ) ); 0330 0331 Q_FALLTHROUGH(); 0332 } 0333 0334 case K3b::Doc::DataProject: { 0335 K3b::DataDoc* dataDoc = static_cast<K3b::DataDoc*>(doc); 0336 0337 dataDoc->setIsoOptions( K3b::IsoOptions::load( c, false ) ); 0338 0339 QString datamode = c.readEntry( "data_track_mode" ); 0340 if( datamode == "mode1" ) 0341 dataDoc->setDataMode( K3b::DataMode1 ); 0342 else if( datamode == "mode2" ) 0343 dataDoc->setDataMode( K3b::DataMode2 ); 0344 else 0345 dataDoc->setDataMode( K3b::DataModeAuto ); 0346 0347 dataDoc->setVerifyData( c.readEntry( "verify data", false ) ); 0348 0349 QString s = c.readEntry( "multisession mode" ); 0350 if( s == "none" ) 0351 dataDoc->setMultiSessionMode( K3b::DataDoc::NONE ); 0352 else if( s == "start" ) 0353 dataDoc->setMultiSessionMode( K3b::DataDoc::START ); 0354 else if( s == "continue" ) 0355 dataDoc->setMultiSessionMode( K3b::DataDoc::CONTINUE ); 0356 else if( s == "finish" ) 0357 dataDoc->setMultiSessionMode( K3b::DataDoc::FINISH ); 0358 else 0359 dataDoc->setMultiSessionMode( K3b::DataDoc::AUTO ); 0360 0361 break; 0362 } 0363 0364 case K3b::Doc::VideoDvdProject: { 0365 // the only defaults we need here are the volume id and stuff 0366 K3b::DataDoc* dataDoc = static_cast<K3b::DataDoc*>(doc); 0367 dataDoc->setIsoOptions( K3b::IsoOptions::load( c, false ) ); 0368 dataDoc->setVerifyData( c.readEntry( "verify data", false ) ); 0369 break; 0370 } 0371 0372 case K3b::Doc::MixedProject: { 0373 K3b::MixedDoc* mixedDoc = static_cast<K3b::MixedDoc*>(doc); 0374 0375 mixedDoc->audioDoc()->writeCdText( c.readEntry( "cd_text", true ) ); 0376 mixedDoc->audioDoc()->setNormalize( c.readEntry( "normalize", false ) ); 0377 0378 // load mixed type 0379 if( c.readEntry( "mixed_type" ) == "last_track" ) 0380 mixedDoc->setMixedType( K3b::MixedDoc::DATA_LAST_TRACK ); 0381 else if( c.readEntry( "mixed_type" ) == "first_track" ) 0382 mixedDoc->setMixedType( K3b::MixedDoc::DATA_FIRST_TRACK ); 0383 else 0384 mixedDoc->setMixedType( K3b::MixedDoc::DATA_SECOND_SESSION ); 0385 0386 QString datamode = c.readEntry( "data_track_mode" ); 0387 if( datamode == "mode1" ) 0388 mixedDoc->dataDoc()->setDataMode( K3b::DataMode1 ); 0389 else if( datamode == "mode2" ) 0390 mixedDoc->dataDoc()->setDataMode( K3b::DataMode2 ); 0391 else 0392 mixedDoc->dataDoc()->setDataMode( K3b::DataModeAuto ); 0393 0394 mixedDoc->dataDoc()->setIsoOptions( K3b::IsoOptions::load( c, false ) ); 0395 0396 if( mixedDoc->dataDoc()->isoOptions().volumeID().isEmpty() ) 0397 mixedDoc->dataDoc()->setVolumeID( doc->URL().fileName() ); 0398 0399 break; 0400 } 0401 0402 case K3b::Doc::VcdProject: { 0403 K3b::VcdDoc* vcdDoc = static_cast<K3b::VcdDoc*>(doc); 0404 0405 // FIXME: I think we miss a lot here! 0406 0407 vcdDoc->vcdOptions()->setPbcEnabled( c.readEntry( "Use Playback Control", false ) ); 0408 vcdDoc->vcdOptions()->setPbcNumkeysEnabled( c.readEntry( "Use numeric keys to navigate chapters", false ) ); 0409 vcdDoc->vcdOptions()->setPbcPlayTime( c.readEntry( "Play each Sequence/Segment", 1 ) ); 0410 vcdDoc->vcdOptions()->setPbcWaitTime( c.readEntry( "Time to wait after each Sequence/Segment", 2 ) ); 0411 0412 if( vcdDoc->vcdOptions()->volumeId().isEmpty() ) 0413 vcdDoc->vcdOptions()->setVolumeId( doc->URL().fileName() ); 0414 0415 break; 0416 } 0417 } 0418 0419 if( doc->type() == K3b::Doc::DataProject || 0420 doc->type() == K3b::Doc::MovixProject || 0421 doc->type() == K3b::Doc::VideoDvdProject ) { 0422 if( static_cast<K3b::DataDoc*>(doc)->isoOptions().volumeID().isEmpty() ) 0423 static_cast<K3b::DataDoc*>(doc)->setVolumeID( doc->URL().fileName() ); 0424 } 0425 0426 doc->setModified( false ); 0427 } 0428 0429 0430 QString K3b::ProjectManager::dbusPath( K3b::Doc* doc ) const 0431 { 0432 ProjectInterfaces::const_iterator it = d->projectInterfaces.constFind( doc ); 0433 if( it != d->projectInterfaces.constEnd() ) 0434 return it.value()->dbusPath(); 0435 else 0436 return QString(); 0437 } 0438 0439 0440 K3b::Doc* K3b::ProjectManager::openProject( const QUrl& url ) 0441 { 0442 QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); 0443 0444 QTemporaryFile tmpfile; 0445 tmpfile.setAutoRemove(false); 0446 KIO::StoredTransferJob* transferJob = KIO::storedGet( url ); 0447 if (!transferJob->exec()) 0448 return NULL; 0449 tmpfile.open(); 0450 tmpfile.write(transferJob->data()); 0451 tmpfile.close(); 0452 0453 // /////////////////////////////////////////////// 0454 // first check if it's a store or an old plain xml file 0455 bool success = false; 0456 QDomDocument xmlDoc; 0457 0458 // try opening a store 0459 KoStore* store = KoStore::createStore( tmpfile.fileName(), KoStore::Read ); 0460 if( store ) { 0461 if( !store->bad() ) { 0462 // try opening the document inside the store 0463 if( store->open( "maindata.xml" ) ) { 0464 QIODevice* dev = store->device(); 0465 dev->open( QIODevice::ReadOnly ); 0466 if( xmlDoc.setContent( dev ) ) 0467 success = true; 0468 dev->close(); 0469 store->close(); 0470 } 0471 } 0472 0473 delete store; 0474 } 0475 0476 if( !success ) { 0477 // try reading an old plain document 0478 tmpfile.remove(); 0479 if ( tmpfile.open() ) { 0480 // 0481 // First check if this is really an xml file because if this is a very big file 0482 // the setContent method blocks for a very long time 0483 // 0484 char test[5]; 0485 if( tmpfile.read( test, 5 ) ) { 0486 if( ::strncmp( test, "<?xml", 5 ) ) { 0487 qDebug() << "(K3b::Doc) " << url.toLocalFile() << " seems to be no xml file."; 0488 QApplication::restoreOverrideCursor(); 0489 return 0; 0490 } 0491 tmpfile.reset(); 0492 } 0493 else { 0494 qDebug() << "(K3b::Doc) could not read from file."; 0495 QApplication::restoreOverrideCursor(); 0496 return 0; 0497 } 0498 if( xmlDoc.setContent( &tmpfile ) ) 0499 success = true; 0500 tmpfile.remove(); 0501 } 0502 } 0503 0504 // /////////////////////////////////////////////// 0505 if( !success ) { 0506 qDebug() << "(K3b::Doc) could not open file " << url.toLocalFile(); 0507 QApplication::restoreOverrideCursor(); 0508 return 0; 0509 } 0510 0511 // check the documents DOCTYPE 0512 K3b::Doc::Type type = K3b::Doc::AudioProject; 0513 if( xmlDoc.doctype().name() == "k3b_audio_project" ) 0514 type = K3b::Doc::AudioProject; 0515 else if( xmlDoc.doctype().name() == "k3b_data_project" ) 0516 type = K3b::Doc::DataProject; 0517 else if( xmlDoc.doctype().name() == "k3b_vcd_project" ) 0518 type = K3b::Doc::VcdProject; 0519 else if( xmlDoc.doctype().name() == "k3b_mixed_project" ) 0520 type = K3b::Doc::MixedProject; 0521 else if( xmlDoc.doctype().name() == "k3b_movix_project" ) 0522 type = K3b::Doc::MovixProject; 0523 else if( xmlDoc.doctype().name() == "k3b_movixdvd_project" ) 0524 type = K3b::Doc::MovixProject; // backward compatibility 0525 else if( xmlDoc.doctype().name() == "k3b_dvd_project" ) 0526 type = K3b::Doc::DataProject; // backward compatibility 0527 else if( xmlDoc.doctype().name() == "k3b_video_dvd_project" ) { 0528 type = K3b::Doc::VideoDvdProject; 0529 } else { 0530 qDebug() << "(K3b::Doc) unknown doc type: " << xmlDoc.doctype().name(); 0531 QApplication::restoreOverrideCursor(); 0532 return 0; 0533 } 0534 0535 // we do not know yet if we will be able to actually open the project, so don't inform others yet 0536 K3b::Doc* newDoc = createEmptyProject( type ); 0537 0538 // --------- 0539 // load the data into the document 0540 QDomElement root = xmlDoc.documentElement(); 0541 if( newDoc->loadDocumentData( &root ) ) { 0542 newDoc->setURL( url ); 0543 newDoc->setSaved( true ); 0544 newDoc->setModified( false ); 0545 0546 // ok, finish the doc setup, inform the others about the new project 0547 //dcopInterface( newDoc ); 0548 addProject( newDoc ); 0549 0550 // FIXME: find a better way to tell everyone (especially the projecttabwidget) 0551 // that the doc is not changed 0552 emit projectSaved( newDoc ); 0553 0554 qDebug() << "(K3b::ProjectManager) loading project done."; 0555 } 0556 else { 0557 delete newDoc; 0558 newDoc = 0; 0559 } 0560 0561 QApplication::restoreOverrideCursor(); 0562 0563 return newDoc; 0564 } 0565 0566 0567 bool K3b::ProjectManager::saveProject( K3b::Doc* doc, const QUrl& url ) 0568 { 0569 QTemporaryFile tmpfile; 0570 tmpfile.setAutoRemove(false); 0571 tmpfile.open(); 0572 0573 bool success = false; 0574 0575 // create the store 0576 KoStore* store = KoStore::createStore( tmpfile.fileName(), KoStore::Write, "application/x-k3b" ); 0577 if( store ) { 0578 if( store->bad() ) { 0579 delete store; 0580 } 0581 else { 0582 // open the document inside the store 0583 store->open( "maindata.xml" ); 0584 0585 // save the data in the document 0586 QDomDocument xmlDoc( "k3b_" + doc->typeString() + "_project" ); 0587 0588 xmlDoc.appendChild( xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); 0589 QDomElement docElem = xmlDoc.createElement( "k3b_" + doc->typeString() + "_project" ); 0590 xmlDoc.appendChild( docElem ); 0591 success = doc->saveDocumentData( &docElem ); 0592 if( success ) { 0593 KoStoreDevice dev(store); 0594 dev.open( QIODevice::WriteOnly ); 0595 QTextStream xmlStream( &dev ); 0596 xmlDoc.save( xmlStream, 0 ); 0597 0598 doc->setURL( url ); 0599 doc->setModified( false ); 0600 } 0601 0602 // close the document inside the store 0603 store->close(); 0604 0605 // remove the store (destructor writes the store to disk) 0606 delete store; 0607 0608 doc->setSaved( success ); 0609 0610 if( success ) { 0611 emit projectSaved( doc ); 0612 } 0613 } 0614 } 0615 KIO::FileCopyJob *copyJob = KIO::file_move(QUrl::fromLocalFile(tmpfile.fileName()), url, -1, KIO::Overwrite); 0616 copyJob->exec(); 0617 0618 return success; 0619 } 0620 0621 0622 void K3b::ProjectManager::slotProjectChanged( K3b::Doc* doc ) 0623 { 0624 emit projectChanged( doc ); 0625 } 0626 0627 #include "moc_k3bprojectmanager.cpp"