File indexing completed on 2023-10-01 08:39:45
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 <KLocalizedString> 0037 #include <KWindowSystem> 0038 #include <LineEditUrlDropEventFilter> 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 LineEditUrlDropEventFilter(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, SIGNAL(currentIndexChanged(int)), this, SLOT(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 if (m_window) { 0254 KWindowInfo info(m_window->winId(), NET::WMDesktop); 0255 KWindowSystem::setCurrentDesktop(info.desktop()); 0256 KWindowSystem::forceActiveWindow(m_window->winId()); 0257 } 0258 0259 qCDebug(KGET_DEBUG) << "Show the dialog!"; 0260 show(); 0261 } 0262 0263 bool NewTransferDialog::isEmpty() 0264 { 0265 return (m_multiple ? !ui.listWidget->count() : ui.urlRequester->text().trimmed().isEmpty()); 0266 } 0267 0268 void NewTransferDialog::inputTimer() 0269 { 0270 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 0271 m_timer->start(); 0272 } 0273 0274 void NewTransferDialog::checkInput() 0275 { 0276 qDebug() << "Check input"; 0277 QUrl source = QUrl(ui.urlRequester->text().trimmed()); 0278 const QUrl dest = ui.destRequester->url(); 0279 0280 // check the destination folder 0281 UrlChecker::UrlError error = UrlChecker::checkFolder(dest); 0282 const bool folderValid = (error == UrlChecker::NoError); 0283 bool destinationValid = false; 0284 QString infoText; 0285 QString warningText; 0286 if (!folderValid) { 0287 if (m_multiple) { 0288 infoText = UrlChecker::message(QUrl(), UrlChecker::Folder, error); 0289 } else { 0290 // might be a destination instead of a folder 0291 destinationValid = (UrlChecker::checkDestination(dest) == UrlChecker::NoError); 0292 } 0293 } else { 0294 m_destination = dest; 0295 } 0296 0297 // check the source 0298 if (!m_multiple) { 0299 source = mostLocalUrl(source); 0300 } 0301 error = UrlChecker::checkSource(source); 0302 const bool sourceValid = (error == UrlChecker::NoError); 0303 if (!m_multiple && !sourceValid) { 0304 infoText = UrlChecker::message(QUrl(), UrlChecker::Source, error); 0305 } 0306 0307 // check if any sources are checked and for existing transfers or destinations 0308 bool filesChecked = false; 0309 if (m_multiple && folderValid) { 0310 QListWidget *list = ui.listWidget; 0311 0312 // check if some sources have been checked 0313 for (int i = 0; i < list->count(); ++i) { 0314 QListWidgetItem *item = list->item(i); 0315 if (item->checkState() == Qt::Checked) { 0316 filesChecked = true; 0317 break; 0318 } 0319 } 0320 if (!filesChecked) { 0321 infoText = i18n("Select at least one source url."); 0322 } 0323 0324 // check if there are existing files 0325 if (filesChecked) { 0326 bool existingFile = false; 0327 for (int i = 0; i < list->count(); ++i) { 0328 QListWidgetItem *item = list->item(i); 0329 const QUrl source = QUrl(item->text()); 0330 const QUrl destUrl = UrlChecker::destUrl(dest, source); 0331 if (UrlChecker::wouldOverwrite(source, destUrl)) { 0332 item->setBackground(m_existingFileBackground); 0333 existingFile = true; 0334 } else { 0335 item->setBackground(m_normalBackground); 0336 } 0337 } 0338 if (existingFile) { 0339 warningText = i18n("Files that exist already in the current folder have been marked."); // TODO better message 0340 } 0341 } 0342 } 0343 0344 // single file 0345 UrlChecker::UrlWarning warning = UrlChecker::NoWarning; 0346 if (!m_multiple && sourceValid && (folderValid || destinationValid)) { 0347 m_destination = UrlChecker::destUrl(dest, source); 0348 // show only one message for existing transfers 0349 m_existingTransfer = UrlChecker::existingTransfer(source, UrlChecker::Source, &warning); 0350 if (m_existingTransfer) { 0351 warningText = UrlChecker::message(QUrl(), UrlChecker::Source, warning); 0352 } else { 0353 m_existingTransfer = UrlChecker::existingTransfer(m_destination, UrlChecker::Destination, &warning); 0354 if (m_existingTransfer) { 0355 warningText = UrlChecker::message(QUrl(), UrlChecker::Destination, warning); 0356 } 0357 } 0358 0359 if (UrlChecker::wouldOverwrite(QUrl(ui.urlRequester->text().trimmed()), m_destination)) { 0360 m_overWriteSingle = true; 0361 if (!warningText.isEmpty()) { 0362 warningText += '\n'; 0363 } 0364 warningText += UrlChecker::message(QUrl(), UrlChecker::Destination, UrlChecker::ExistingFile); 0365 } else { 0366 m_overWriteSingle = false; 0367 } 0368 } 0369 0370 if (!infoText.isEmpty()) { 0371 setInformation(infoText); 0372 } else if (!warningText.isEmpty()) { 0373 setWarning(warningText); 0374 } else { 0375 ui.errorWidget->hide(); 0376 } 0377 0378 // activate the ok button 0379 if (m_multiple) { 0380 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(folderValid && filesChecked); 0381 } else { 0382 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled((folderValid || destinationValid) && sourceValid); 0383 } 0384 0385 qCDebug(KGET_DEBUG) << source << source.fileName() << dest << dest.fileName() << "Folder valid:" << folderValid << "Destination valid:" << destinationValid 0386 << "Source valid:" << sourceValid; 0387 } 0388 0389 void NewTransferDialog::slotFinished(int resultCode) 0390 { 0391 if (resultCode == QDialog::Accepted) { 0392 dialogAccepted(); 0393 } 0394 clear(); 0395 } 0396 0397 void NewTransferDialog::dialogAccepted() 0398 { 0399 qCDebug(KGET_DEBUG) << "Dialog accepted."; 0400 0401 // an existing transfer has been specified and since ok was clicked, it was chosen to be overwritten 0402 if (m_existingTransfer) { 0403 qCDebug(KGET_DEBUG) << "Removing existing transfer:" << m_existingTransfer; 0404 KGet::delTransfer(m_existingTransfer); 0405 } 0406 0407 // set the last directory 0408 QString dir = m_destination.toLocalFile(); 0409 if (!QFileInfo(dir).isDir()) { 0410 dir = m_destination.adjusted(QUrl::RemoveFilename).toLocalFile(); 0411 } 0412 Settings::setLastDirectory(dir); 0413 Settings::self()->save(); 0414 0415 const QString group = ui.groupComboBox->currentText(); 0416 0417 /// add data to create transfers 0418 QList<KGet::TransferData> data; 0419 if (!m_multiple) { 0420 if (m_overWriteSingle) { 0421 qCDebug(KGET_DEBUG) << "Removing existing file:" << m_destination; 0422 // removes m_destination if it exists, do that here so that it is removed no matter if a transfer could be created or not 0423 // as the user decided to throw the file away 0424 FileDeleter::deleteFile(m_destination); 0425 } 0426 0427 // sourceUrl is valid, has been checked before 0428 const QUrl sourceUrl = QUrl(ui.urlRequester->text().trimmed()); 0429 qCDebug(KGET_DEBUG) << "Downloading" << sourceUrl << "to" << m_destination; 0430 data << KGet::TransferData(sourceUrl, m_destination, group, true); 0431 } else { 0432 QList<QUrl> list; 0433 for (int i = 0; i != ui.listWidget->count(); ++i) { 0434 QListWidgetItem *item = ui.listWidget->item(i); 0435 0436 // find selected sources 0437 if (item->checkState() == Qt::Checked) { 0438 // both sourceUrl and destUrl are valid, they have been tested in checkInput 0439 const QUrl sourceUrl = QUrl(item->text().trimmed()); 0440 const QUrl destUrl = UrlChecker::destUrl(m_destination, sourceUrl); 0441 qCDebug(KGET_DEBUG) << "Downloading" << sourceUrl << "to" << destUrl; 0442 0443 // file exists already, remove it 0444 if (item->background() == m_existingFileBackground) { 0445 qCDebug(KGET_DEBUG) << "Removing existing file:" << destUrl; 0446 // removes destUrl if it exists, do that here so that it is removed no matter if a transfer could be created or not 0447 // as the user decided to throw the file away 0448 FileDeleter::deleteFile(destUrl); 0449 } 0450 0451 data << KGet::TransferData(sourceUrl, destUrl, group, true); 0452 } 0453 } 0454 } 0455 0456 if (!data.isEmpty()) { 0457 Settings::setLastGroup(ui.groupComboBox->currentText()); 0458 KGet::createTransfers(data); 0459 } 0460 } 0461 0462 void NewTransferDialog::setInformation(const QString &information) 0463 { 0464 ui.errorWidget->setMessageType(KMessageWidget::Information); 0465 ui.errorWidget->setText(information); 0466 ui.errorWidget->setVisible(!information.isEmpty()); 0467 } 0468 0469 void NewTransferDialog::setWarning(const QString &warning) 0470 { 0471 ui.errorWidget->setMessageType(KMessageWidget::Warning); 0472 ui.errorWidget->setText(warning); 0473 ui.errorWidget->setVisible(!warning.isEmpty()); 0474 } 0475 0476 /** 0477 * NOTE some checks in this class might seem redundant, though target is to display as few dialogs, and then preferable 0478 * the NewTransferDialog, to the user as possible i.e. if not enough information -- e.g. no destination folder 0479 * determinable, ...-- is present for a url or a group of urls they won't be added as transfer, 0480 * instead the NewTransferDialog will be shown 0481 * 0482 * This also tries to add as many transfers as possible with one run, to ensure a high speed 0483 */ 0484 NewTransferDialogHandler::NewTransferDialogHandler(QObject *parent) 0485 : QObject(parent) 0486 , m_nextJobId(0) 0487 { 0488 } 0489 0490 NewTransferDialogHandler::~NewTransferDialogHandler() 0491 { 0492 } 0493 0494 void NewTransferDialogHandler::showNewTransferDialog(const QUrl &url) 0495 { 0496 showNewTransferDialog(url.isEmpty() ? QList<QUrl>() : QList<QUrl>() << url); 0497 } 0498 0499 void NewTransferDialogHandler::showNewTransferDialog(QList<QUrl> urls) 0500 { 0501 if (urls.isEmpty()) { 0502 newTransferDialogHandler->createDialog(urls, QString()); 0503 return; 0504 } 0505 0506 QHash<int, UrlData>::iterator itUrls = newTransferDialogHandler->m_urls.insert(newTransferDialogHandler->m_nextJobId, UrlData()); 0507 QString folder; 0508 QString suggestedFileName; 0509 0510 /// Only two urls defined, check if second one is a path or a file name 0511 if (urls.count() == 2) { 0512 const QUrl lastUrl = urls.last(); 0513 QDir dir(lastUrl.toLocalFile()); 0514 0515 // check if last url is a file path, either absolute or relative 0516 if (lastUrl.isLocalFile()) { 0517 if (QDir::isAbsolutePath(lastUrl.toLocalFile())) { 0518 if (dir.exists()) { 0519 // second url is a folder path 0520 folder = lastUrl.adjusted(QUrl::RemoveFilename).toString(); 0521 } else { 0522 // second url is a file path, use this one 0523 folder = lastUrl.adjusted(QUrl::RemoveFilename).toString(); 0524 suggestedFileName = lastUrl.fileName(); 0525 } 0526 urls.removeLast(); 0527 } else { 0528 // second url is just a file name 0529 suggestedFileName = lastUrl.fileName(); 0530 urls.removeLast(); 0531 } 0532 } else if (!lastUrl.isValid() || (lastUrl.scheme().isEmpty() && lastUrl.adjusted(QUrl::RemoveFilename).isEmpty())) { 0533 // Sometimes valid filenames are not recognized by KURL::isLocalFile(), they are marked as invalid then 0534 suggestedFileName = lastUrl.url(); 0535 urls.removeLast(); 0536 } 0537 } 0538 0539 /// More than two urls defined, and last is local and will be used as destination directory 0540 if (urls.count() > 2 && urls.last().isLocalFile()) { 0541 /** 0542 * FIXME should the code be uncommented again, though then inputting a wrong destination like 0543 * ~/Downloads/folderNotExisting would result in ~/Downloads/ instead of informing the user 0544 * and giving them the possibility to improve their mistake 0545 */ 0546 // if (!QFileInfo(urls.last().toLocalFile()).isDir()) { 0547 // folder = urls.last().directory(QUrl::AppendTrailingSlash); 0548 // } else { 0549 folder = urls.last().adjusted(QUrl::RemoveFilename).toString(); // checks if that folder is correct happen later 0550 // } 0551 urls.removeLast(); 0552 } 0553 0554 // add a folder or suggestedFileName if they are valid 0555 if (!folder.isEmpty() && KGet::isValidDestDirectory(folder)) { 0556 (*itUrls).folder = folder; 0557 } 0558 if (!suggestedFileName.isEmpty()) { 0559 (*itUrls).suggestedFileName = QUrl(suggestedFileName).toString(); // pathOrUrl to get a non percent encoded url 0560 } 0561 0562 newTransferDialogHandler->m_numJobs[newTransferDialogHandler->m_nextJobId] = urls.count(); 0563 foreach (const QUrl &url, urls) { 0564 // needed to avoid when protocols like the desktop protocol is used, see bko:185283 0565 KIO::Job *job = mostLocalUrlJob(url); 0566 job->setProperty("jobId", (newTransferDialogHandler->m_nextJobId)); 0567 connect(job, SIGNAL(result(KJob *)), newTransferDialogHandler, SLOT(slotMostLocalUrlResult(KJob *))); 0568 job->start(); 0569 } 0570 0571 ++(newTransferDialogHandler->m_nextJobId); 0572 } 0573 0574 void NewTransferDialogHandler::slotMostLocalUrlResult(KJob *j) 0575 { 0576 auto *job = static_cast<MostLocalUrlJob *>(j); 0577 const int jobId = job->property("jobId").toInt(); 0578 0579 if (job->error()) { 0580 qCWarning(KGET_DEBUG) << "An error happened for" << job->url(); 0581 } else { 0582 m_urls[jobId].urls << job->mostLocalUrl(); 0583 } 0584 --m_numJobs[jobId]; 0585 0586 if (m_numJobs[jobId] <= 0) { 0587 handleUrls(jobId); 0588 } 0589 } 0590 0591 void NewTransferDialogHandler::handleUrls(const int jobId) 0592 { 0593 QHash<int, UrlData>::iterator itUrls = m_urls.find(jobId); 0594 if (itUrls == m_urls.end()) { 0595 qCWarning(KGET_DEBUG) << "JobId" << jobId << "was not defined, could not handle urls for it."; 0596 return; 0597 } 0598 0599 QList<QUrl> urls = (*itUrls).urls; 0600 UrlChecker::removeDuplicates(urls); 0601 0602 QString folder = (*itUrls).folder; 0603 if (!folder.isEmpty() && (UrlChecker::checkFolder(QUrl::fromLocalFile(folder), true) != UrlChecker::NoError)) { 0604 folder.clear(); 0605 } 0606 0607 const QString suggestedFileName = (*itUrls).suggestedFileName; 0608 QUrl newDest; 0609 const QUrl folderUrl = QUrl::fromLocalFile(folder); 0610 0611 // check if the sources are correct 0612 UrlChecker check(UrlChecker::Source); 0613 check.addUrls(urls); 0614 check.displayErrorMessages(); 0615 check.existingTransfers(); 0616 urls = check.correctUrls(); 0617 0618 QList<KGet::TransferData> data; 0619 0620 /// Just one file to download, with a specified suggestedFileName, handle if possible 0621 if (!suggestedFileName.isEmpty() && (urls.count() == 1)) { 0622 const QUrl sourceUrl = urls.first(); 0623 const QList<TransferGroupHandler *> groups = KGet::groupsFromExceptions(sourceUrl); 0624 const QString groupName = (groups.isEmpty() ? QString() : groups.first()->name()); 0625 QString defaultFolder; 0626 if (groups.isEmpty()) { 0627 defaultFolder = (Settings::askForDestination() ? QString() : QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)); 0628 } else { 0629 defaultFolder = groups.first()->defaultFolder(); 0630 } 0631 0632 if (!folder.isEmpty()) { 0633 const QUrl destUrl = UrlChecker::destUrl(QUrl::fromLocalFile(folder), sourceUrl, suggestedFileName); 0634 newDest = check.checkExistingFile(sourceUrl, destUrl); 0635 if (!newDest.isEmpty()) { 0636 data << KGet::TransferData(sourceUrl, newDest, groupName); 0637 } 0638 urls.removeFirst(); 0639 } else if (((!groups.isEmpty() && !Settings::directoriesAsSuggestion()) || !Settings::askForDestination()) 0640 && (UrlChecker::checkFolder(QUrl::fromLocalFile(defaultFolder)) == UrlChecker::NoError)) { 0641 const QUrl destUrl = UrlChecker::destUrl(QUrl::fromLocalFile(defaultFolder), sourceUrl, suggestedFileName); 0642 newDest = check.checkExistingFile(sourceUrl, destUrl); 0643 if (!newDest.isEmpty()) { 0644 data << KGet::TransferData(sourceUrl, newDest, groupName); 0645 } 0646 urls.removeFirst(); 0647 } 0648 } 0649 0650 /// A valid folder has been defined, use that for downloading 0651 if (!folder.isEmpty()) { 0652 // find the associated groups first, we just need the first matching group though 0653 const QList<TransferGroupHandler *> groups = KGet::allTransferGroups(); 0654 foreach (TransferGroupHandler *group, groups) { 0655 if (urls.isEmpty()) { 0656 break; 0657 } 0658 0659 const QString groupName = group->name(); 0660 const QStringList patterns = group->regExp().pattern().split(','); 0661 0662 // find all urls where a group can be identified 0663 QList<QUrl>::iterator it = urls.begin(); 0664 while (it != urls.end()) { 0665 const QUrl sourceUrl = *it; 0666 if (KGet::matchesExceptions(sourceUrl, patterns)) { 0667 const QUrl destUrl = UrlChecker::destUrl(folderUrl, sourceUrl); 0668 newDest = check.checkExistingFile(sourceUrl, destUrl); 0669 if (!newDest.isEmpty()) { 0670 data << KGet::TransferData(sourceUrl, newDest, groupName); 0671 } 0672 it = urls.erase(it); 0673 } else { 0674 ++it; 0675 } 0676 } 0677 } 0678 0679 // there are still some unhandled urls, i.e. for those no group could be found, add them with an empty group 0680 foreach (const QUrl &sourceUrl, urls) { 0681 const QUrl destUrl = UrlChecker::destUrl(folderUrl, sourceUrl); 0682 newDest = check.checkExistingFile(sourceUrl, destUrl); 0683 if (!newDest.isEmpty()) { 0684 data << KGet::TransferData(sourceUrl, newDest); 0685 } 0686 } 0687 0688 // all urls have been handled 0689 urls.clear(); 0690 } 0691 0692 /// Now handle default folders/groups 0693 qCDebug(KGET_DEBUG) << "DIRECTORIES AS SUGGESTION" << Settings::directoriesAsSuggestion(); 0694 if (!Settings::directoriesAsSuggestion() && !urls.isEmpty()) { 0695 qCDebug(KGET_DEBUG) << "No, Directories not as suggestion"; 0696 0697 // find the associated groups first, we just need the first matching group though 0698 const QList<TransferGroupHandler *> groups = KGet::allTransferGroups(); 0699 foreach (TransferGroupHandler *group, groups) { 0700 if (urls.isEmpty()) { 0701 break; 0702 } 0703 0704 const QUrl folderUrl = QUrl::fromLocalFile(group->defaultFolder()); 0705 if (UrlChecker::checkFolder(folderUrl) != UrlChecker::NoError) { 0706 continue; 0707 } 0708 0709 const QString groupName = group->name(); 0710 const QStringList patterns = group->regExp().pattern().split(','); 0711 0712 QList<QUrl>::iterator it = urls.begin(); 0713 while (it != urls.end()) { 0714 const QUrl sourceUrl = *it; 0715 if (KGet::matchesExceptions(sourceUrl, patterns)) { 0716 const QUrl destUrl = UrlChecker::destUrl(folderUrl, sourceUrl); 0717 newDest = check.checkExistingFile(sourceUrl, destUrl); 0718 if (!newDest.isEmpty()) { 0719 data << KGet::TransferData(sourceUrl, newDest, groupName); 0720 } 0721 0722 it = urls.erase(it); 0723 } else { 0724 ++it; 0725 } 0726 } 0727 } 0728 } 0729 0730 /// Download the rest of the urls to QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) if the user is not aksed for a destination 0731 if (!Settings::askForDestination()) { 0732 // the download path will be always used 0733 const QString dir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); 0734 if (!dir.isEmpty()) { 0735 QList<QUrl>::iterator it = urls.begin(); 0736 while (it != urls.end()) { 0737 const QUrl sourceUrl = *it; 0738 const QUrl destUrl = UrlChecker::destUrl(QUrl::fromLocalFile(dir), sourceUrl); 0739 newDest = check.checkExistingFile(sourceUrl, destUrl); 0740 if (!newDest.isEmpty()) { 0741 data << KGet::TransferData(sourceUrl, newDest); 0742 } 0743 0744 it = urls.erase(it); 0745 } 0746 } 0747 } 0748 0749 /// Now create transfers for the urls that provided enough data 0750 if (!data.isEmpty()) { 0751 KGet::createTransfers(data); 0752 } 0753 0754 /// Handle custom newtransferdialogs... 0755 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? 0756 QUrl url = urls.first(); 0757 QPointer<QDialog> dialog; 0758 foreach (TransferFactory *factory, KGet::factories()) { 0759 const QList<TransferGroupHandler *> groups = KGet::groupsFromExceptions(url); 0760 dialog = factory->createNewTransferDialog(url, suggestedFileName, !groups.isEmpty() ? groups.first() : nullptr); 0761 if (dialog) { 0762 KWindowInfo info(KGet::m_mainWindow->winId(), NET::WMDesktop); 0763 KWindowSystem::setCurrentDesktop(info.desktop()); 0764 KWindowSystem::forceActiveWindow(KGet::m_mainWindow->winId()); 0765 0766 dialog->exec(); 0767 delete dialog; 0768 } 0769 } 0770 } 0771 0772 m_numJobs.remove(jobId); 0773 m_urls.erase(itUrls); 0774 0775 /// Display default NewTransferDialog 0776 if (!urls.isEmpty()) { 0777 createDialog(urls, suggestedFileName); 0778 } 0779 } 0780 0781 void NewTransferDialogHandler::createDialog(const QList<QUrl> &urls, const QString &suggestedFileName) 0782 { 0783 if (!m_dialog) { 0784 m_dialog = new NewTransferDialog(KGet::m_mainWindow); 0785 } 0786 0787 m_dialog->m_window = KGet::m_mainWindow; 0788 m_dialog->showDialog(urls, suggestedFileName); 0789 } 0790 0791 #include "moc_newtransferdialog.cpp"