File indexing completed on 2024-04-28 08:49:25
0001 /*************************************************************************** 0002 * Copyright (C) 2007-2014 Lukas Appelhans <l.appelhans@gmx.de> * 0003 * Copyright (C) 2008 Dario Freddi <drf54321@gmail.com> * 0004 * Copyright (C) 2010 Matthias Fuchs <mat69@gmx.net> * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, * 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0014 * GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License * 0017 * along with this program; if not, write to the * 0018 * Free Software Foundation, Inc., * 0019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 0020 ***************************************************************************/ 0021 0022 #include "urlchecker.h" 0023 #include "core/filedeleter.h" 0024 #include "core/kget.h" 0025 #include "core/transferhandler.h" 0026 #include "core/transfertreemodel.h" 0027 #include "mainwindow.h" 0028 #include "settings.h" 0029 #include "urlchecker_p.h" 0030 0031 #include <algorithm> 0032 #include <boost/bind/bind.hpp> 0033 0034 #include "kget_debug.h" 0035 0036 #include <QCheckBox> 0037 #include <QDialogButtonBox> 0038 #include <QFileInfo> 0039 #include <QHBoxLayout> 0040 #include <QLabel> 0041 #include <QPushButton> 0042 0043 #include <KIO/RenameDialog> 0044 #include <KLocalizedString> 0045 #include <KSeparator> 0046 #include <KStandardGuiItem> 0047 0048 ExistingTransferDialog::ExistingTransferDialog(const QString &text, const QString &caption, QWidget *parent) 0049 : QDialog(parent) 0050 { 0051 setWindowTitle(caption.isEmpty() ? i18n("Question") : caption); 0052 setModal(true); 0053 0054 auto *layout = new QVBoxLayout; 0055 auto *bottomLayout = new QHBoxLayout; 0056 0057 auto *label = new QLabel(text, this); 0058 layout->addWidget(label); 0059 layout->addWidget(new KSeparator(Qt::Horizontal, this)); 0060 0061 m_applyAll = new QCheckBox(i18n("Appl&y to all"), this); 0062 bottomLayout->addStretch(1); 0063 bottomLayout->addWidget(m_applyAll); 0064 0065 auto *buttonBox = new QDialogButtonBox(this); 0066 buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel); 0067 connect(buttonBox->button(QDialogButtonBox::Yes), &QPushButton::clicked, this, &ExistingTransferDialog::slotYesClicked); 0068 connect(buttonBox->button(QDialogButtonBox::No), &QPushButton::clicked, this, &ExistingTransferDialog::slotNoClicked); 0069 connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &ExistingTransferDialog::slotCancelClicked); 0070 bottomLayout->addWidget(buttonBox); 0071 layout->addLayout(bottomLayout, 0); 0072 0073 setLayout(layout); 0074 } 0075 0076 void ExistingTransferDialog::slotYesClicked() 0077 { 0078 done(m_applyAll->isChecked() ? YesAll : Yes); 0079 } 0080 0081 void ExistingTransferDialog::slotNoClicked() 0082 { 0083 done(m_applyAll->isChecked() ? NoAll : No); 0084 } 0085 0086 void ExistingTransferDialog::slotCancelClicked() 0087 { 0088 done(Cancel); 0089 } 0090 0091 UrlChecker::UrlChecker(UrlType type) 0092 : m_type(type) 0093 , m_cancel(false) 0094 , m_overwriteAll(false) 0095 , m_autoRenameAll(false) 0096 , m_skipAll(false) 0097 { 0098 } 0099 0100 UrlChecker::~UrlChecker() 0101 { 0102 } 0103 0104 /// Static methods following 0105 0106 struct lessThan { 0107 bool operator()(const QUrl &lhs, const QUrl &rhs) const 0108 { 0109 return lhs.url() < rhs.url(); 0110 } 0111 }; 0112 0113 void UrlChecker::removeDuplicates(QList<QUrl> &urls) 0114 { 0115 std::sort(urls.begin(), urls.end(), lessThan()); // sort the urls, to find duplicates fast 0116 urls.erase( 0117 std::unique(urls.begin(), 0118 urls.end(), 0119 boost::bind(&QUrl::matches, boost::placeholders::_1, boost::placeholders::_2, QUrl::StripTrailingSlash | QUrl::NormalizePathSegments)), 0120 urls.end()); 0121 } 0122 0123 UrlChecker::UrlError UrlChecker::checkUrl(const QUrl &url, const UrlChecker::UrlType type, bool showNotification) 0124 { 0125 switch (type) { 0126 case Source: 0127 return checkSource(url, showNotification); 0128 case Destination: 0129 return checkDestination(url, showNotification); 0130 case Folder: 0131 return checkFolder(url, showNotification); 0132 } 0133 0134 return NoError; 0135 } 0136 0137 bool UrlChecker::wouldOverwrite(const QUrl &source, const QUrl &dest) 0138 { 0139 return (dest.isLocalFile() && QFile::exists(dest.toLocalFile()) && source != dest && !FileDeleter::isFileBeingDeleted(dest)); 0140 } 0141 0142 UrlChecker::UrlError UrlChecker::checkSource(const QUrl &src, bool showNotification) 0143 { 0144 // NOTE hasPath is not used, as this would disallow addresses like https://www.kde.org/ as there is no path 0145 UrlError error = NoError; 0146 if (src.isEmpty()) { 0147 return Empty; 0148 } 0149 if ((error == NoError) && !src.isValid()) { 0150 error = Invalid; 0151 } 0152 if ((error == NoError) && src.scheme().isEmpty()) { 0153 error = NoProtocol; 0154 } 0155 /*if ((error == NoError) && !src.hasHost()) {//FIXME deactivated to allow file://....metalink etc 0156 error = NoHost; 0157 }*/ 0158 0159 if (showNotification && (error != NoError)) { 0160 qCDebug(KGET_DEBUG) << "Source:" << src << "has error:" << error; 0161 KGet::showNotification("error", message(src, Source, error)); 0162 } 0163 0164 // TODO also check sourceUrl.url() != QUrl(sourceUrl.url()).fileName() as in NewTransferDialog::setSource? 0165 0166 return error; 0167 } 0168 0169 UrlChecker::UrlError UrlChecker::checkDestination(const QUrl &destination, bool showNotification) 0170 { 0171 UrlError error = NoError; 0172 0173 if (destination.isEmpty()) { 0174 error = Empty; 0175 } 0176 0177 if (error == NoError) { 0178 // not supposed to be a folder 0179 QFileInfo fileInfo(destination.toLocalFile()); 0180 if (!destination.isValid() || fileInfo.isDir()) { 0181 error = Invalid; 0182 } 0183 0184 qDebug() << "Adjusted destination:" << destination.adjusted(QUrl::RemoveFilename).path(); 0185 if ((error == NoError) && !QFileInfo(destination.adjusted(QUrl::RemoveFilename).path()).isWritable()) { 0186 error = NotWriteable; 0187 } 0188 } 0189 0190 qCDebug(KGET_DEBUG) << "Destination:" << destination << "has error:" << error; 0191 0192 if (showNotification && (error != NoError)) { 0193 KGet::showNotification("error", message(destination, Destination, error)); 0194 } 0195 0196 return error; 0197 } 0198 0199 UrlChecker::UrlError UrlChecker::checkFolder(const QUrl &folder, bool showNotification) 0200 { 0201 UrlError error = NoError; 0202 0203 const QString destDir = folder.toLocalFile(); 0204 if (folder.isEmpty() || destDir.isEmpty()) { 0205 error = Empty; 0206 } 0207 0208 if (error == NoError) { 0209 // has to be a folder 0210 QFileInfo fileInfo(destDir); 0211 if (!folder.isValid() || !fileInfo.isDir()) { 0212 error = Invalid; 0213 } 0214 0215 // has to be writeable 0216 if ((error == NoError) && !fileInfo.isWritable()) { 0217 error = NotWriteable; 0218 } 0219 } 0220 0221 if (showNotification && (error != NoError)) { 0222 qCDebug(KGET_DEBUG) << "Folder:" << folder << "has error:" << error; 0223 KGet::showNotification("error", message(folder, Folder, error)); 0224 } 0225 0226 return error; 0227 } 0228 0229 QUrl UrlChecker::destUrl(const QUrl &destOrFolder, const QUrl &source, const QString &fileName) 0230 { 0231 QUrl dest = destOrFolder; 0232 if (QFileInfo(dest.toLocalFile()).isDir()) { 0233 QString usedFileName = (fileName.isEmpty() ? source.fileName() : fileName); 0234 if (usedFileName.isEmpty()) { 0235 usedFileName = QUrl::toPercentEncoding(source.toString(), "/"); 0236 } 0237 if (!dest.path().endsWith('/')) 0238 dest.setPath(dest.path() + '/'); 0239 dest.setPath(dest.adjusted(QUrl::RemoveFilename).path() + usedFileName); 0240 } else if (!fileName.isEmpty()) { 0241 dest.setPath(dest.adjusted(QUrl::RemoveFilename).path() + fileName); 0242 } 0243 0244 return dest; 0245 } 0246 0247 TransferHandler *UrlChecker::existingTransfer(const QUrl &url, const UrlChecker::UrlType type, UrlChecker::UrlWarning *warning) 0248 { 0249 UrlWarning temp; 0250 UrlWarning &warn = (warning ? (*warning) : temp); 0251 warn = NoWarning; 0252 0253 switch (type) { 0254 case Source: 0255 return existingSource(url, warn); 0256 case Destination: 0257 return existingDestination(url, warn); 0258 default: 0259 return nullptr; 0260 } 0261 } 0262 0263 TransferHandler *UrlChecker::existingSource(const QUrl &source, UrlChecker::UrlWarning &warning) 0264 { 0265 // Check if a transfer with the same url already exists 0266 Transfer *transfer = KGet::m_transferTreeModel->findTransfer(source); 0267 if (transfer) { 0268 if (transfer->status() == Job::Finished) { 0269 warning = ExistingFinishedTransfer; 0270 } else { 0271 warning = ExistingTransfer; 0272 } 0273 } 0274 0275 return (transfer ? transfer->handler() : nullptr); 0276 } 0277 0278 TransferHandler *UrlChecker::existingDestination(const QUrl &url, UrlChecker::UrlWarning &warning) 0279 { 0280 Transfer *transfer = KGet::m_transferTreeModel->findTransferByDestination(url); 0281 if (transfer) { 0282 if (transfer->status() == Job::Finished) { 0283 warning = ExistingFinishedTransfer; 0284 } else { 0285 warning = ExistingTransfer; 0286 } 0287 } else if (QFile::exists(url.toString())) { 0288 warning = ExistingFile; 0289 } 0290 0291 return (transfer ? transfer->handler() : nullptr); 0292 } 0293 0294 QString UrlChecker::message(const QUrl &url, const UrlChecker::UrlType type, const UrlChecker::UrlError error) 0295 { 0296 if (url.isEmpty()) { 0297 if (type == Folder) { 0298 switch (error) { 0299 case Empty: 0300 return i18n("No download directory specified."); 0301 case Invalid: 0302 return i18n("Invalid download directory specified."); 0303 case NotWriteable: 0304 return i18n("Download directory is not writeable."); 0305 default: 0306 return QString(); 0307 } 0308 } 0309 if (type == Destination) { 0310 switch (error) { 0311 case Empty: 0312 return i18n("No download destination specified."); 0313 case Invalid: 0314 return i18n("Invalid download destination specified."); 0315 case NotWriteable: 0316 return i18n("Download destination is not writeable."); 0317 default: 0318 return QString(); 0319 } 0320 } 0321 if (type == Source) { 0322 switch (error) { 0323 case Empty: 0324 return i18n("No URL specified."); 0325 case Invalid: 0326 return i18n("Malformed URL."); 0327 case NoProtocol: 0328 return i18n("Malformed URL, protocol missing."); 0329 case NoHost: 0330 return i18n("Malformed URL, host missing."); 0331 default: 0332 return QString(); 0333 } 0334 } 0335 } else { 0336 const QString urlString = url.toString(); 0337 if (type == Folder) { 0338 switch (error) { 0339 case Empty: 0340 return i18n("No download directory specified."); 0341 case Invalid: 0342 return i18n("Invalid download directory specified:\n%1", urlString); 0343 case NotWriteable: 0344 return i18n("Download directory is not writeable:\n%1", urlString); 0345 default: 0346 return QString(); 0347 } 0348 } 0349 if (type == Destination) { 0350 switch (error) { 0351 case Empty: 0352 return i18n("No download destination specified."); 0353 case Invalid: 0354 return i18n("Invalid download destination specified:\n%1", urlString); 0355 case NotWriteable: 0356 return i18n("Download destination is not writeable:\n%1", urlString); 0357 default: 0358 return QString(); 0359 } 0360 } 0361 if (type == Source) { 0362 switch (error) { 0363 case Empty: 0364 return i18n("No URL specified."); 0365 case Invalid: 0366 return i18n("Malformed URL:\n%1", urlString); 0367 case NoProtocol: 0368 return i18n("Malformed URL, protocol missing:\n%1", urlString); 0369 case NoHost: 0370 return i18n("Malformed URL, host missing:\n%1", urlString); 0371 default: 0372 return QString(); 0373 } 0374 } 0375 } 0376 0377 return QString(); 0378 } 0379 0380 QString UrlChecker::message(const QUrl &url, const UrlChecker::UrlType type, const UrlChecker::UrlWarning warning) 0381 { 0382 if (url.isEmpty()) { 0383 if (type == Destination) { 0384 switch (warning) { 0385 case ExistingFile: 0386 return i18n("File already exists. Overwrite it?"); 0387 case ExistingFinishedTransfer: 0388 return i18n("You have already downloaded that file from another location.\nDownload and delete the previous one?"); 0389 case ExistingTransfer: 0390 return i18n("You are already downloading that file from another location.\nDownload and delete the previous one?"); 0391 default: 0392 return QString(); 0393 } 0394 } 0395 if (type == Source) { 0396 switch (warning) { 0397 case ExistingFile: 0398 return i18n("File already exists. Overwrite it?"); 0399 case ExistingFinishedTransfer: 0400 return i18n("You have already completed a download from that location. Download it again?"); 0401 case ExistingTransfer: 0402 return i18n("You have a download in progress from that location.\nDelete it and download again?"); 0403 default: 0404 return QString(); 0405 } 0406 } 0407 } else { 0408 const QString urlString = url.toString(); 0409 if (type == Destination) { 0410 switch (warning) { 0411 case ExistingFile: 0412 return i18n("File already exists:\n%1\nOverwrite it?", urlString); 0413 case ExistingFinishedTransfer: 0414 return i18n("You have already downloaded that file from another location.\nDownload and delete the previous one?"); 0415 case ExistingTransfer: 0416 return i18n("You are already downloading that file from another location.\nDownload and delete the previous one?"); 0417 default: 0418 return QString(); 0419 } 0420 } 0421 if (type == Source) { 0422 switch (warning) { 0423 case ExistingFinishedTransfer: 0424 return i18n("You have already completed a download from the location: \n\n%1\n\nDownload it again?", urlString); 0425 case ExistingTransfer: 0426 return i18n("You have a download in progress from the location: \n\n%1\n\nDelete it and download again?", urlString); 0427 default: 0428 return QString(); 0429 } 0430 } 0431 } 0432 0433 return QString(); 0434 } 0435 0436 QString UrlChecker::message(const QList<QUrl> &urls, const UrlChecker::UrlType type, const UrlChecker::UrlError error) 0437 { 0438 QString urlsString; 0439 if (!urls.isEmpty()) { 0440 urlsString = urls.first().toString(); 0441 for (int i = 1; i < urls.count(); ++i) { 0442 urlsString += '\n' + urls[i].toString(); 0443 } 0444 urlsString = QString("<p style=\"font-size: small;\">\%1</p>").arg(urlsString); 0445 } 0446 0447 if (urls.isEmpty()) { 0448 if ((type == Folder) || (type == Destination)) { 0449 return message(QUrl(), type, error); 0450 } 0451 if (type == Source) { 0452 switch (error) { 0453 case Empty: 0454 return i18n("No URL specified."); 0455 case Invalid: 0456 return i18n("Malformed URLs."); 0457 case NoProtocol: 0458 return i18n("Malformed URLs, protocol missing."); 0459 case NoHost: 0460 return i18n("Malformed URLs, host missing."); 0461 default: 0462 return QString(); 0463 } 0464 } 0465 } else { 0466 switch (error) { 0467 case Empty: 0468 return i18n("No URL specified."); 0469 case Invalid: 0470 return i18n("Malformed URLs:\n%1", urlsString); 0471 case NoProtocol: 0472 return i18n("Malformed URLs, protocol missing:\n%1", urlsString); 0473 case NoHost: 0474 return i18n("Malformed URLs, host missing:\n%1", urlsString); 0475 case NotWriteable: 0476 return i18n("Destinations are not writable:\n%1", urlsString); 0477 default: 0478 return QString(); 0479 } 0480 } 0481 0482 return QString(); 0483 } 0484 0485 QString UrlChecker::message(const QList<QUrl> &urls, const UrlChecker::UrlType type, const UrlChecker::UrlWarning warning) 0486 { 0487 QString urlsString; 0488 if (!urls.isEmpty()) { 0489 urlsString = urls.first().toString(); 0490 for (int i = 1; i < urls.count(); ++i) { 0491 urlsString += '\n' + urls[i].toString(); 0492 } 0493 urlsString = QString("<p style=\"font-size: small;\">\%1</p>").arg(urlsString); 0494 } 0495 0496 if (urls.isEmpty()) { 0497 if (type == Destination) { 0498 switch (warning) { 0499 case ExistingFile: 0500 return i18n("Files exist already. Overwrite them?"); 0501 case ExistingFinishedTransfer: 0502 return i18n("You have already completed downloads at those destinations. Download them again?"); 0503 case ExistingTransfer: 0504 return i18n("You have downloads in progress to these destinations.\nDelete them and download again?"); 0505 default: 0506 return QString(); 0507 } 0508 } 0509 if (type == Source) { 0510 switch (warning) { 0511 case ExistingFinishedTransfer: 0512 return i18n("You have already completed downloads from these locations. Download them again?"); 0513 case ExistingTransfer: 0514 return i18n("You have downloads in progress from these locations.\nDelete them and download again?"); 0515 default: 0516 return QString(); 0517 } 0518 } 0519 } else { 0520 if (type == Destination) { 0521 switch (warning) { 0522 case ExistingFile: 0523 return i18n("Files exist already:\n%1\nOverwrite them?", urlsString); 0524 case ExistingFinishedTransfer: 0525 return i18n("You have already completed downloads at those destinations: \n\n%1\n\n Download them again?", urlsString); 0526 case ExistingTransfer: 0527 return i18n("You have downloads in progress to these destinations: \n\n%1\n\nDelete them and download again?", urlsString); 0528 default: 0529 return QString(); 0530 } 0531 } 0532 if (type == Source) { 0533 switch (warning) { 0534 case ExistingFinishedTransfer: 0535 return i18n("You have already completed downloads from these locations: \n\n%1\n\nDownload them again?", urlsString); 0536 case ExistingTransfer: 0537 return i18n("You have downloads in progress from these locations: \n\n%1\n\nDelete them and download again?", urlsString); 0538 default: 0539 QString(); 0540 } 0541 } 0542 } 0543 0544 return QString(); 0545 } 0546 0547 QList<QUrl> UrlChecker::hasExistingTransferMessages(const QList<QUrl> &urls, const UrlChecker::UrlType type) 0548 { 0549 UrlWarning warning; 0550 QHash<UrlWarning, QList<QPair<QUrl, TransferHandler *>>> splitWarnings; 0551 QList<QUrl> urlsToDownload; 0552 0553 // collect all errors 0554 foreach (const QUrl &url, urls) { 0555 TransferHandler *transfer = existingTransfer(url, type, &warning); 0556 if (transfer) { 0557 splitWarnings[warning] << qMakePair(url, transfer); 0558 } else { 0559 urlsToDownload << url; 0560 } 0561 } 0562 0563 // First ask about unfinished existing transfers 0564 QList<QPair<QUrl, TransferHandler *>>::const_iterator it; 0565 QList<QPair<QUrl, TransferHandler *>>::const_iterator itEnd; 0566 QList<UrlWarning> orderOfExecution; 0567 QList<TransferHandler *> toDelete; 0568 orderOfExecution << ExistingTransfer << ExistingFinishedTransfer; 0569 for (int i = 0; i < orderOfExecution.count(); ++i) { 0570 warning = orderOfExecution[i]; 0571 if (splitWarnings.contains(warning)) { 0572 QList<QPair<QUrl, TransferHandler *>> existing = splitWarnings[warning]; 0573 itEnd = existing.constEnd(); 0574 bool isYesAll = false; 0575 bool isNoAll = false; 0576 for (it = existing.constBegin(); it != itEnd; ++it) { 0577 if (isYesAll) { 0578 urlsToDownload << it->first; 0579 toDelete << it->second; 0580 continue; 0581 } 0582 0583 if (isNoAll) { 0584 break; 0585 } 0586 0587 int result; 0588 if (Settings::filesOverwrite() || (Settings::filesAutomaticRename() && (warning != ExistingTransfer))) { 0589 result = ExistingTransferDialog::ExistingDialogReturn::YesAll; 0590 } else { 0591 result = hasExistingDialog(it->first, type, warning); 0592 } 0593 switch (result) { 0594 case ExistingTransferDialog::ExistingDialogReturn::YesAll: 0595 isYesAll = true; 0596 // fallthrough 0597 case ExistingTransferDialog::ExistingDialogReturn::Yes: 0598 urlsToDownload << it->first; 0599 toDelete << it->second; 0600 break; 0601 case ExistingTransferDialog::ExistingDialogReturn::NoAll: 0602 isNoAll = true; 0603 case ExistingTransferDialog::ExistingDialogReturn::No: 0604 break; 0605 case ExistingTransferDialog::ExistingDialogReturn::Cancel: 0606 default: 0607 removeTransfers(toDelete); 0608 return urlsToDownload; 0609 } 0610 } 0611 } 0612 } 0613 0614 removeTransfers(toDelete); 0615 return urlsToDownload; 0616 } 0617 0618 void UrlChecker::removeTransfers(const QList<TransferHandler *> &toRemove) 0619 { 0620 QList<TransferHandler *> transfers = toRemove; 0621 transfers.removeAll(nullptr); 0622 if (!transfers.isEmpty()) { 0623 KGet::delTransfers(transfers); 0624 } 0625 } 0626 0627 int UrlChecker::hasExistingDialog(const QUrl &url, const UrlChecker::UrlType type, const UrlChecker::UrlWarning warning) 0628 { 0629 QWidget *parent = KGet::m_mainWindow; 0630 0631 // getting the caption 0632 QString caption; 0633 if (type == Source) { 0634 switch (warning) { 0635 case ExistingFinishedTransfer: 0636 caption = i18n("Delete it and download again?"); 0637 break; 0638 case ExistingTransfer: 0639 caption = i18n("Download it again?"); 0640 break; 0641 default: 0642 break; 0643 } 0644 } else if (type == Destination) { 0645 switch (warning) { 0646 case ExistingFinishedTransfer: 0647 case ExistingTransfer: 0648 caption = i18n("File already downloaded. Download anyway?"); 0649 break; 0650 case ExistingFile: 0651 caption = i18n("File already exists"); 0652 break; 0653 default: 0654 break; 0655 } 0656 } 0657 0658 QScopedPointer<QDialog> dialog(new ExistingTransferDialog(message(url, type, warning), caption, parent)); 0659 0660 return dialog->exec(); 0661 } 0662 0663 /// Non static methods following 0664 0665 void UrlChecker::clear() 0666 { 0667 m_correctUrls.clear(); 0668 m_splitErrorUrls.clear(); 0669 m_cancel = false; 0670 m_overwriteAll = false; 0671 m_autoRenameAll = false; 0672 m_skipAll = false; 0673 } 0674 0675 UrlChecker::UrlType UrlChecker::type() const 0676 { 0677 return m_type; 0678 } 0679 0680 void UrlChecker::setType(UrlChecker::UrlType type) 0681 { 0682 clear(); 0683 m_type = type; 0684 } 0685 0686 UrlChecker::UrlError UrlChecker::addUrl(const QUrl &url) 0687 { 0688 const UrlError error = checkUrl(url, m_type); 0689 if (error == NoError) { 0690 m_correctUrls << url; 0691 } else { 0692 m_splitErrorUrls[error] << url; 0693 } 0694 0695 return error; 0696 } 0697 0698 bool UrlChecker::addUrls(const QList<QUrl> &urls) 0699 { 0700 bool worked = true; 0701 foreach (const QUrl &url, urls) { 0702 const UrlError error = addUrl(url); 0703 if (error != NoError) { 0704 worked = false; 0705 } 0706 } 0707 0708 return worked; 0709 } 0710 0711 void UrlChecker::existingTransfers() 0712 { 0713 m_correctUrls = hasExistingTransferMessages(correctUrls(), m_type); 0714 } 0715 0716 QUrl UrlChecker::checkExistingFile(const QUrl &source, const QUrl &destination) 0717 { 0718 QUrl newDestination = destination; 0719 0720 // any url is ignored 0721 if (m_cancel) { 0722 return QUrl(); 0723 } 0724 0725 if (Settings::filesOverwrite()) { 0726 m_overwriteAll = true; 0727 } else if (Settings::filesAutomaticRename()) { 0728 m_autoRenameAll = true; 0729 } 0730 0731 if (wouldOverwrite(source, destination)) { 0732 KIO::RenameDialog_Options args = KIO::RenameDialog_MultipleItems | KIO::RenameDialog_Skip | KIO::RenameDialog_Overwrite; 0733 QScopedPointer<KIO::RenameDialog> dlg(new KIO::RenameDialog(KGet::m_mainWindow, i18n("File already exists"), source, destination, args)); 0734 0735 /// in the following cases no dialog needs to be shown 0736 if (m_skipAll) { // only existing are ignored 0737 return QUrl(); 0738 } else if (m_overwriteAll) { 0739 FileDeleter::deleteFile(newDestination); 0740 return newDestination; 0741 } else if (m_autoRenameAll) { 0742 newDestination = dlg->autoDestUrl(); 0743 return newDestination; 0744 } 0745 0746 /// now show the dialog and look at the result 0747 const int result = dlg->exec(); 0748 switch (result) { 0749 case KIO::Result_Overwrite: { 0750 // delete the file, that way it won't show up in future calls of this method 0751 FileDeleter::deleteFile(newDestination); 0752 return newDestination; 0753 } 0754 case KIO::Result_OverwriteAll: { 0755 // delete the file, that way it won't show up in future calls of this method 0756 FileDeleter::deleteFile(newDestination); 0757 m_overwriteAll = true; 0758 return newDestination; 0759 } 0760 case KIO::Result_Rename: 0761 // call it again, as there is no check on the user input 0762 return checkExistingFile(source, dlg->newDestUrl()); 0763 case KIO::Result_AutoRename: 0764 newDestination = dlg->autoDestUrl(); 0765 m_autoRenameAll = true; 0766 return newDestination; 0767 case KIO::Result_Skip: 0768 return QUrl(); 0769 case KIO::Result_AutoSkip: 0770 m_skipAll = true; 0771 return QUrl(); 0772 case KIO::Result_Cancel: 0773 m_cancel = true; 0774 return QUrl(); 0775 default: 0776 return QUrl(); 0777 } 0778 } 0779 0780 return newDestination; 0781 } 0782 0783 QList<QUrl> UrlChecker::correctUrls() const 0784 { 0785 return m_correctUrls; 0786 } 0787 0788 QList<QUrl> UrlChecker::errorUrls() const 0789 { 0790 QList<QUrl> urls; 0791 0792 QHash<UrlChecker::UrlError, QList<QUrl>>::const_iterator it; 0793 QHash<UrlChecker::UrlError, QList<QUrl>>::const_iterator itEnd = m_splitErrorUrls.constEnd(); 0794 for (it = m_splitErrorUrls.constBegin(); it != itEnd; ++it) { 0795 urls << (*it); 0796 } 0797 0798 return urls; 0799 } 0800 0801 QHash<UrlChecker::UrlError, QList<QUrl>> UrlChecker::splitErrorUrls() const 0802 { 0803 return m_splitErrorUrls; 0804 } 0805 0806 void UrlChecker::displayErrorMessages() 0807 { 0808 QHash<UrlChecker::UrlError, QList<QUrl>>::const_iterator it; 0809 QHash<UrlChecker::UrlError, QList<QUrl>>::const_iterator itEnd = m_splitErrorUrls.constEnd(); 0810 for (it = m_splitErrorUrls.constBegin(); it != itEnd; ++it) { 0811 QString m; 0812 if (it->count() > 1) { 0813 m = message(*it, m_type, it.key()); 0814 } else if (!it->isEmpty()) { 0815 m = message(it->first(), m_type, it.key()); 0816 } 0817 0818 if (!m.isEmpty()) { 0819 KGet::showNotification("error", m); 0820 } 0821 } 0822 } 0823 0824 #include "moc_urlchecker_p.cpp"