File indexing completed on 2024-04-21 04:57:04

0001 /* This file is part of the KDE project
0002 
0003    Copyright (C) 2004 Dario Massarin <nekkar@libero.it>
0004    Copyright (C) 2008 - 2011 Lukas Appelhans <l.appelhans@gmx.de>
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/transfer.h"
0013 
0014 #include "settings.h"
0015 
0016 #include "core/plugin/transferfactory.h"
0017 #include "core/scheduler.h"
0018 #include "core/transferhandler.h"
0019 
0020 #include <KLazyLocalizedString>
0021 #include <KLocalizedString>
0022 #include <QDomElement>
0023 
0024 struct StatusStrings {
0025     KLazyLocalizedString name;
0026 };
0027 
0028 const StatusStrings STATUSTEXTS[] = {{kli18n("Downloading....")},
0029                                      {kli18nc("transfer state: delayed", "Delayed")},
0030                                      {kli18nc("transfer state: stopped", "Stopped")},
0031                                      {kli18nc("transfer state: aborted", "Aborted")},
0032                                      {kli18nc("transfer state: finished", "Finished")},
0033                                      {KLazyLocalizedString()}, // TODO: Add FinishedKeepAlive status
0034                                      {kli18nc("changing the destination of the file", "Changing destination")}};
0035 const QStringList STATUSICONS = QStringList() << "media-playback-start"
0036                                               << "view-history"
0037                                               << "process-stop"
0038                                               << "dialog-error"
0039                                               << "dialog-ok"
0040                                               << "media-playback-start"
0041                                               << "media-playback-pause";
0042 
0043 Transfer::Transfer(TransferGroup *parent, TransferFactory *factory, Scheduler *scheduler, const QUrl &source, const QUrl &dest, const QDomElement *e)
0044     : Job(scheduler, parent)
0045     , m_source(source)
0046     , m_dest(dest)
0047     , m_totalSize(0)
0048     , m_downloadedSize(0)
0049     , m_uploadedSize(0)
0050     , m_percent(0)
0051     , m_downloadSpeed(0)
0052     , m_uploadSpeed(0)
0053     , m_uploadLimit(0)
0054     , m_downloadLimit(0)
0055     , m_isSelected(false)
0056     , m_capabilities()
0057     , m_visibleUploadLimit(0)
0058     , m_visibleDownloadLimit(0)
0059     , m_runningSeconds(0)
0060     , m_ratio(0)
0061     , m_handler(nullptr)
0062     , m_factory(factory)
0063 {
0064     Q_UNUSED(e)
0065 }
0066 
0067 Transfer::~Transfer()
0068 {
0069 }
0070 
0071 void Transfer::setCapabilities(Capabilities capabilities)
0072 {
0073     if (m_capabilities != capabilities) {
0074         m_capabilities = capabilities;
0075         Q_EMIT capabilitiesChanged();
0076     }
0077 }
0078 
0079 void Transfer::create()
0080 {
0081     init();
0082 }
0083 
0084 void Transfer::destroy(DeleteOptions options)
0085 {
0086     deinit(options);
0087 }
0088 
0089 void Transfer::init() // TODO think about e, maybe not have it at all in the constructor?
0090 {
0091 }
0092 
0093 bool Transfer::setDirectory(const QUrl &newDirectory)
0094 {
0095     Q_UNUSED(newDirectory)
0096 
0097     // the standard implementation always returns false
0098     return false;
0099 }
0100 
0101 int Transfer::elapsedTime() const
0102 {
0103     if (status() == Job::Running)
0104         return m_runningTime.elapsed() / 1000 + m_runningSeconds;
0105 
0106     return m_runningSeconds;
0107 }
0108 
0109 int Transfer::averageDownloadSpeed() const
0110 {
0111     const int runningSeconds = elapsedTime();
0112     if (runningSeconds) {
0113         return m_totalSize / runningSeconds;
0114     }
0115 
0116     return 0;
0117 }
0118 
0119 QHash<QUrl, QPair<bool, int>> Transfer::availableMirrors(const QUrl &file) const
0120 {
0121     Q_UNUSED(file)
0122 
0123     QHash<QUrl, QPair<bool, int>> available;
0124     available[m_source] = QPair<bool, int>(true, 1);
0125     return available;
0126 }
0127 
0128 void Transfer::setUploadLimit(int ulLimit, SpeedLimit limit)
0129 {
0130     if (limit == Transfer::VisibleSpeedLimit) {
0131         m_visibleUploadLimit = ulLimit;
0132         if (ulLimit < m_uploadLimit || m_uploadLimit == 0)
0133             m_uploadLimit = ulLimit;
0134     } else {
0135         m_uploadLimit = ulLimit;
0136     }
0137 
0138     setSpeedLimits(m_uploadLimit, m_downloadLimit);
0139 }
0140 
0141 void Transfer::setDownloadLimit(int dlLimit, SpeedLimit limit)
0142 {
0143     if (limit == Transfer::VisibleSpeedLimit) {
0144         m_visibleDownloadLimit = dlLimit;
0145         if (dlLimit < m_downloadLimit || m_downloadLimit == 0)
0146             m_downloadLimit = dlLimit;
0147     } else {
0148         m_downloadLimit = dlLimit;
0149     }
0150 
0151     setSpeedLimits(m_uploadLimit, m_downloadLimit);
0152 }
0153 
0154 int Transfer::uploadLimit(SpeedLimit limit) const
0155 {
0156     if (limit == Transfer::VisibleSpeedLimit)
0157         return m_visibleUploadLimit;
0158 
0159     return m_uploadLimit;
0160 }
0161 
0162 int Transfer::downloadLimit(SpeedLimit limit) const
0163 {
0164     if (limit == Transfer::VisibleSpeedLimit)
0165         return m_visibleDownloadLimit;
0166 
0167     return m_downloadLimit;
0168 }
0169 
0170 void Transfer::setMaximumShareRatio(double ratio)
0171 {
0172     m_ratio = ratio;
0173     checkShareRatio();
0174 }
0175 
0176 void Transfer::checkShareRatio()
0177 {
0178     if (m_downloadedSize == 0 || m_ratio == 0)
0179         return;
0180 
0181     if ((double)m_uploadedSize / m_downloadedSize >= m_ratio)
0182         setDownloadLimit(1, Transfer::InvisibleSpeedLimit); // If we set it to 0 we would have no limit xD
0183     else
0184         setDownloadLimit(0, Transfer::InvisibleSpeedLimit);
0185 }
0186 
0187 void Transfer::setLog(const QString &message, Transfer::LogLevel level)
0188 {
0189     QString msg("<font color=\"blue\">" + QTime::currentTime().toString() + "</font> : ");
0190     if (level == Log_Error) {
0191         msg += "<font color=\"red\">" + message + "</font>";
0192     }
0193     if (level == Log_Warning) {
0194         msg += "<font color=\"yellow\">" + message + "</font>";
0195     } else {
0196         msg += message;
0197     }
0198     m_log << msg;
0199 }
0200 
0201 TransferHandler *Transfer::handler()
0202 {
0203     if (!m_handler)
0204         m_handler = m_factory->createTransferHandler(this, scheduler());
0205 
0206     return m_handler;
0207 }
0208 
0209 TransferTreeModel *Transfer::model()
0210 {
0211     return group()->model();
0212 }
0213 
0214 void Transfer::save(const QDomElement &element)
0215 {
0216     QDomElement e = element;
0217     e.setAttribute("Source", m_source.url());
0218     e.setAttribute("Dest", m_dest.url());
0219     e.setAttribute("TotalSize", m_totalSize);
0220     e.setAttribute("DownloadedSize", m_downloadedSize);
0221     e.setAttribute("UploadedSize", m_uploadedSize);
0222     e.setAttribute("DownloadLimit", m_visibleDownloadLimit);
0223     e.setAttribute("UploadLimit", m_visibleUploadLimit);
0224     e.setAttribute("ElapsedTime", status() == Job::Running ? m_runningTime.elapsed() / 1000 + m_runningSeconds : m_runningSeconds);
0225     e.setAttribute("Policy", policy() == Job::Start ? "Start" : (policy() == Job::Stop ? "Stop" : "None"));
0226 }
0227 
0228 void Transfer::load(const QDomElement *element)
0229 {
0230     if (!element) {
0231         setStatus(status(), i18nc("transfer state: stopped", "Stopped"), "process-stop");
0232         setStartStatus(status());
0233         return;
0234     }
0235 
0236     const QDomElement e = *element;
0237 
0238     m_source = QUrl(e.attribute("Source"));
0239     m_dest = QUrl(e.attribute("Dest"));
0240 
0241     m_totalSize = e.attribute("TotalSize").toULongLong();
0242     m_downloadedSize = e.attribute("DownloadedSize").toULongLong();
0243     m_uploadedSize = e.attribute("UploadedSize").toULongLong();
0244     m_percent = (m_totalSize ? ((100.0 * m_downloadedSize) / m_totalSize) : 0);
0245 
0246     if ((m_totalSize == m_downloadedSize) && (m_totalSize != 0)) {
0247         setStartStatus(Job::Finished);
0248         setStatus(startStatus());
0249     } else {
0250         setStatus(status(), i18nc("transfer state: stopped", "Stopped"), "process-stop");
0251         setStartStatus(status());
0252     }
0253     setUploadLimit(e.attribute("UploadLimit").toInt(), Transfer::VisibleSpeedLimit);
0254     setDownloadLimit(e.attribute("DownloadLimit").toInt(), Transfer::VisibleSpeedLimit);
0255     m_runningSeconds = e.attribute("ElapsedTime").toInt();
0256     if (Settings::startupAction() == 1) {
0257         setPolicy(Job::Start);
0258     } else if (Settings::startupAction() == 2) {
0259         setPolicy(Job::Stop);
0260     } else {
0261         if (e.attribute("Policy") == "Start")
0262             setPolicy(Job::Start);
0263         else if (e.attribute("Policy") == "Stop")
0264             setPolicy(Job::Stop);
0265         else
0266             setPolicy(Job::None);
0267     }
0268 }
0269 
0270 void Transfer::setStatus(Job::Status jobStatus, const QString &text, const QString &pix)
0271 {
0272     const bool statusChanged = (status() != jobStatus);
0273     QString statusText = text;
0274     if (statusText.isEmpty()) {
0275         statusText = KLocalizedString(STATUSTEXTS[jobStatus].name).toString();
0276     }
0277 
0278     // always prefer pix, if it is set
0279     if (!pix.isNull()) {
0280         m_statusIconName = pix;
0281     } else if (statusChanged || m_statusIconName.isNull()) {
0282         m_statusIconName = STATUSICONS[jobStatus];
0283     }
0284 
0285     m_statusText = statusText;
0286 
0287     if (jobStatus == Job::Running && status() != Job::Running) {
0288         m_runningTime.restart();
0289     }
0290     if (jobStatus != Job::Running && status() == Job::Running)
0291         m_runningSeconds = m_runningTime.elapsed() / 1000 + m_runningSeconds;
0292     /**
0293      * It's important to call job::setStatus AFTER having changed the
0294      * icon or the text or whatever.
0295      * This because this function also notifies about this change
0296      * the scheduler which could also decide to change it another time
0297      * as well. For example if a job status is set to Aborted, the scheduler
0298      * could mark it to Delayed. This could trigger another icon or text
0299      * change which would be the right one since the status of the Job
0300      * has changed. If we set the icon or text after calling setStatus(),
0301      * we can overwrite the last icon or text change.
0302      */
0303     Job::setStatus(jobStatus);
0304 }
0305 
0306 void Transfer::setTransferChange(ChangesFlags change, bool postEvent)
0307 {
0308     if (change & Tc_DownloadedSize || change & Tc_Status) {
0309         change = change | Tc_RemainingTime;
0310     }
0311     handler()->setTransferChange(change, postEvent);
0312 }
0313 
0314 QString Transfer::statusText(Job::Status status)
0315 {
0316     return STATUSTEXTS[status].name.toString();
0317 }
0318 
0319 QString Transfer::statusIconName(Job::Status status)
0320 {
0321     return STATUSICONS[status];
0322 }
0323 
0324 #include "moc_transfer.cpp"