File indexing completed on 2024-05-05 04:51:44
0001 /* 0002 SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl> 0003 SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org> 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "k3bdataurladdingdialog.h" 0008 #include "k3bencodingconverter.h" 0009 0010 #include "k3bdatadoc.h" 0011 #include "k3bdiritem.h" 0012 #include "k3bcore.h" 0013 #include "k3bfileitem.h" 0014 #include "k3bmultichoicedialog.h" 0015 #include "k3bvalidators.h" 0016 #include "k3bglobals.h" 0017 #include "k3bisooptions.h" 0018 #include "k3b.h" 0019 #include "k3bapplication.h" 0020 #include "k3biso9660.h" 0021 #include "k3bdirsizejob.h" 0022 #include "k3binteractiondialog.h" 0023 #include "k3bthread.h" 0024 #include "k3bsignalwaiter.h" 0025 #include "k3bexternalbinmanager.h" 0026 0027 #include <KConfig> 0028 #include <KSqueezedTextLabel> 0029 #include <KIconLoader> 0030 #include <KLocalizedString> 0031 #include <KMessageBox> 0032 #include <KStandardGuiItem> 0033 #include <kio/listjob.h> 0034 0035 #include <QDir> 0036 #include <QFileInfo> 0037 #include <QList> 0038 #include <QUrl> 0039 #include <QDialogButtonBox> 0040 #include <QGridLayout> 0041 #include <QProgressBar> 0042 #include <QLabel> 0043 #include <QLayout> 0044 #include <QInputDialog> 0045 0046 #include <unistd.h> 0047 0048 0049 K3b::DataUrlAddingDialog::DataUrlAddingDialog( const QList<QUrl>& urls, DirItem* dir, QWidget* parent ) 0050 : DataUrlAddingDialog( dir, parent ) 0051 { 0052 m_urls = urls; 0053 for( QList<QUrl>::ConstIterator it = urls.begin(); it != urls.end(); ++it ) 0054 m_urlQueue.append( qMakePair( K3b::convertToLocalUrl(*it), dir ) ); 0055 } 0056 0057 0058 K3b::DataUrlAddingDialog::DataUrlAddingDialog( const QList<DataItem*>& items, DirItem* dir, bool copy, QWidget* parent ) 0059 : DataUrlAddingDialog( dir, parent ) 0060 { 0061 m_infoLabel->setText( i18n("Moving files to project \"%1\"...", dir->getDoc()->URL().fileName()) ); 0062 m_copyItems = copy; 0063 0064 for( QList<K3b::DataItem*>::const_iterator it = items.begin(); it != items.end(); ++it ) { 0065 m_items.append( qMakePair( *it, dir ) ); 0066 ++m_totalFiles; 0067 if( (*it)->isDir() ) { 0068 m_totalFiles += static_cast<K3b::DirItem*>( *it )->numFiles(); 0069 m_totalFiles += static_cast<K3b::DirItem*>( *it )->numDirs(); 0070 } 0071 } 0072 } 0073 0074 0075 K3b::DataUrlAddingDialog::DataUrlAddingDialog( DirItem* dir, QWidget* parent ) 0076 : QDialog( parent), 0077 m_doc( dir->getDoc() ), 0078 m_bExistingItemsReplaceAll(false), 0079 m_bExistingItemsIgnoreAll(false), 0080 m_bFolderLinksFollowAll(false), 0081 m_bFolderLinksAddAll(false), 0082 m_iAddHiddenFiles(0), 0083 m_iAddSystemFiles(0), 0084 m_bCanceled(false), 0085 m_copyItems(false), 0086 m_totalFiles(0), 0087 m_filesHandled(0), 0088 m_lastProgress(0) 0089 { 0090 m_encodingConverter = new K3b::EncodingConverter(); 0091 0092 setWindowTitle(i18n("Adding files to project '%1'",m_doc->URL().fileName())); 0093 setAttribute( Qt::WA_DeleteOnClose ); 0094 QGridLayout* grid = new QGridLayout( this ); 0095 0096 m_counterLabel = new QLabel( this ); 0097 m_infoLabel = new KSqueezedTextLabel( i18n("Adding files to project '%1'..." 0098 ,m_doc->URL().fileName()), this ); 0099 m_progressWidget = new QProgressBar( this ); 0100 0101 QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Cancel, this ); 0102 connect( buttonBox, SIGNAL(rejected()), SLOT(reject()) ); 0103 0104 grid->addWidget( m_counterLabel, 0, 1 ); 0105 grid->addWidget( m_infoLabel, 0, 0 ); 0106 grid->addWidget( m_progressWidget, 1, 0, 1, 2 ); 0107 grid->addWidget( buttonBox, 2, 0, 1, 2 ); 0108 0109 m_dirSizeJob = new K3b::DirSizeJob( this ); 0110 connect( m_dirSizeJob, SIGNAL(finished(bool)), 0111 this, SLOT(slotDirSizeDone(bool)) ); 0112 0113 // try to start with a reasonable size 0114 resize( (int)( fontMetrics().horizontalAdvance( windowTitle() ) * 1.5 ), sizeHint().height() ); 0115 } 0116 0117 0118 K3b::DataUrlAddingDialog::~DataUrlAddingDialog() 0119 { 0120 // make sure the dir size job is finished 0121 m_dirSizeJob->cancel(); 0122 K3b::SignalWaiter::waitForJob( m_dirSizeJob ); 0123 0124 QString message = resultMessage(); 0125 if( !message.isEmpty() ) 0126 KMessageBox::detailedError( parentWidget(), i18n("Problems while adding files to the project."), message ); 0127 0128 delete m_encodingConverter; 0129 } 0130 0131 0132 void K3b::DataUrlAddingDialog::addUrls( const QList<QUrl>& urls, 0133 K3b::DirItem* dir, 0134 QWidget* parent ) 0135 { 0136 if( !urls.isEmpty() ) { 0137 auto *dlg = new DataUrlAddingDialog( urls, dir, parent ); 0138 dlg->setAttribute(Qt::WA_DeleteOnClose); 0139 QMetaObject::invokeMethod( dlg, "slotStartAddUrls", Qt::QueuedConnection ); 0140 } 0141 } 0142 0143 0144 void K3b::DataUrlAddingDialog::moveItems( const QList<K3b::DataItem*>& items, 0145 K3b::DirItem* dir, 0146 QWidget* parent ) 0147 { 0148 if( !items.isEmpty() ) { 0149 auto *dlg = new DataUrlAddingDialog( items, dir, false, parent ); 0150 dlg->setAttribute(Qt::WA_DeleteOnClose); 0151 QMetaObject::invokeMethod( dlg, "slotStartCopyMoveItems", Qt::QueuedConnection ); 0152 } 0153 } 0154 0155 0156 void K3b::DataUrlAddingDialog::copyItems( const QList<K3b::DataItem*>& items, 0157 K3b::DirItem* dir, 0158 QWidget* parent ) 0159 { 0160 if( !items.isEmpty() ) { 0161 auto *dlg = new DataUrlAddingDialog( items, dir, true, parent ); 0162 dlg->setAttribute(Qt::WA_DeleteOnClose); 0163 QMetaObject::invokeMethod( dlg, "slotStartCopyMoveItems", Qt::QueuedConnection ); 0164 } 0165 } 0166 0167 0168 void K3b::DataUrlAddingDialog::slotStartAddUrls() 0169 { 0170 // 0171 // A common mistake by beginners is to try to burn an iso image 0172 // with a data project. Let's warn them 0173 // 0174 if( m_urls.count() == 1 ) { 0175 K3b::Iso9660 isoF( m_urls.first().toLocalFile() ); 0176 if( isoF.open() ) { 0177 if( KMessageBox::warningTwoActions( parentWidget(), 0178 i18n("<p>The file you are about to add to the project is an ISO 9660 image. As such " 0179 "it can be burned to a medium directly since it already contains a file " 0180 "system.<br>" 0181 "Are you sure you want to add this file to the project?"), 0182 i18n("Adding image file to project"), 0183 KGuiItem(i18n("Add the file to the project"),"list-add"), 0184 KGuiItem(i18n("Burn the image directly"),"tools-media-optical-burn") ) == KMessageBox::SecondaryAction ) { 0185 k3bappcore->k3bMainWindow()->slotWriteImage( m_urls.first() ); 0186 reject(); 0187 return; 0188 } 0189 } 0190 } 0191 0192 slotAddUrls(); 0193 if( !m_urlQueue.isEmpty() ) { 0194 m_dirSizeJob->setUrls( m_urls ); 0195 m_dirSizeJob->setFollowSymlinks( m_doc->isoOptions().followSymbolicLinks() ); 0196 m_dirSizeJob->start(); 0197 exec(); 0198 } 0199 } 0200 0201 0202 void K3b::DataUrlAddingDialog::slotStartCopyMoveItems() 0203 { 0204 slotCopyMoveItems(); 0205 if( !m_items.isEmpty() ) { 0206 m_progressWidget->setMaximum( m_totalFiles ); 0207 exec(); 0208 } 0209 } 0210 0211 0212 void K3b::DataUrlAddingDialog::slotAddUrls() 0213 { 0214 if( m_bCanceled ) 0215 return; 0216 0217 // add next url 0218 QUrl url = m_urlQueue.first().first; 0219 K3b::DirItem* dir = m_urlQueue.first().second; 0220 m_urlQueue.erase( m_urlQueue.begin() ); 0221 // 0222 // HINT: 0223 // we only use QFileInfo::absoluteFilePath() and QFileInfo::isHidden() 0224 // both do not cause QFileInfo to stat, thus no speed improvement 0225 // can come from removing QFileInfo usage here. 0226 // 0227 QFileInfo info(url.toLocalFile()); 0228 QString absoluteFilePath( info.absoluteFilePath() ); 0229 QString resolved( absoluteFilePath ); 0230 0231 bool valid = true; 0232 k3b_struct_stat statBuf, resolvedStatBuf; 0233 bool isSymLink = false; 0234 bool isDir = false; 0235 bool isFile = false; 0236 0237 ++m_filesHandled; 0238 0239 m_infoLabel->setText( url.toLocalFile() ); 0240 if( m_totalFiles == 0 ) 0241 m_counterLabel->setText( QString("(%1)").arg(m_filesHandled) ); 0242 else 0243 m_counterLabel->setText( QString("(%1/%2)").arg(m_filesHandled).arg(m_totalFiles) ); 0244 0245 // 0246 // 1. Check if we want and can add the url 0247 // 0248 0249 if( !url.isLocalFile() ) { 0250 valid = false; 0251 m_nonLocalFiles.append( url.toLocalFile() ); 0252 } 0253 0254 else if( k3b_lstat( QFile::encodeName(absoluteFilePath), &statBuf ) != 0 ) { 0255 valid = false; 0256 m_notFoundFiles.append( url.toLocalFile() ); 0257 } 0258 0259 else if( !m_encodingConverter->encodedLocally( QFile::encodeName( url.toLocalFile() ) ) ) { 0260 valid = false; 0261 m_invalidFilenameEncodingFiles.append( url.toLocalFile() ); 0262 } 0263 0264 else { 0265 isSymLink = S_ISLNK(statBuf.st_mode); 0266 isFile = S_ISREG(statBuf.st_mode); 0267 isDir = S_ISDIR(statBuf.st_mode); 0268 0269 // symlinks are always readable and can always be added to a project 0270 // but we need to know if the symlink points to a directory 0271 if( isSymLink ) { 0272 resolved = K3b::resolveLink( absoluteFilePath ); 0273 k3b_stat( QFile::encodeName(resolved), &resolvedStatBuf ); 0274 isDir = S_ISDIR(resolvedStatBuf.st_mode); 0275 } 0276 0277 else { 0278 if( ::access( QFile::encodeName( absoluteFilePath ), R_OK ) != 0 ) { 0279 valid = false; 0280 m_unreadableFiles.append( url.toLocalFile() ); 0281 } 0282 else if( isFile && (unsigned long long)statBuf.st_size >= 0xFFFFFFFFULL ) { 0283 const K3b::ExternalBin *mkisofsBin = k3bcore->externalBinManager()->binObject( "mkisofs" ); 0284 if ( !mkisofsBin || !mkisofsBin->hasFeature( "no-4gb-limit" ) ) { 0285 valid = false; 0286 m_tooBigFiles.append( url.toLocalFile() ); 0287 } 0288 } 0289 } 0290 0291 // FIXME: if we do not add hidden dirs the progress gets messed up! 0292 0293 // 0294 // check for hidden and system files 0295 // 0296 if( valid ) { 0297 if( info.isHidden() && !addHiddenFiles() ) 0298 valid = false; 0299 if( S_ISCHR(statBuf.st_mode) || 0300 S_ISBLK(statBuf.st_mode) || 0301 S_ISFIFO(statBuf.st_mode) || 0302 S_ISSOCK(statBuf.st_mode) ) 0303 if( !addSystemFiles() ) 0304 valid = false; 0305 if( isSymLink ) 0306 if( S_ISCHR(resolvedStatBuf.st_mode) || 0307 S_ISBLK(resolvedStatBuf.st_mode) || 0308 S_ISFIFO(resolvedStatBuf.st_mode) || 0309 S_ISSOCK(resolvedStatBuf.st_mode) ) 0310 if( !addSystemFiles() ) 0311 valid = false; 0312 } 0313 } 0314 0315 0316 // 0317 // 2. Handle the url 0318 // 0319 0320 QString newName = url.fileName(); 0321 0322 // filenames cannot end in backslashes (mkisofs problem. See comments in k3bisoimager.cpp (escapeGraftPoint())) 0323 bool bsAtEnd = false; 0324 while (!newName.isEmpty() && newName[newName.length() - 1] == '\\') { 0325 newName.truncate( newName.length()-1 ); 0326 bsAtEnd = true; 0327 } 0328 if( bsAtEnd ) 0329 m_mkisofsLimitationRenamedFiles.append( url.toLocalFile() + " -> " + newName ); 0330 0331 // backup dummy name 0332 if( newName.isEmpty() ) 0333 newName = '1'; 0334 0335 K3b::DirItem* newDirItem = 0; 0336 0337 // 0338 // The source is valid. Now check if the project already contains a file with that name 0339 // and if so handle it properly 0340 // 0341 if( valid ) { 0342 if( K3b::DataItem* oldItem = dir->find( newName ) ) { 0343 // 0344 // reuse an existing dir 0345 // 0346 if( oldItem->isDir() && isDir ) 0347 newDirItem = dynamic_cast<K3b::DirItem*>(oldItem); 0348 0349 // 0350 // we cannot replace files in the old session with dirs and vice versa (I think) 0351 // files are handled in K3b::FileItem constructor and dirs handled above 0352 // 0353 else if( oldItem->isFromOldSession() && 0354 isDir != oldItem->isDir() ) { 0355 if( !getNewName( newName, dir, newName ) ) 0356 valid = false; 0357 } 0358 0359 else if( m_bExistingItemsIgnoreAll ) 0360 valid = false; 0361 0362 else if( oldItem->localPath() == resolved ) { 0363 // 0364 // Just ignore if the same file is added again 0365 // 0366 valid = false; 0367 } 0368 0369 else if( m_bExistingItemsReplaceAll ) { 0370 // if we replace an item from an old session the K3b::FileItem constructor takes care 0371 // of replacing the item 0372 if( !oldItem->isFromOldSession() ) 0373 delete oldItem; 0374 } 0375 0376 // 0377 // Let the user choose 0378 // 0379 else { 0380 switch( K3b::MultiChoiceDialog::choose( i18n("File already exists"), 0381 i18n("<p>File <em>%1</em> already exists in " 0382 "project folder <em>%2</em>.", 0383 newName, 0384 QString( '/' + dir->k3bPath()) ), 0385 QMessageBox::Warning, 0386 this, 0387 6, 0388 KGuiItem( i18n("Replace"), 0389 QString(), 0390 i18n("Replace the existing file") ), 0391 KGuiItem( i18n("Replace All"), 0392 QString(), 0393 i18n("Always replace existing files") ), 0394 KGuiItem( i18n("Ignore"), 0395 QString(), 0396 i18n("Keep the existing file") ), 0397 KGuiItem( i18n("Ignore All"), 0398 QString(), 0399 i18n("Always keep the existing file") ), 0400 KGuiItem( i18n("Rename"), 0401 QString(), 0402 i18n("Rename the new file") ), 0403 KStandardGuiItem::cancel() ) ) { 0404 case 2: // replace all 0405 m_bExistingItemsReplaceAll = true; 0406 // fallthrough 0407 case 1: // replace 0408 // if we replace an item from an old session the K3b::FileItem constructor takes care 0409 // of replacing the item 0410 if( !oldItem->isFromOldSession() ) 0411 delete oldItem; 0412 break; 0413 case 4: // ignore all 0414 m_bExistingItemsIgnoreAll = true; 0415 // fallthrough 0416 case 3: // ignore 0417 valid = false; 0418 break; 0419 case 5: // rename 0420 if( !getNewName( newName, dir, newName ) ) 0421 valid = false; 0422 break; 0423 case 6: // cancel 0424 reject(); 0425 return; 0426 } 0427 } 0428 } 0429 } 0430 0431 0432 // 0433 // One more thing to warn the user about: We cannot follow links to folders since that 0434 // would change the doc. So we simply ask the user what to do with a link to a folder 0435 // 0436 if( valid ) { 0437 // let's see if this link starts a loop 0438 // that means if it points to some folder above this one 0439 // if so we cannot follow it anyway 0440 if( isDir && isSymLink && !absoluteFilePath.startsWith( resolved ) ) { 0441 bool followLink = dir->getDoc()->isoOptions().followSymbolicLinks() || m_bFolderLinksFollowAll; 0442 if( !followLink && !m_bFolderLinksAddAll ) { 0443 switch( K3b::MultiChoiceDialog::choose( i18n("Adding link to folder"), 0444 i18n("<p>'%1' is a symbolic link to folder '%2'." 0445 "<p>If you intend to make K3b follow symbolic links you should consider letting K3b do this now " 0446 "since K3b will not be able to do so afterwards because symbolic links to folders inside a " 0447 "K3b project cannot be resolved." 0448 "<p><b>If you do not intend to enable the option <em>follow symbolic links</em> you may safely " 0449 "ignore this warning and choose to add the link to the project.</b>", 0450 absoluteFilePath, 0451 resolved ), 0452 QMessageBox::Warning, 0453 this, 0454 5, 0455 KGuiItem(i18n("Follow link now")), 0456 KGuiItem(i18n("Always follow links")), 0457 KGuiItem(i18n("Add link to project")), 0458 KGuiItem(i18n("Always add links")), 0459 KStandardGuiItem::cancel()) ) { 0460 case 2: 0461 m_bFolderLinksFollowAll = true; 0462 Q_FALLTHROUGH(); 0463 case 1: 0464 followLink = true; 0465 break; 0466 case 4: 0467 m_bFolderLinksAddAll = true; 0468 Q_FALLTHROUGH(); 0469 case 3: 0470 followLink = false; 0471 break; 0472 case 5: 0473 reject(); 0474 return; 0475 } 0476 } 0477 0478 if( followLink ) { 0479 absoluteFilePath = resolved; 0480 isSymLink = false; 0481 0482 // count the files in the followed dir 0483 if( m_dirSizeJob->active() ) 0484 m_dirSizeQueue.append( QUrl::fromLocalFile(absoluteFilePath) ); 0485 else { 0486 m_progressWidget->setMaximum( 0 ); 0487 m_dirSizeJob->setUrls( QList<QUrl>() << QUrl::fromLocalFile(absoluteFilePath) ); 0488 m_dirSizeJob->start(); 0489 } 0490 } 0491 } 0492 } 0493 0494 0495 // 0496 // Project valid also (we overwrite or renamed) 0497 // now create the new item 0498 // 0499 if( valid ) { 0500 // 0501 // Set the volume id from the first added url 0502 // only if the doc was not changed yet 0503 // 0504 if( m_urls.count() == 1 && 0505 !dir->getDoc()->isModified() && 0506 !dir->getDoc()->isSaved() ) { 0507 dir->getDoc()->setVolumeID( K3b::removeFilenameExtension( newName ) ); 0508 } 0509 0510 if( isDir && !isSymLink ) { 0511 if( !newDirItem ) { // maybe we reuse an already existing dir 0512 newDirItem = new K3b::DirItem( newName ); 0513 newDirItem->setLocalPath( url.toLocalFile() ); // HACK: see k3bdiritem.h 0514 dir->addDataItem( newDirItem ); 0515 } 0516 0517 KIO::ListJob *lj = KIO::listDir(QUrl::fromLocalFile(absoluteFilePath), KIO::HideProgressInfo); 0518 KIO::UDSEntryList list; 0519 connect(lj, &KIO::ListJob::entries, this, [&](KIO::Job *, const KIO::UDSEntryList &l) { list.append(l); }); 0520 lj->exec(); 0521 foreach( const KIO::UDSEntry& entry, list ) { 0522 const QString fileName = entry.stringValue( KIO::UDSEntry::UDS_NAME ); 0523 if (fileName != QStringLiteral(".") && fileName != QStringLiteral("..")) { 0524 m_urlQueue.append( qMakePair( QUrl::fromLocalFile(absoluteFilePath + '/' + fileName ), newDirItem ) ); 0525 } 0526 } 0527 } 0528 else { 0529 m_newItems[ dir ].append( new K3b::FileItem( &statBuf, &resolvedStatBuf, url.toLocalFile(), *dir->getDoc(), newName ) ); 0530 } 0531 } 0532 0533 if( m_urlQueue.isEmpty() ) { 0534 Q_FOREACH( DirItem* dir, m_newItems.keys() ) { 0535 dir->addDataItems( m_newItems[ dir ] ); 0536 } 0537 m_dirSizeJob->cancel(); 0538 m_progressWidget->setMaximum( 100 ); 0539 accept(); 0540 } 0541 else { 0542 updateProgress(); 0543 QMetaObject::invokeMethod( this, "slotAddUrls", Qt::QueuedConnection ); 0544 } 0545 } 0546 0547 0548 void K3b::DataUrlAddingDialog::slotCopyMoveItems() 0549 { 0550 if( m_bCanceled ) 0551 return; 0552 0553 // 0554 // Pop first item from the item list 0555 // 0556 K3b::DataItem* item = m_items.first().first; 0557 K3b::DirItem* dir = m_items.first().second; 0558 m_items.erase( m_items.begin() ); 0559 0560 ++m_filesHandled; 0561 m_infoLabel->setText( item->k3bPath() ); 0562 if( m_totalFiles == 0 ) 0563 m_counterLabel->setText( QString("(%1)").arg(m_filesHandled) ); 0564 else 0565 m_counterLabel->setText( QString("(%1/%2)").arg(m_filesHandled).arg(m_totalFiles) ); 0566 0567 0568 if( dir == item->parent() ) { 0569 qDebug() << "(K3b::DataUrlAddingDialog) trying to move an item into its own parent dir."; 0570 } 0571 else if( dir == item ) { 0572 qDebug() << "(K3b::DataUrlAddingDialog) trying to move an item into itselft."; 0573 } 0574 else { 0575 // 0576 // Let's see if an item with that name already exists 0577 // 0578 if( K3b::DataItem* oldItem = dir->find( item->k3bName() ) ) { 0579 // 0580 // reuse an existing dir: move all child items into the old dir 0581 // 0582 if( oldItem->isDir() && item->isDir() ) { 0583 QList<K3b::DataItem*> const& cl = dynamic_cast<K3b::DirItem*>( item )->children(); 0584 for( QList<K3b::DataItem*>::const_iterator it = cl.constBegin(); 0585 it != cl.constEnd(); ++it ) 0586 m_items.append( qMakePair( *it, dynamic_cast<K3b::DirItem*>( oldItem ) ) ); 0587 0588 // FIXME: we need to remove the old dir item 0589 } 0590 0591 // 0592 // we cannot replace files in the old session with dirs and vice versa (I think) 0593 // files are handled in K3b::FileItem constructor and dirs handled above 0594 // 0595 else if( oldItem->isFromOldSession() && 0596 item->isDir() != oldItem->isDir() ) { 0597 QString newName; 0598 if( getNewName( newName, dir, newName ) ) { 0599 if( m_copyItems ) 0600 item = item->copy(); 0601 item->setK3bName( newName ); 0602 dir->addDataItem( item ); 0603 } 0604 } 0605 0606 else if( m_bExistingItemsReplaceAll ) { 0607 // 0608 // if we replace an item from an old session K3b::DirItem::addDataItem takes care 0609 // of replacing the item 0610 // 0611 if( !oldItem->isFromOldSession() ) 0612 delete oldItem; 0613 if( m_copyItems ) 0614 item = item->copy(); 0615 dir->addDataItem( item ); 0616 } 0617 0618 else if( !m_bExistingItemsIgnoreAll ) { 0619 switch( K3b::MultiChoiceDialog::choose( i18n("File already exists"), 0620 i18n("<p>File <em>%1</em> already exists in " 0621 "project folder <em>%2</em>.", 0622 item->k3bName(), 0623 '/' + dir->k3bPath() ), 0624 QMessageBox::Warning, 0625 this, 0626 6, 0627 KGuiItem( i18n("Replace"), 0628 QString(), 0629 i18n("Replace the existing file") ), 0630 KGuiItem( i18n("Replace All"), 0631 QString(), 0632 i18n("Always replace existing files") ), 0633 KGuiItem( i18n("Ignore"), 0634 QString(), 0635 i18n("Keep the existing file") ), 0636 KGuiItem( i18n("Ignore All"), 0637 QString(), 0638 i18n("Always keep the existing file") ), 0639 KGuiItem( i18n("Rename"), 0640 QString(), 0641 i18n("Rename the new file") ), 0642 KStandardGuiItem::cancel() ) ) { 0643 case 2: // replace all 0644 m_bExistingItemsReplaceAll = true; 0645 // fallthrough 0646 case 1: // replace 0647 // 0648 // if we replace an item from an old session K3b::DirItem::addDataItem takes care 0649 // of replacing the item 0650 // 0651 if( !oldItem->isFromOldSession() ) 0652 delete oldItem; 0653 if( m_copyItems ) 0654 item = item->copy(); 0655 dir->addDataItem( item ); 0656 break; 0657 case 4: // ignore all 0658 m_bExistingItemsIgnoreAll = true; 0659 // fallthrough 0660 case 3: // ignore 0661 // do nothing 0662 break; 0663 case 5: {// rename 0664 QString newName; 0665 if( getNewName( newName, dir, newName ) ) { 0666 if( m_copyItems ) 0667 item = item->copy(); 0668 item->setK3bName( newName ); 0669 dir->addDataItem( item ); 0670 } 0671 break; 0672 } 0673 case 6: // cancel 0674 reject(); 0675 return; 0676 } 0677 } 0678 } 0679 0680 // 0681 // No old item with the same name 0682 // 0683 else { 0684 if( m_copyItems ) 0685 item = item->copy(); 0686 dir->addDataItem( item ); 0687 } 0688 } 0689 0690 if( m_items.isEmpty() ) { 0691 m_dirSizeJob->cancel(); 0692 accept(); 0693 } 0694 else { 0695 updateProgress(); 0696 QMetaObject::invokeMethod( this, "slotCopyMoveItems", Qt::QueuedConnection ); 0697 } 0698 } 0699 0700 0701 void K3b::DataUrlAddingDialog::reject() 0702 { 0703 m_bCanceled = true; 0704 m_dirSizeJob->cancel(); 0705 QDialog::reject(); 0706 } 0707 0708 0709 void K3b::DataUrlAddingDialog::slotDirSizeDone( bool success ) 0710 { 0711 if( success ) { 0712 m_totalFiles += m_dirSizeJob->totalFiles() + m_dirSizeJob->totalDirs(); 0713 if( m_dirSizeQueue.isEmpty() ) { 0714 m_progressWidget->setValue( 100 ); 0715 updateProgress(); 0716 } 0717 else { 0718 m_dirSizeJob->setUrls( QList<QUrl>() << m_dirSizeQueue.back() ); 0719 m_dirSizeQueue.pop_back(); 0720 m_dirSizeJob->start(); 0721 } 0722 } 0723 } 0724 0725 0726 void K3b::DataUrlAddingDialog::updateProgress() 0727 { 0728 if( m_totalFiles > 0 ) { 0729 unsigned int p = 100*m_filesHandled/m_totalFiles; 0730 if( p > m_lastProgress ) { 0731 m_lastProgress = p; 0732 m_progressWidget->setValue( p ); 0733 } 0734 } 0735 else { 0736 // make sure the progress bar shows something 0737 m_progressWidget->setValue( m_filesHandled ); 0738 } 0739 } 0740 0741 0742 bool K3b::DataUrlAddingDialog::getNewName( const QString& oldName, K3b::DirItem* dir, QString& newName ) 0743 { 0744 bool ok = true; 0745 newName = oldName; 0746 QValidator* validator = K3b::Validators::iso9660Validator( false, this ); 0747 int pos; 0748 do { 0749 newName = QInputDialog::getText( this, 0750 i18n("Enter New Filename"), 0751 i18n("A file with that name already exists. Please enter a new name:"), 0752 QLineEdit::Normal, 0753 newName, &ok ); 0754 0755 } while( ok && validator->validate( newName, pos ) == QValidator::Acceptable && dir->find( newName ) ); 0756 0757 delete validator; 0758 0759 return ok; 0760 } 0761 0762 0763 bool K3b::DataUrlAddingDialog::addHiddenFiles() 0764 { 0765 if( m_iAddHiddenFiles == 0 ) { 0766 // FIXME: the isVisible() stuff makes the static addUrls method not return (same below) 0767 if( KMessageBox::questionTwoActions( /*isVisible() ? */this/* : parentWidget()*/, 0768 i18n("Do you also want to add hidden files?"), 0769 i18n("Hidden Files"), KGuiItem(i18n("Add")), KGuiItem(i18n("Do Not Add")) ) == KMessageBox::PrimaryAction ) 0770 m_iAddHiddenFiles = 1; 0771 else 0772 m_iAddHiddenFiles = -1; 0773 } 0774 0775 return ( m_iAddHiddenFiles == 1 ); 0776 } 0777 0778 0779 bool K3b::DataUrlAddingDialog::addSystemFiles() 0780 { 0781 if( m_iAddSystemFiles == 0 ) { 0782 if( KMessageBox::questionTwoActions( /*isVisible() ? */this/* : parentWidget()*/, 0783 i18n("Do you also want to add system files " 0784 "(FIFOs, sockets, device files, and broken symlinks)?"), 0785 i18n("System Files"), KGuiItem(i18n("Add")), KGuiItem(i18n("Do Not Add")) ) == KMessageBox::PrimaryAction ) 0786 m_iAddSystemFiles = 1; 0787 else 0788 m_iAddSystemFiles = -1; 0789 } 0790 0791 return ( m_iAddSystemFiles == 1 ); 0792 } 0793 0794 0795 QString K3b::DataUrlAddingDialog::resultMessage() const 0796 { 0797 QString message; 0798 if( !m_unreadableFiles.isEmpty() ) 0799 message += QString("<p><b>%1:</b><br>%2") 0800 .arg( i18n("Insufficient permissions to read the following files") ) 0801 .arg( m_unreadableFiles.join( "<br>" ) ); 0802 if( !m_notFoundFiles.isEmpty() ) 0803 message += QString("<p><b>%1:</b><br>%2") 0804 .arg( i18n("Unable to find the following files") ) 0805 .arg( m_notFoundFiles.join( "<br>" ) ); 0806 if( !m_nonLocalFiles.isEmpty() ) 0807 message += QString("<p><b>%1:</b><br>%2") 0808 .arg( i18n("No non-local files supported") ) 0809 .arg( m_unreadableFiles.join( "<br>" ) ); 0810 if( !m_tooBigFiles.isEmpty() ) 0811 message += QString("<p><b>%1:</b><br>%2") 0812 .arg( i18n("To burn files bigger than %1 please use %2",KIO::convertSize(0xFFFFFFFF), 0813 QString("mkisofs >= 2.01.01a33 / genisoimage >= 1.1.4") ) ) 0814 .arg( m_tooBigFiles.join( "<br>" ) ); 0815 if( !m_mkisofsLimitationRenamedFiles.isEmpty() ) 0816 message += QString("<p><b>%1:</b><br>%2") 0817 .arg( i18n("Some filenames had to be modified due to limitations in mkisofs") ) 0818 .arg( m_mkisofsLimitationRenamedFiles.join( "<br>" ) ); 0819 if( !m_invalidFilenameEncodingFiles.isEmpty() ) 0820 message += QString("<p><b>%1:</b><br>%2") 0821 .arg( i18n("The following filenames have an invalid encoding. You may fix this " 0822 "with the convmv tool") ) 0823 .arg( m_invalidFilenameEncodingFiles.join( "<br>" ) ); 0824 0825 return message; 0826 } 0827 0828 #include "moc_k3bdataurladdingdialog.cpp"