File indexing completed on 2024-12-01 07:38:56
0001 /* This file is part of the KDE project 0002 0003 Copyright (C) 2005 Dario Massarin <nekkar@libero.it> 0004 Copyright (C) 2007 by Javier Goday <jgoday@gmail.com> 0005 Copyright (C) 2008 - 2009 by Lukas Appelhans <l.appelhans@gmx.de> 0006 Copyright (C) 2010 by Matthias Fuchs <mat69@gmx.net> 0007 0008 This program is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 */ 0013 0014 #include "newtransferdialog.h" 0015 0016 #include "core/filedeleter.h" 0017 #include "core/kget.h" 0018 #include "core/mostlocalurl.h" 0019 #include "core/plugin/transferfactory.h" 0020 #include "core/transfergrouphandler.h" 0021 #include "core/transfertreemodel.h" 0022 #include "core/urlchecker.h" 0023 #include "mainwindow.h" 0024 #include "settings.h" 0025 0026 #include "kget_debug.h" 0027 #include <QDebug> 0028 0029 #include <QApplication> 0030 #include <QClipboard> 0031 #include <QDir> 0032 #include <QFileInfo> 0033 #include <QTimer> 0034 0035 #include <KColorScheme> 0036 #include <KLineEditUrlDropEventFilter> 0037 #include <KLocalizedString> 0038 #include <KWindowSystem> 0039 #include <QListWidgetItem> 0040 #include <QStandardPaths> 0041 0042 Q_GLOBAL_STATIC(NewTransferDialogHandler, newTransferDialogHandler) 0043 0044 NewTransferDialog::NewTransferDialog(QWidget *parent) 0045 : QDialog(parent) 0046 , m_window(nullptr) 0047 , m_existingTransfer(nullptr) 0048 , m_multiple(false) 0049 , m_overWriteSingle(false) 0050 { 0051 setModal(true); 0052 setWindowTitle(i18n("New Download")); 0053 0054 ui.setupUi(this); 0055 0056 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 0057 0058 // timer to avoid constant checking of the input 0059 m_timer = new QTimer(this); 0060 m_timer->setInterval(350); 0061 m_timer->setSingleShot(true); 0062 connect(m_timer, &QTimer::timeout, this, &NewTransferDialog::checkInput); 0063 0064 const KColorScheme scheme = KColorScheme(QPalette::Active, KColorScheme::View); 0065 m_existingFileBackground = scheme.background(KColorScheme::NeutralBackground); 0066 m_normalBackground = scheme.background(); 0067 0068 // properties of the m_destRequester combobox 0069 auto *dropUrlEventFilter = new KLineEditUrlDropEventFilter(this); 0070 dropUrlEventFilter->installEventFilter(ui.destRequester->comboBox()); 0071 ui.destRequester->comboBox()->setDuplicatesEnabled(false); 0072 ui.destRequester->comboBox()->setEditable(true); 0073 ui.destRequester->setAcceptMode(QFileDialog::AcceptSave); 0074 0075 ui.errorWidget->setCloseButtonVisible(false); 0076 0077 connect(ui.groupComboBox, &QComboBox::currentIndexChanged, this, &NewTransferDialog::setDefaultDestination); 0078 0079 connect(ui.urlRequester, &QLineEdit::textChanged, this, &NewTransferDialog::setDefaultDestination); 0080 connect(ui.destRequester, &KUrlRequester::textChanged, this, &NewTransferDialog::inputTimer); 0081 connect(ui.urlRequester, &QLineEdit::textChanged, this, &NewTransferDialog::inputTimer); 0082 connect(ui.listWidget, &QListWidget::itemChanged, this, &NewTransferDialog::inputTimer); 0083 connect(this, &QDialog::finished, this, &NewTransferDialog::slotFinished); 0084 connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 0085 connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0086 } 0087 0088 NewTransferDialog::~NewTransferDialog() 0089 { 0090 } 0091 0092 void NewTransferDialog::setMultiple(bool useMultiple) 0093 { 0094 m_multiple = useMultiple; 0095 0096 const Qt::Alignment alignment = Qt::AlignLeft | (m_multiple ? Qt::AlignTop : Qt::AlignVCenter); 0097 ui.urlLabel->setAlignment(alignment); 0098 ui.urlRequester->setVisible(!m_multiple); 0099 ui.listWidget->setVisible(m_multiple); 0100 ui.destRequester->setMode(m_multiple ? KFile::Directory : KFile::File); 0101 } 0102 0103 void NewTransferDialog::clear() 0104 { 0105 ui.urlRequester->clear(); 0106 ui.urlRequester->setFocus(); 0107 ui.listWidget->clear(); 0108 ui.destRequester->comboBox()->clear(); 0109 ui.destRequester->clear(); 0110 m_destination.clear(); 0111 m_sources.clear(); 0112 m_existingTransfer = nullptr; 0113 m_overWriteSingle = false; 0114 0115 // add all destinations 0116 QStringList list; 0117 QString downloadPath = KGet::generalDestDir(); 0118 if (!downloadPath.isEmpty()) { 0119 if (!downloadPath.endsWith('/')) { 0120 downloadPath.append('/'); 0121 } 0122 list << downloadPath; 0123 } 0124 foreach (TransferGroupHandler *handler, KGet::allTransferGroups()) { 0125 const QString folder = handler->defaultFolder(); 0126 if (!folder.isEmpty()) { 0127 list << (folder.endsWith('/') ? folder : folder + '/'); 0128 } 0129 } 0130 0131 list.removeDuplicates(); 0132 ui.destRequester->comboBox()->insertItems(0, list); 0133 0134 // add all transfer groups 0135 ui.groupComboBox->clear(); 0136 foreach (TransferGroupHandler *group, KGet::allTransferGroups()) { 0137 ui.groupComboBox->addItem(QIcon::fromTheme(group->iconName()), group->name()); 0138 } 0139 ui.groupComboBox->setCurrentItem(Settings::lastGroup()); 0140 if (ui.groupComboBox->currentIndex() == -1) { 0141 ui.groupComboBox->setCurrentIndex(0); 0142 } 0143 0144 const bool multipleGroups = KGet::transferGroupNames().count(); 0145 ui.groupComboBox->setVisible(multipleGroups); 0146 ui.groupLabel->setVisible(multipleGroups); 0147 } 0148 0149 void NewTransferDialog::setSource(const QList<QUrl> &sources) 0150 { 0151 if (sources.isEmpty()) { 0152 return; 0153 } 0154 0155 if (sources.count() == 1) { 0156 QUrl m_srcUrl = sources.first(); 0157 ui.urlRequester->clear(); 0158 if (m_srcUrl.isEmpty()) { 0159 m_srcUrl = QUrl(QApplication::clipboard()->text(QClipboard::Clipboard).trimmed()); 0160 } 0161 0162 if (UrlChecker::checkSource(m_srcUrl) == UrlChecker::NoError) { 0163 ui.urlRequester->insert(m_srcUrl.toString()); 0164 } 0165 } else { 0166 foreach (const QUrl &sourceUrl, sources) { 0167 if (sourceUrl.url() 0168 != QUrl(sourceUrl.url()) 0169 .fileName()) { // TODO simplify, whatfor is this check anyway, shouldn't the sources be checked already and if not add this to UrlChecker 0170 qCDebug(KGET_DEBUG) << "Insert" << sourceUrl; 0171 auto *newItem = new QListWidgetItem(sourceUrl.toString(), ui.listWidget); 0172 newItem->setCheckState(Qt::Checked); 0173 } 0174 } 0175 } 0176 0177 const QList<TransferGroupHandler *> groups = KGet::groupsFromExceptions(sources.first()); 0178 if (!groups.isEmpty()) { 0179 ui.groupComboBox->setCurrentIndex(ui.groupComboBox->findText(groups.first()->name())); 0180 } 0181 } 0182 0183 void NewTransferDialog::setDestinationFileName(const QString &filename) 0184 { 0185 ui.destRequester->setUrl(QUrl(ui.destRequester->url().adjusted(QUrl::RemoveFilename).toString() + filename)); 0186 } 0187 0188 void NewTransferDialog::setDestination() 0189 { 0190 // sets destRequester to either display the defaultFolder of group or the generalDestDir 0191 QString group = ui.groupComboBox->currentText(); 0192 TransferGroupHandler *current = nullptr; 0193 foreach (TransferGroupHandler *handler, KGet::allTransferGroups()) { 0194 if (handler->name() == group) { 0195 current = handler; 0196 break; 0197 } 0198 } 0199 0200 if (current) { 0201 QString groupFolder = current->defaultFolder(); 0202 if (groupFolder.isEmpty()) { 0203 groupFolder = KGet::generalDestDir(); 0204 } 0205 if (!groupFolder.endsWith('/')) { 0206 groupFolder.append('/'); 0207 } 0208 ui.destRequester->comboBox()->setCurrentItem(groupFolder, true); 0209 } 0210 } 0211 0212 void NewTransferDialog::showDialog(QList<QUrl> list, const QString &suggestedFileName) 0213 { 0214 // TODO handle the case where for some there are suggested file names --> own file name column in multiple setting 0215 // the dialog is already in use, adapt it 0216 if (isVisible()) { 0217 list << m_sources; 0218 } 0219 clear(); // Let's clear the old stuff 0220 m_sources << list; 0221 UrlChecker::removeDuplicates(m_sources); 0222 const int size = m_sources.size(); 0223 qCDebug(KGET_DEBUG) << "SET SOURCES " << m_sources << " MULTIPLE " << (size > 1); 0224 setMultiple(size > 1); 0225 0226 if (size) { 0227 if (size == 1 && !suggestedFileName.isEmpty()) { 0228 setDestinationFileName(suggestedFileName); 0229 } 0230 0231 setSource(m_sources); 0232 } 0233 0234 prepareDialog(); 0235 } 0236 0237 void NewTransferDialog::setDefaultDestination() 0238 { 0239 // NOTE if the user enters a file name manually and the changes the group the manually entered file name will be overwritten 0240 setDestination(); 0241 0242 // set a file name 0243 if (!m_multiple) { 0244 const QUrl url(ui.urlRequester->text().trimmed()); 0245 if ((UrlChecker::checkSource(url) == UrlChecker::NoError) && QFileInfo(ui.destRequester->url().toLocalFile()).isDir()) { 0246 setDestinationFileName(url.fileName()); 0247 } 0248 } 0249 } 0250 0251 void NewTransferDialog::prepareDialog() 0252 { 0253 qCDebug(KGET_DEBUG) << "Show the dialog!"; 0254 show(); 0255 } 0256 0257 bool NewTransferDialog::isEmpty() 0258 { 0259 return (m_multiple ? !ui.listWidget->count() : ui.urlRequester->text().trimmed().isEmpty()); 0260 } 0261 0262 void NewTransferDialog::inputTimer() 0263 { 0264 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 0265 m_timer->start(); 0266 } 0267 0268 void NewTransferDialog::checkInput() 0269 { 0270 qDebug() << "Check input"; 0271 QUrl source = QUrl(ui.urlRequester->text().trimmed()); 0272 const QUrl dest = ui.destRequester->url(); 0273 0274 // check the destination folder 0275 UrlChecker::UrlError error = UrlChecker::checkFolder(dest); 0276 const bool folderValid = (error == UrlChecker::NoError); 0277 bool destinationValid = false; 0278 QString infoText; 0279 QString warningText; 0280 if (!folderValid) { 0281 if (m_multiple) { 0282 infoText = UrlChecker::message(QUrl(), UrlChecker::Folder, error); 0283 } else { 0284 // might be a destination instead of a folder 0285 destinationValid = (UrlChecker::checkDestination(dest) == UrlChecker::NoError); 0286 } 0287 } else { 0288 m_destination = dest; 0289 } 0290 0291 // check the source 0292 if (!m_multiple) { 0293 source = mostLocalUrl(source); 0294 } 0295 error = UrlChecker::checkSource(source); 0296 const bool sourceValid = (error == UrlChecker::NoError); 0297 if (!m_multiple && !sourceValid) { 0298 infoText = UrlChecker::message(QUrl(), UrlChecker::Source, error); 0299 } 0300 0301 // check if any sources are checked and for existing transfers or destinations 0302 bool filesChecked = false; 0303 if (m_multiple && folderValid) { 0304 QListWidget *list = ui.listWidget; 0305 0306 // check if some sources have been checked 0307 for (int i = 0; i < list->count(); ++i) { 0308 QListWidgetItem *item = list->item(i); 0309 if (item->checkState() == Qt::Checked) { 0310 filesChecked = true; 0311 break; 0312 } 0313 } 0314 if (!filesChecked) { 0315 infoText = i18n("Select at least one source url."); 0316 } 0317 0318 // check if there are existing files 0319 if (filesChecked) { 0320 bool existingFile = false; 0321 for (int i = 0; i < list->count(); ++i) { 0322 QListWidgetItem *item = list->item(i); 0323 const QUrl source = QUrl(item->text()); 0324 const QUrl destUrl = UrlChecker::destUrl(dest, source); 0325 if (UrlChecker::wouldOverwrite(source, destUrl)) { 0326 item->setBackground(m_existingFileBackground); 0327 existingFile = true; 0328 } else { 0329 item->setBackground(m_normalBackground); 0330 } 0331 } 0332 if (existingFile) { 0333 warningText = i18n("Files that exist already in the current folder have been marked."); // TODO better message 0334 } 0335 } 0336 } 0337 0338 // single file 0339 UrlChecker::UrlWarning warning = UrlChecker::NoWarning; 0340 if (!m_multiple && sourceValid && (folderValid || destinationValid)) { 0341 m_destination = UrlChecker::destUrl(dest, source); 0342 // show only one message for existing transfers 0343 m_existingTransfer = UrlChecker::existingTransfer(source, UrlChecker::Source, &warning); 0344 if (m_existingTransfer) { 0345 warningText = UrlChecker::message(QUrl(), UrlChecker::Source, warning); 0346 } else { 0347 m_existingTransfer = UrlChecker::existingTransfer(m_destination, UrlChecker::Destination, &warning); 0348 if (m_existingTransfer) { 0349 warningText = UrlChecker::message(QUrl(), UrlChecker::Destination, warning); 0350 } 0351 } 0352 0353 if (UrlChecker::wouldOverwrite(QUrl(ui.urlRequester->text().trimmed()), m_destination)) { 0354 m_overWriteSingle = true; 0355 if (!warningText.isEmpty()) { 0356 warningText += '\n'; 0357 } 0358 warningText += UrlChecker::message(QUrl(), UrlChecker::Destination, UrlChecker::ExistingFile); 0359 } else { 0360 m_overWriteSingle = false; 0361 } 0362 } 0363 0364 if (!infoText.isEmpty()) { 0365 setInformation(infoText); 0366 } else if (!warningText.isEmpty()) { 0367 setWarning(warningText); 0368 } else { 0369 ui.errorWidget->hide(); 0370 } 0371 0372 // activate the ok button 0373 if (m_multiple) { 0374 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(folderValid && filesChecked); 0375 } else { 0376 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled((folderValid || destinationValid) && sourceValid); 0377 } 0378 0379 qCDebug(KGET_DEBUG) << source << source.fileName() << dest << dest.fileName() << "Folder valid:" << folderValid << "Destination valid:" << destinationValid 0380 << "Source valid:" << sourceValid; 0381 } 0382 0383 void NewTransferDialog::slotFinished(int resultCode) 0384 { 0385 if (resultCode == QDialog::Accepted) { 0386 dialogAccepted(); 0387 } 0388 clear(); 0389 } 0390 0391 void NewTransferDialog::dialogAccepted() 0392 { 0393 qCDebug(KGET_DEBUG) << "Dialog accepted."; 0394 0395 // an existing transfer has been specified and since ok was clicked, it was chosen to be overwritten 0396 if (m_existingTransfer) { 0397 qCDebug(KGET_DEBUG) << "Removing existing transfer:" << m_existingTransfer; 0398 KGet::delTransfer(m_existingTransfer); 0399 } 0400 0401 // set the last directory 0402 QString dir = m_destination.toLocalFile(); 0403 if (!QFileInfo(dir).isDir()) { 0404 dir = m_destination.adjusted(QUrl::RemoveFilename).toLocalFile(); 0405 } 0406 Settings::setLastDirectory(dir); 0407 Settings::self()->save(); 0408 0409 const QString group = ui.groupComboBox->currentText(); 0410 0411 /// add data to create transfers 0412 QList<KGet::TransferData> data; 0413 if (!m_multiple) { 0414 if (m_overWriteSingle) { 0415 qCDebug(KGET_DEBUG) << "Removing existing file:" << m_destination; 0416 // removes m_destination if it exists, do that here so that it is removed no matter if a transfer could be created or not 0417 // as the user decided to throw the file away 0418 FileDeleter::deleteFile(m_destination); 0419 } 0420 0421 // sourceUrl is valid, has been checked before 0422 const QUrl sourceUrl = QUrl(ui.urlRequester->text().trimmed()); 0423 qCDebug(KGET_DEBUG) << "Downloading" << sourceUrl << "to" << m_destination; 0424 data << KGet::TransferData(sourceUrl, m_destination, group, true); 0425 } else { 0426 QList<QUrl> list; 0427 for (int i = 0; i != ui.listWidget->count(); ++i) { 0428 QListWidgetItem *item = ui.listWidget->item(i); 0429 0430 // find selected sources 0431 if (item->checkState() == Qt::Checked) { 0432 // both sourceUrl and destUrl are valid, they have been tested in checkInput 0433 const QUrl sourceUrl = QUrl(item->text().trimmed()); 0434 const QUrl destUrl = UrlChecker::destUrl(m_destination, sourceUrl); 0435 qCDebug(KGET_DEBUG) << "Downloading" << sourceUrl << "to" << destUrl; 0436 0437 // file exists already, remove it 0438 if (item->background() == m_existingFileBackground) { 0439 qCDebug(KGET_DEBUG) << "Removing existing file:" << destUrl; 0440 // removes destUrl if it exists, do that here so that it is removed no matter if a transfer could be created or not 0441 // as the user decided to throw the file away 0442 FileDeleter::deleteFile(destUrl); 0443 } 0444 0445 data << KGet::TransferData(sourceUrl, destUrl, group, true); 0446 } 0447 } 0448 } 0449 0450 if (!data.isEmpty()) { 0451 Settings::setLastGroup(ui.groupComboBox->currentText()); 0452 KGet::createTransfers(data); 0453 } 0454 } 0455 0456 void NewTransferDialog::setInformation(const QString &information) 0457 { 0458 ui.errorWidget->setMessageType(KMessageWidget::Information); 0459 ui.errorWidget->setText(information); 0460 ui.errorWidget->setVisible(!information.isEmpty()); 0461 } 0462 0463 void NewTransferDialog::setWarning(const QString &warning) 0464 { 0465 ui.errorWidget->setMessageType(KMessageWidget::Warning); 0466 ui.errorWidget->setText(warning); 0467 ui.errorWidget->setVisible(!warning.isEmpty()); 0468 } 0469 0470 /** 0471 * NOTE some checks in this class might seem redundant, though target is to display as few dialogs, and then preferable 0472 * the NewTransferDialog, to the user as possible i.e. if not enough information -- e.g. no destination folder 0473 * determinable, ...-- is present for a url or a group of urls they won't be added as transfer, 0474 * instead the NewTransferDialog will be shown 0475 * 0476 * This also tries to add as many transfers as possible with one run, to ensure a high speed 0477 */ 0478 NewTransferDialogHandler::NewTransferDialogHandler(QObject *parent) 0479 : QObject(parent) 0480 , m_nextJobId(0) 0481 { 0482 } 0483 0484 NewTransferDialogHandler::~NewTransferDialogHandler() 0485 { 0486 } 0487 0488 void NewTransferDialogHandler::showNewTransferDialog(const QUrl &url) 0489 { 0490 showNewTransferDialog(url.isEmpty() ? QList<QUrl>() : QList<QUrl>() << url); 0491 } 0492 0493 void NewTransferDialogHandler::showNewTransferDialog(QList<QUrl> urls) 0494 { 0495 if (urls.isEmpty()) { 0496 newTransferDialogHandler->createDialog(urls, QString()); 0497 return; 0498 } 0499 0500 QHash<int, UrlData>::iterator itUrls = newTransferDialogHandler->m_urls.insert(newTransferDialogHandler->m_nextJobId, UrlData()); 0501 QString folder; 0502 QString suggestedFileName; 0503 0504 /// Only two urls defined, check if second one is a path or a file name 0505 if (urls.count() == 2) { 0506 const QUrl lastUrl = urls.last(); 0507 QDir dir(lastUrl.toLocalFile()); 0508 0509 // check if last url is a file path, either absolute or relative 0510 if (lastUrl.isLocalFile()) { 0511 if (QDir::isAbsolutePath(lastUrl.toLocalFile())) { 0512 if (dir.exists()) { 0513 // second url is a folder path 0514 folder = lastUrl.adjusted(QUrl::RemoveFilename).toString(); 0515 } else { 0516 // second url is a file path, use this one 0517 folder = lastUrl.adjusted(QUrl::RemoveFilename).toString(); 0518 suggestedFileName = lastUrl.fileName(); 0519 } 0520 urls.removeLast(); 0521 } else { 0522 // second url is just a file name 0523 suggestedFileName = lastUrl.fileName(); 0524 urls.removeLast(); 0525 } 0526 } else if (!lastUrl.isValid() || (lastUrl.scheme().isEmpty() && lastUrl.adjusted(QUrl::RemoveFilename).isEmpty())) { 0527 // Sometimes valid filenames are not recognized by KURL::isLocalFile(), they are marked as invalid then 0528 suggestedFileName = lastUrl.url(); 0529 urls.removeLast(); 0530 } 0531 } 0532 0533 /// More than two urls defined, and last is local and will be used as destination directory 0534 if (urls.count() > 2 && urls.last().isLocalFile()) { 0535 /** 0536 * FIXME should the code be uncommented again, though then inputting a wrong destination like 0537 * ~/Downloads/folderNotExisting would result in ~/Downloads/ instead of informing the user 0538 * and giving them the possibility to improve their mistake 0539 */ 0540 // if (!QFileInfo(urls.last().toLocalFile()).isDir()) { 0541 // folder = urls.last().directory(QUrl::AppendTrailingSlash); 0542 // } else { 0543 folder = urls.last().adjusted(QUrl::RemoveFilename).toString(); // checks if that folder is correct happen later 0544 // } 0545 urls.removeLast(); 0546 } 0547 0548 // add a folder or suggestedFileName if they are valid 0549 if (!folder.isEmpty() && KGet::isValidDestDirectory(folder)) { 0550 (*itUrls).folder = folder; 0551 } 0552 if (!suggestedFileName.isEmpty()) { 0553 (*itUrls).suggestedFileName = QUrl(suggestedFileName).toString(); // pathOrUrl to get a non percent encoded url 0554 } 0555 0556 newTransferDialogHandler->m_numJobs[newTransferDialogHandler->m_nextJobId] = urls.count(); 0557 foreach (const QUrl &url, urls) { 0558 // needed to avoid when protocols like the desktop protocol is used, see bko:185283 0559 KIO::Job *job = mostLocalUrlJob(url); 0560 job->setProperty("jobId", (newTransferDialogHandler->m_nextJobId)); 0561 connect(job, &KJob::result, newTransferDialogHandler, &NewTransferDialogHandler::slotMostLocalUrlResult); 0562 job->start(); 0563 } 0564 0565 ++(newTransferDialogHandler->m_nextJobId); 0566 } 0567 0568 void NewTransferDialogHandler::slotMostLocalUrlResult(KJob *j) 0569 { 0570 auto *job = static_cast<MostLocalUrlJob *>(j); 0571 const int jobId = job->property("jobId").toInt(); 0572 0573 if (job->error()) { 0574 qCWarning(KGET_DEBUG) << "An error happened for" << job->url(); 0575 } else { 0576 m_urls[jobId].urls << job->mostLocalUrl(); 0577 } 0578 --m_numJobs[jobId]; 0579 0580 if (m_numJobs[jobId] <= 0) { 0581 handleUrls(jobId); 0582 } 0583 } 0584 0585 void NewTransferDialogHandler::handleUrls(const int jobId) 0586 { 0587 QHash<int, UrlData>::iterator itUrls = m_urls.find(jobId); 0588 if (itUrls == m_urls.end()) { 0589 qCWarning(KGET_DEBUG) << "JobId" << jobId << "was not defined, could not handle urls for it."; 0590 return; 0591 } 0592 0593 QList<QUrl> urls = (*itUrls).urls; 0594 UrlChecker::removeDuplicates(urls); 0595 0596 QString folder = (*itUrls).folder; 0597 if (!folder.isEmpty() && (UrlChecker::checkFolder(QUrl::fromLocalFile(folder), true) != UrlChecker::NoError)) { 0598 folder.clear(); 0599 } 0600 0601 const QString suggestedFileName = (*itUrls).suggestedFileName; 0602 QUrl newDest; 0603 const QUrl folderUrl = QUrl::fromLocalFile(folder); 0604 0605 // check if the sources are correct 0606 UrlChecker check(UrlChecker::Source); 0607 check.addUrls(urls); 0608 check.displayErrorMessages(); 0609 check.existingTransfers(); 0610 urls = check.correctUrls(); 0611 0612 QList<KGet::TransferData> data; 0613 0614 /// Just one file to download, with a specified suggestedFileName, handle if possible 0615 if (!suggestedFileName.isEmpty() && (urls.count() == 1)) { 0616 const QUrl sourceUrl = urls.first(); 0617 const QList<TransferGroupHandler *> groups = KGet::groupsFromExceptions(sourceUrl); 0618 const QString groupName = (groups.isEmpty() ? QString() : groups.first()->name()); 0619 QString defaultFolder; 0620 if (groups.isEmpty()) { 0621 defaultFolder = (Settings::askForDestination() ? QString() : QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)); 0622 } else { 0623 defaultFolder = groups.first()->defaultFolder(); 0624 } 0625 0626 if (!folder.isEmpty()) { 0627 const QUrl destUrl = UrlChecker::destUrl(QUrl::fromLocalFile(folder), sourceUrl, suggestedFileName); 0628 newDest = check.checkExistingFile(sourceUrl, destUrl); 0629 if (!newDest.isEmpty()) { 0630 data << KGet::TransferData(sourceUrl, newDest, groupName); 0631 } 0632 urls.removeFirst(); 0633 } else if (((!groups.isEmpty() && !Settings::directoriesAsSuggestion()) || !Settings::askForDestination()) 0634 && (UrlChecker::checkFolder(QUrl::fromLocalFile(defaultFolder)) == UrlChecker::NoError)) { 0635 const QUrl destUrl = UrlChecker::destUrl(QUrl::fromLocalFile(defaultFolder), sourceUrl, suggestedFileName); 0636 newDest = check.checkExistingFile(sourceUrl, destUrl); 0637 if (!newDest.isEmpty()) { 0638 data << KGet::TransferData(sourceUrl, newDest, groupName); 0639 } 0640 urls.removeFirst(); 0641 } 0642 } 0643 0644 /// A valid folder has been defined, use that for downloading 0645 if (!folder.isEmpty()) { 0646 // find the associated groups first, we just need the first matching group though 0647 const QList<TransferGroupHandler *> groups = KGet::allTransferGroups(); 0648 foreach (TransferGroupHandler *group, groups) { 0649 if (urls.isEmpty()) { 0650 break; 0651 } 0652 0653 const QString groupName = group->name(); 0654 const QStringList patterns = group->regExp().pattern().split(','); 0655 0656 // find all urls where a group can be identified 0657 QList<QUrl>::iterator it = urls.begin(); 0658 while (it != urls.end()) { 0659 const QUrl sourceUrl = *it; 0660 if (KGet::matchesExceptions(sourceUrl, patterns)) { 0661 const QUrl destUrl = UrlChecker::destUrl(folderUrl, sourceUrl); 0662 newDest = check.checkExistingFile(sourceUrl, destUrl); 0663 if (!newDest.isEmpty()) { 0664 data << KGet::TransferData(sourceUrl, newDest, groupName); 0665 } 0666 it = urls.erase(it); 0667 } else { 0668 ++it; 0669 } 0670 } 0671 } 0672 0673 // there are still some unhandled urls, i.e. for those no group could be found, add them with an empty group 0674 foreach (const QUrl &sourceUrl, urls) { 0675 const QUrl destUrl = UrlChecker::destUrl(folderUrl, sourceUrl); 0676 newDest = check.checkExistingFile(sourceUrl, destUrl); 0677 if (!newDest.isEmpty()) { 0678 data << KGet::TransferData(sourceUrl, newDest); 0679 } 0680 } 0681 0682 // all urls have been handled 0683 urls.clear(); 0684 } 0685 0686 /// Now handle default folders/groups 0687 qCDebug(KGET_DEBUG) << "DIRECTORIES AS SUGGESTION" << Settings::directoriesAsSuggestion(); 0688 if (!Settings::directoriesAsSuggestion() && !urls.isEmpty()) { 0689 qCDebug(KGET_DEBUG) << "No, Directories not as suggestion"; 0690 0691 // find the associated groups first, we just need the first matching group though 0692 const QList<TransferGroupHandler *> groups = KGet::allTransferGroups(); 0693 foreach (TransferGroupHandler *group, groups) { 0694 if (urls.isEmpty()) { 0695 break; 0696 } 0697 0698 const QUrl folderUrl = QUrl::fromLocalFile(group->defaultFolder()); 0699 if (UrlChecker::checkFolder(folderUrl) != UrlChecker::NoError) { 0700 continue; 0701 } 0702 0703 const QString groupName = group->name(); 0704 const QStringList patterns = group->regExp().pattern().split(','); 0705 0706 QList<QUrl>::iterator it = urls.begin(); 0707 while (it != urls.end()) { 0708 const QUrl sourceUrl = *it; 0709 if (KGet::matchesExceptions(sourceUrl, patterns)) { 0710 const QUrl destUrl = UrlChecker::destUrl(folderUrl, sourceUrl); 0711 newDest = check.checkExistingFile(sourceUrl, destUrl); 0712 if (!newDest.isEmpty()) { 0713 data << KGet::TransferData(sourceUrl, newDest, groupName); 0714 } 0715 0716 it = urls.erase(it); 0717 } else { 0718 ++it; 0719 } 0720 } 0721 } 0722 } 0723 0724 /// Download the rest of the urls to QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) if the user is not aksed for a destination 0725 if (!Settings::askForDestination()) { 0726 // the download path will be always used 0727 const QString dir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); 0728 if (!dir.isEmpty()) { 0729 QList<QUrl>::iterator it = urls.begin(); 0730 while (it != urls.end()) { 0731 const QUrl sourceUrl = *it; 0732 const QUrl destUrl = UrlChecker::destUrl(QUrl::fromLocalFile(dir), sourceUrl); 0733 newDest = check.checkExistingFile(sourceUrl, destUrl); 0734 if (!newDest.isEmpty()) { 0735 data << KGet::TransferData(sourceUrl, newDest); 0736 } 0737 0738 it = urls.erase(it); 0739 } 0740 } 0741 } 0742 0743 /// Now create transfers for the urls that provided enough data 0744 if (!data.isEmpty()) { 0745 KGet::createTransfers(data); 0746 } 0747 0748 /// Handle custom newtransferdialogs... 0749 if ((!m_dialog || m_dialog->isEmpty()) && urls.count() == 1) { // FIXME why the m_dialog check? whenever a dialog has been created this would not be shown? 0750 QUrl url = urls.first(); 0751 QPointer<QDialog> dialog; 0752 foreach (TransferFactory *factory, KGet::factories()) { 0753 const QList<TransferGroupHandler *> groups = KGet::groupsFromExceptions(url); 0754 dialog = factory->createNewTransferDialog(url, suggestedFileName, !groups.isEmpty() ? groups.first() : nullptr); 0755 if (dialog) { 0756 dialog->exec(); 0757 delete dialog; 0758 } 0759 } 0760 } 0761 0762 m_numJobs.remove(jobId); 0763 m_urls.erase(itUrls); 0764 0765 /// Display default NewTransferDialog 0766 if (!urls.isEmpty()) { 0767 createDialog(urls, suggestedFileName); 0768 } 0769 } 0770 0771 void NewTransferDialogHandler::createDialog(const QList<QUrl> &urls, const QString &suggestedFileName) 0772 { 0773 if (!m_dialog) { 0774 m_dialog = new NewTransferDialog(KGet::m_mainWindow); 0775 } 0776 0777 m_dialog->m_window = KGet::m_mainWindow; 0778 m_dialog->showDialog(urls, suggestedFileName); 0779 } 0780 0781 #include "moc_newtransferdialog.cpp"