File indexing completed on 2023-10-03 07:54:00
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; 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); 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 m_runningTime.addSecs(m_runningSeconds); 0290 } 0291 if (jobStatus != Job::Running && status() == Job::Running) 0292 m_runningSeconds = m_runningTime.elapsed() / 1000; 0293 /** 0294 * It's important to call job::setStatus AFTER having changed the 0295 * icon or the text or whatever. 0296 * This because this function also notifies about this change 0297 * the scheduler which could also decide to change it another time 0298 * as well. For example if a job status is set to Aborted, the scheduler 0299 * could mark it to Delayed. This could trigger another icon or text 0300 * change which would be the right one since the status of the Job 0301 * has changed. If we set the icon or text after calling setStatus(), 0302 * we can overwrite the last icon or text change. 0303 */ 0304 Job::setStatus(jobStatus); 0305 } 0306 0307 void Transfer::setTransferChange(ChangesFlags change, bool postEvent) 0308 { 0309 if (change & Tc_DownloadedSize || change & Tc_Status) { 0310 change = change | Tc_RemainingTime; 0311 } 0312 handler()->setTransferChange(change, postEvent); 0313 } 0314 0315 QString Transfer::statusText(Job::Status status) 0316 { 0317 return STATUSTEXTS[status].name.toString(); 0318 } 0319 0320 QString Transfer::statusIconName(Job::Status status) 0321 { 0322 return STATUSICONS[status]; 0323 } 0324 0325 #include "moc_transfer.cpp"