File indexing completed on 2024-11-03 04:33:10

0001 /* This file is part of the KDE project
0002 
0003    Copyright (C) 2005 Dario Massarin <nekkar@libero.it>
0004    Copyright (C) 2010 Matthias Fuchs <mat69@gmx.net>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 */
0011 
0012 #include "core/transfergroup.h"
0013 
0014 #include "core/kget.h"
0015 #include "core/transfergrouphandler.h"
0016 
0017 #include "kget_debug.h"
0018 #include <KIO/Global>
0019 
0020 #include <QDomElement>
0021 
0022 TransferGroup::TransferGroup(TransferTreeModel *model, Scheduler *parent, const QString &name)
0023     : JobQueue(parent)
0024     , m_model(model)
0025     , m_name(name)
0026     , m_totalSize(0)
0027     , m_downloadedSize(0)
0028     , m_uploadedSize(0)
0029     , m_percent(0)
0030     , m_downloadSpeed(0)
0031     , m_uploadSpeed(0)
0032     , m_downloadLimit(0)
0033     , m_uploadLimit(0)
0034     , m_visibleDownloadLimit(0)
0035     , m_visibleUploadLimit(0)
0036     , m_iconName("bookmark-new-list")
0037     , m_defaultFolder()
0038 {
0039     m_handler = new TransferGroupHandler(parent, this);
0040 }
0041 
0042 TransferGroup::~TransferGroup()
0043 {
0044 }
0045 
0046 int TransferGroup::downloadSpeed()
0047 {
0048     m_downloadSpeed = 0;
0049     foreach (Job *job, runningJobs()) {
0050         auto *transfer = static_cast<Transfer *>(job);
0051         if (transfer)
0052             m_downloadSpeed += transfer->downloadSpeed();
0053     }
0054     return m_downloadSpeed;
0055 }
0056 
0057 int TransferGroup::uploadSpeed()
0058 {
0059     m_uploadSpeed = 0;
0060     foreach (Job *job, runningJobs()) {
0061         auto *transfer = static_cast<Transfer *>(job);
0062         if (transfer)
0063             m_uploadSpeed += transfer->uploadSpeed();
0064     }
0065     return m_uploadSpeed;
0066 }
0067 
0068 bool TransferGroup::supportsSpeedLimits()
0069 {
0070     QList<Job *> jobs = runningJobs();
0071     foreach (Job *job, jobs) {
0072         auto *transfer = static_cast<Transfer *>(job);
0073         if (!(transfer->capabilities() & Transfer::Cap_SpeedLimit)) {
0074             return false;
0075         }
0076     }
0077 
0078     // empty jobs can't support a speed limit
0079     return !jobs.isEmpty();
0080 }
0081 
0082 void TransferGroup::setStatus(Status queueStatus)
0083 {
0084     JobQueue::setStatus(queueStatus);
0085 
0086     m_handler->setGroupChange(Gc_Status, true);
0087 }
0088 
0089 void TransferGroup::append(Transfer *transfer)
0090 {
0091     JobQueue::append(transfer);
0092 
0093     calculateSpeedLimits();
0094 }
0095 
0096 void TransferGroup::append(const QList<Transfer *> &transfers)
0097 {
0098     QList<Job *> jobs;
0099     foreach (Transfer *transfer, transfers) {
0100         jobs << transfer;
0101     }
0102     JobQueue::append(jobs);
0103 
0104     calculateSpeedLimits();
0105 }
0106 
0107 void TransferGroup::prepend(Transfer *transfer)
0108 {
0109     JobQueue::prepend(transfer);
0110 
0111     calculateSpeedLimits();
0112 }
0113 
0114 void TransferGroup::insert(Transfer *transfer, Transfer *after)
0115 {
0116     JobQueue::insert(transfer, after);
0117 
0118     calculateSpeedLimits();
0119 }
0120 
0121 void TransferGroup::remove(Transfer *transfer)
0122 {
0123     JobQueue::remove(transfer);
0124 
0125     calculateSpeedLimits();
0126 }
0127 
0128 void TransferGroup::remove(const QList<Transfer *> &transfers)
0129 {
0130     QList<Job *> jobs;
0131     foreach (Transfer *transfer, transfers) {
0132         jobs << transfer;
0133     }
0134     JobQueue::remove(jobs);
0135 
0136     calculateSpeedLimits();
0137 }
0138 
0139 void TransferGroup::move(Transfer *transfer, Transfer *after)
0140 {
0141     if (transfer == after)
0142         return;
0143 
0144     JobQueue::move(transfer, after);
0145 }
0146 
0147 Transfer *TransferGroup::findTransfer(const QUrl &src)
0148 {
0149     iterator it = begin();
0150     iterator itEnd = end();
0151 
0152     for (; it != itEnd; ++it) {
0153         auto *t = (Transfer *)*it;
0154         if (t->source().url() == src.url())
0155             return t;
0156     }
0157     return nullptr;
0158 }
0159 
0160 Transfer *TransferGroup::findTransferByDestination(const QUrl &dest)
0161 {
0162     iterator it = begin();
0163     iterator itEnd = end();
0164 
0165     for (; it != itEnd; ++it) {
0166         auto *t = (Transfer *)*it;
0167         if (t->dest().url() == dest.url()) {
0168             return t;
0169         }
0170     }
0171     return nullptr;
0172 }
0173 
0174 void TransferGroup::setUploadLimit(int ulLimit, Transfer::SpeedLimit limit)
0175 {
0176     if (limit == Transfer::VisibleSpeedLimit) {
0177         m_visibleUploadLimit = ulLimit;
0178         if (ulLimit < m_uploadLimit || m_uploadLimit == 0)
0179             m_uploadLimit = ulLimit;
0180     } else {
0181         m_uploadLimit = ulLimit;
0182     }
0183 
0184     calculateUploadLimit();
0185 }
0186 
0187 void TransferGroup::setDownloadLimit(int dlLimit, Transfer::SpeedLimit limit)
0188 {
0189     if (limit == Transfer::VisibleSpeedLimit) {
0190         m_visibleDownloadLimit = dlLimit;
0191         if (dlLimit < m_downloadLimit || m_downloadLimit == 0)
0192             m_downloadLimit = dlLimit;
0193     } else {
0194         m_downloadLimit = dlLimit;
0195     }
0196 
0197     calculateDownloadLimit();
0198 }
0199 
0200 int TransferGroup::uploadLimit(Transfer::SpeedLimit limit) const
0201 {
0202     if (limit == Transfer::VisibleSpeedLimit)
0203         return m_visibleUploadLimit;
0204 
0205     return m_uploadLimit;
0206 }
0207 
0208 int TransferGroup::downloadLimit(Transfer::SpeedLimit limit) const
0209 {
0210     if (limit == Transfer::VisibleSpeedLimit)
0211         return m_visibleDownloadLimit;
0212 
0213     return m_downloadLimit;
0214 }
0215 
0216 void TransferGroup::calculateSpeedLimits()
0217 {
0218     qCDebug(KGET_DEBUG) << "We will calculate the new SpeedLimits now";
0219     calculateDownloadLimit();
0220     calculateUploadLimit();
0221 }
0222 
0223 void TransferGroup::calculateDownloadLimit()
0224 {
0225     qCDebug(KGET_DEBUG) << "Calculate new DownloadLimit of " + QString::number(m_downloadLimit);
0226     if (supportsSpeedLimits()) {
0227         const QList<Job *> running = runningJobs();
0228         int n = running.count();
0229         int pool = 0; // We create a pool where we have some KiB/s to go to other transfer's...
0230         QList<Transfer *> transfersNeedSpeed;
0231         foreach (Job *job, running) {
0232             auto *transfer = static_cast<Transfer *>(job);
0233             if (transfer) {
0234                 if (m_downloadLimit == 0 && transfer->downloadLimit(Transfer::VisibleSpeedLimit) != 0)
0235                     continue;
0236                 else if (m_downloadLimit == 0 && transfer->downloadLimit(Transfer::VisibleSpeedLimit) == 0)
0237                     transfer->setDownloadLimit(0, Transfer::InvisibleSpeedLimit);
0238                 else if (transfer->downloadLimit(Transfer::VisibleSpeedLimit) < m_downloadLimit / n
0239                          && transfer->downloadLimit(Transfer::VisibleSpeedLimit) != 0)
0240                     /*If the transfer's visible download limit is under the new one,
0241                                    we move the KiB/s which are different to the pool*/
0242                     pool = pool + (m_downloadLimit / n - transfer->downloadLimit(Transfer::VisibleSpeedLimit));
0243                 else if (transfer->downloadSpeed() + 10 < m_downloadLimit / n) {
0244                     /*When the downloadSpeed of the transfer is under the new downloadLimit + 10 then we
0245                         set the downloadLimit to the downloadSpeed + 10*/
0246                     pool = pool + m_downloadLimit / n - transfer->downloadSpeed() + 10;
0247                     transfer->setDownloadLimit(transfer->downloadSpeed() + 10, Transfer::InvisibleSpeedLimit);
0248                 } else {
0249                     transfer->setDownloadLimit(m_downloadLimit / n, Transfer::InvisibleSpeedLimit);
0250                     transfersNeedSpeed.append(transfer);
0251                 }
0252             }
0253         }
0254         foreach (Transfer *transfer, transfersNeedSpeed) {
0255             transfer->setDownloadLimit(m_downloadLimit / n + pool / transfersNeedSpeed.count(), Transfer::InvisibleSpeedLimit);
0256         }
0257     }
0258 }
0259 
0260 void TransferGroup::calculateUploadLimit()
0261 {
0262     qCDebug(KGET_DEBUG) << "Calculate new Upload Limit of " + QString::number(m_uploadLimit);
0263     if (supportsSpeedLimits()) {
0264         const QList<Job *> running = runningJobs();
0265         int n = running.count();
0266         int pool = 0; // We create a pool where we have some KiB/s to go to other transfer's...
0267         QList<Transfer *> transfersNeedSpeed;
0268         foreach (Job *job, running) {
0269             auto *transfer = static_cast<Transfer *>(job);
0270             if (transfer) {
0271                 if (m_uploadLimit == 0 && transfer->uploadLimit(Transfer::VisibleSpeedLimit) != 0)
0272                     continue;
0273                 else if (m_uploadLimit == 0 && transfer->uploadLimit(Transfer::VisibleSpeedLimit) == 0)
0274                     transfer->setUploadLimit(0, Transfer::InvisibleSpeedLimit);
0275                 else if (transfer->uploadLimit(Transfer::VisibleSpeedLimit) < m_uploadLimit / n && transfer->uploadLimit(Transfer::VisibleSpeedLimit) != 0)
0276                     /*If the transfer's visible upload limit is under the new one,
0277                                    we move the KiB/s which are different to the pool*/
0278                     pool = pool + (m_uploadLimit / n - transfer->uploadLimit(Transfer::VisibleSpeedLimit));
0279                 else if (transfer->uploadSpeed() + 10 < m_uploadLimit / n) {
0280                     /*When the uploadSpeed of the transfer is under the new uploadLimit + 10 then we
0281                         set the uploadLimit to the uploadSpeed + 10*/
0282                     pool = pool + m_uploadLimit / n - transfer->uploadSpeed() + 10;
0283                     transfer->setUploadLimit(transfer->uploadSpeed() + 10, Transfer::InvisibleSpeedLimit);
0284                 } else {
0285                     transfer->setUploadLimit(m_uploadLimit / n, Transfer::InvisibleSpeedLimit);
0286                     transfersNeedSpeed.append(transfer);
0287                 }
0288             }
0289         }
0290         foreach (Transfer *transfer, transfersNeedSpeed) {
0291             transfer->setUploadLimit(m_uploadLimit / n + pool / transfersNeedSpeed.count(), Transfer::InvisibleSpeedLimit);
0292         }
0293     }
0294 }
0295 
0296 void TransferGroup::save(QDomElement e) // krazy:exclude=passbyvalue
0297 {
0298     // qCDebug(KGET_DEBUG) << " -->  " << name();
0299 
0300     e.setAttribute("Name", m_name);
0301     e.setAttribute("DefaultFolder", m_defaultFolder);
0302     e.setAttribute("DownloadLimit", m_visibleDownloadLimit);
0303     e.setAttribute("UploadLimit", m_visibleUploadLimit);
0304     e.setAttribute("Icon", m_iconName);
0305     e.setAttribute("Status", status() == JobQueue::Running ? "Running" : "Stopped");
0306     e.setAttribute("RegExpPattern", m_regExp.pattern());
0307 
0308     iterator it = begin();
0309     iterator itEnd = end();
0310 
0311     for (; it != itEnd; ++it) {
0312         auto *transfer = static_cast<Transfer *>(*it);
0313         qCDebug(KGET_DEBUG) << "  -->  " << name() << "  transfer: " << transfer->source();
0314         QDomElement t = e.ownerDocument().createElement("Transfer");
0315         e.appendChild(t);
0316         transfer->save(t);
0317     }
0318 }
0319 
0320 void TransferGroup::load(const QDomElement &e)
0321 {
0322     qCDebug(KGET_DEBUG) << "TransferGroup::load";
0323 
0324     m_name = e.attribute("Name");
0325     m_defaultFolder = e.attribute("DefaultFolder");
0326     m_visibleDownloadLimit = e.attribute("DownloadLimit").toInt();
0327     m_visibleUploadLimit = e.attribute("UploadLimit").toInt();
0328     if (!e.attribute("Icon").isEmpty())
0329         m_iconName = e.attribute("Icon");
0330 
0331     if (e.attribute("Status") == "Running")
0332         setStatus(JobQueue::Running);
0333     else
0334         setStatus(JobQueue::Stopped);
0335 
0336     m_regExp.setPattern(e.attribute("RegExpPattern"));
0337 
0338     QDomNodeList nodeList = e.elementsByTagName("Transfer");
0339     int nItems = nodeList.length();
0340 
0341     QList<QDomElement> elements;
0342     for (int i = 0; i < nItems; ++i) {
0343         elements << nodeList.item(i).toElement();
0344     }
0345 
0346     qCDebug(KGET_DEBUG) << "TransferGroup::load ->"
0347                         << "add" << nItems << "transfers";
0348     KGet::addTransfers(elements, name());
0349 }
0350 
0351 #include "moc_transfergroup.cpp"