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"