transfer.cpp 9.25 KB
Newer Older
1
/* This file is part of the KDE project
2

3
   Copyright (C) 2004 Dario Massarin <nekkar@libero.it>
4
   Copyright (C) 2008 - 2011 Lukas Appelhans <l.appelhans@gmx.de>
5
6
7

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
8
9
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
10
11
*/

Dario Massarin's avatar
Dario Massarin committed
12
#include "core/transfer.h"
Urs Wolfer's avatar
Urs Wolfer committed
13

14
15
#include "settings.h"

Dario Massarin's avatar
Dario Massarin committed
16
#include "core/transferhandler.h"
17
#include "core/plugin/transferfactory.h"
Dario Massarin's avatar
Dario Massarin committed
18
#include "core/scheduler.h"
19

20
#include <KIconLoader>
Laurent Montel's avatar
Laurent Montel committed
21
#include <KLocalizedString>
Urs Wolfer's avatar
Urs Wolfer committed
22
23

#include <QDomElement>
Andreas Pakulat's avatar
Andreas Pakulat committed
24
#include <QTime>
Urs Wolfer's avatar
Urs Wolfer committed
25

26
27
28
29
30
31
32
33
struct StatusStrings
{
    const char * context;
    const char * name;
};

const StatusStrings STATUSTEXTS[] = {
    {"", I18N_NOOP("Downloading....")},
Laurent Montel's avatar
Laurent Montel committed
34
35
36
37
    {I18NC_NOOP("transfer state: delayed", "Delayed")},
    {I18NC_NOOP("transfer state: stopped", "Stopped")},
    {I18NC_NOOP("transfer state: aborted", "Aborted")},
    {I18NC_NOOP("transfer state: finished", "Finished")},
38
    {"", ""},//TODO: Add FinishedKeepAlive status
Laurent Montel's avatar
Laurent Montel committed
39
    {I18NC_NOOP("changing the destination of the file", "Changing destination")}
40
};
41
const QStringList STATUSICONS = QStringList() << "media-playback-start" << "view-history" << "process-stop" << "dialog-error" << "dialog-ok" << "media-playback-start" << "media-playback-pause";
Matthias Fuchs's avatar
Matthias Fuchs committed
42

Dario Massarin's avatar
Dario Massarin committed
43
Transfer::Transfer(TransferGroup * parent, TransferFactory * factory,
Lukas Appelhans's avatar
Lukas Appelhans committed
44
                   Scheduler * scheduler, const QUrl & source, const QUrl & dest,
Dario Massarin's avatar
Dario Massarin committed
45
                   const QDomElement * e)
46
    : Job(scheduler, parent),
Dario Massarin's avatar
Dario Massarin committed
47
      m_source(source), m_dest(dest),
48
49
      m_totalSize(0), m_downloadedSize(0), m_uploadedSize(0),
      m_percent(0), m_downloadSpeed(0), m_uploadSpeed(0),
Lukas Appelhans's avatar
Lukas Appelhans committed
50
      m_uploadLimit(0), m_downloadLimit(0), m_isSelected(false),
51
      m_capabilities(0), m_visibleUploadLimit(0), m_visibleDownloadLimit(0),
52
      m_runningSeconds(0), m_ratio(0), m_handler(nullptr), m_factory(factory)
Matthias Fuchs's avatar
Matthias Fuchs committed
53
54
{
    Q_UNUSED(e)
55
56
}

Stephan Kulow's avatar
Stephan Kulow committed
57
58
59
60
Transfer::~Transfer()
{
}

61
62
void Transfer::setCapabilities(Capabilities capabilities)
{
63
64
65
66
    if (m_capabilities != capabilities) {
        m_capabilities = capabilities;
        emit capabilitiesChanged();
    }
67
68
}

69
void Transfer::create()
Matthias Fuchs's avatar
Matthias Fuchs committed
70
{
71
72
73
    init();
}

Matthias Fuchs's avatar
Matthias Fuchs committed
74
void Transfer::destroy(DeleteOptions options)
75
{
Matthias Fuchs's avatar
Matthias Fuchs committed
76
    deinit(options);
77

78
79
80
81
82
}

void Transfer::init()//TODO think about e, maybe not have it at all in the constructor?
{

Matthias Fuchs's avatar
Matthias Fuchs committed
83
84
85
}


Lukas Appelhans's avatar
Lukas Appelhans committed
86
bool Transfer::setDirectory(const QUrl& newDirectory)
87
{
Matthias Fuchs's avatar
Matthias Fuchs committed
88
    Q_UNUSED(newDirectory)
89

Yuri Chornoivan's avatar
Yuri Chornoivan committed
90
    //the standard implementation always returns false
91
92
93
    return false;
}

94
95
96
97
98
99
100
101
int Transfer::elapsedTime() const
{
    if (status() == Job::Running)
        return m_runningTime.elapsed() / 1000;

    return m_runningSeconds;
}

102
103
104
105
106
107
108
109
110
111
112
int Transfer::averageDownloadSpeed() const
{
    const int runningSeconds = elapsedTime();
    if (runningSeconds)
    {
        return m_totalSize / runningSeconds;
    }

    return 0;
}

Lukas Appelhans's avatar
Lukas Appelhans committed
113
QHash<QUrl, QPair<bool, int> > Transfer::availableMirrors(const QUrl &file) const
114
115
116
{
    Q_UNUSED(file)

Lukas Appelhans's avatar
Lukas Appelhans committed
117
    QHash<QUrl, QPair<bool, int> > available;
118
119
120
121
    available[m_source] = QPair<bool, int>(true, 1);
    return available;
}

Lukas Appelhans's avatar
Lukas Appelhans committed
122
void Transfer::setUploadLimit(int ulLimit, SpeedLimit limit)
123
{
Lukas Appelhans's avatar
Lukas Appelhans committed
124
    if (limit == Transfer::VisibleSpeedLimit)
Alexander Potashev's avatar
Alexander Potashev committed
125
    {
Lukas Appelhans's avatar
Lukas Appelhans committed
126
127
128
        m_visibleUploadLimit = ulLimit;
        if (ulLimit < m_uploadLimit || m_uploadLimit == 0)
            m_uploadLimit = ulLimit;
Alexander Potashev's avatar
Alexander Potashev committed
129
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
130
    else
Alexander Potashev's avatar
Alexander Potashev committed
131
    {
Lukas Appelhans's avatar
Lukas Appelhans committed
132
        m_uploadLimit = ulLimit;
Alexander Potashev's avatar
Alexander Potashev committed
133
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
134
135
136
137
138
139
140

    setSpeedLimits(m_uploadLimit, m_downloadLimit);
}

void Transfer::setDownloadLimit(int dlLimit, SpeedLimit limit)
{
    if (limit == Transfer::VisibleSpeedLimit)
Alexander Potashev's avatar
Alexander Potashev committed
141
    {
Lukas Appelhans's avatar
Lukas Appelhans committed
142
143
144
        m_visibleDownloadLimit = dlLimit;
        if (dlLimit < m_downloadLimit || m_downloadLimit == 0)
            m_downloadLimit = dlLimit;
Alexander Potashev's avatar
Alexander Potashev committed
145
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
146
    else
Alexander Potashev's avatar
Alexander Potashev committed
147
    {
Lukas Appelhans's avatar
Lukas Appelhans committed
148
        m_downloadLimit = dlLimit;
Alexander Potashev's avatar
Alexander Potashev committed
149
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
150
151
152
153
154
155
156
157

    setSpeedLimits(m_uploadLimit, m_downloadLimit);
}

int Transfer::uploadLimit(SpeedLimit limit) const
{
    if (limit == Transfer::VisibleSpeedLimit)
        return m_visibleUploadLimit;
158

Lukas Appelhans's avatar
Lukas Appelhans committed
159
    return m_uploadLimit;
160
161
}

Lukas Appelhans's avatar
Lukas Appelhans committed
162
int Transfer::downloadLimit(SpeedLimit limit) const
163
{
Lukas Appelhans's avatar
Lukas Appelhans committed
164
165
    if (limit == Transfer::VisibleSpeedLimit)
        return m_visibleDownloadLimit;
166

Lukas Appelhans's avatar
Lukas Appelhans committed
167
    return m_downloadLimit;
168
169
}

Lukas Appelhans's avatar
Lukas Appelhans committed
170
171
172
173
174
175
176
177
178
179
180
181
void Transfer::setMaximumShareRatio(double ratio)
{
    m_ratio = ratio;
    checkShareRatio();
}

void Transfer::checkShareRatio()
{
    if (m_downloadedSize == 0 || m_ratio == 0)
        return;

    if (m_uploadedSize / m_downloadedSize >= m_ratio)
Lukas Appelhans's avatar
Lukas Appelhans committed
182
        setDownloadLimit(1, Transfer::InvisibleSpeedLimit);//If we set it to 0 we would have no limit xD
Lukas Appelhans's avatar
Lukas Appelhans committed
183
    else
Lukas Appelhans's avatar
Lukas Appelhans committed
184
        setDownloadLimit(0, Transfer::InvisibleSpeedLimit);
Lukas Appelhans's avatar
Lukas Appelhans committed
185
186
}

187
void Transfer::setLog(const QString& message, Transfer::LogLevel level)
188
189
{
    QString msg("<font color=\"blue\">" + QTime::currentTime().toString() + "</font> : ");
190
    if (level == Log_Error)
191
192
193
    {
        msg += "<font color=\"red\">" + message + "</font>";
    }
194
    if (level == Log_Warning)
195
196
197
198
199
200
201
202
    {
        msg += "<font color=\"yellow\">" + message + "</font>";
    } else {
        msg += message;
    }
    m_log << msg;
}

Dario Massarin's avatar
Dario Massarin committed
203
204
205
TransferHandler * Transfer::handler()
{
    if(!m_handler)
206
        m_handler = m_factory->createTransferHandler(this, scheduler());
Dario Massarin's avatar
Dario Massarin committed
207
208
209
210

    return m_handler;
}

211
212
213
214
215
TransferTreeModel * Transfer::model()
{
    return group()->model();
}

216
void Transfer::save(const QDomElement &element)
217
{
218
    QDomElement e = element;
Stephan Kulow's avatar
Stephan Kulow committed
219
220
    e.setAttribute("Source", m_source.url());
    e.setAttribute("Dest", m_dest.url());
221
    e.setAttribute("TotalSize", m_totalSize);
222
223
    e.setAttribute("DownloadedSize", m_downloadedSize);
    e.setAttribute("UploadedSize", m_uploadedSize);
Lukas Appelhans's avatar
Lukas Appelhans committed
224
225
    e.setAttribute("DownloadLimit", m_visibleDownloadLimit);
    e.setAttribute("UploadLimit", m_visibleUploadLimit);
226
    e.setAttribute("ElapsedTime", status() == Job::Running ? m_runningTime.elapsed() / 1000 : m_runningSeconds);
227
    e.setAttribute("Policy", policy() == Job::Start ? "Start" : (policy() == Job::Stop ? "Stop" : "None"));
Dario Massarin's avatar
Dario Massarin committed
228
}
229

Matthias Fuchs's avatar
Matthias Fuchs committed
230
void Transfer::load(const QDomElement *element)
Dario Massarin's avatar
Dario Massarin committed
231
{
Matthias Fuchs's avatar
Matthias Fuchs committed
232
233
234
235
236
237
238
239
240
    if (!element)
    {
        setStatus(status(), i18nc("transfer state: stopped", "Stopped"), SmallIcon("process-stop"));
        setStartStatus(status());
        return;
    }

    const QDomElement e = *element;

Lukas Appelhans's avatar
Lukas Appelhans committed
241
242
    m_source = QUrl(e.attribute("Source"));
    m_dest = QUrl(e.attribute("Dest"));
243

244
    m_totalSize = e.attribute("TotalSize").toULongLong();
245
246
    m_downloadedSize = e.attribute("DownloadedSize").toULongLong();
    m_uploadedSize = e.attribute("UploadedSize").toULongLong();
247
    m_percent = (m_totalSize ? ((100.0 * m_downloadedSize) / m_totalSize) : 0);
Dario Massarin's avatar
Dario Massarin committed
248

249
250
251
252
    if ((m_totalSize == m_downloadedSize) && (m_totalSize != 0)) {
        setStartStatus(Job::Finished);
        setStatus(startStatus());
    } else {
Urs Wolfer's avatar
Urs Wolfer committed
253
        setStatus(status(), i18nc("transfer state: stopped", "Stopped"), SmallIcon("process-stop"));
254
        setStartStatus(status());
Dario Massarin's avatar
Dario Massarin committed
255
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
256
257
    setUploadLimit(e.attribute("UploadLimit").toInt(), Transfer::VisibleSpeedLimit);
    setDownloadLimit(e.attribute("DownloadLimit").toInt(), Transfer::VisibleSpeedLimit);
258
    m_runningSeconds = e.attribute("ElapsedTime").toInt();
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    if (Settings::startupAction() == 1)
    {
        setPolicy(Job::Start);
    }
    else if (Settings::startupAction() == 2)
    {
        setPolicy(Job::Stop);
    }
    else
    {
        if (e.attribute("Policy") == "Start")
            setPolicy(Job::Start);
        else if (e.attribute("Policy") == "Stop")
            setPolicy(Job::Stop);
        else
            setPolicy(Job::None);
    }
Dario Massarin's avatar
Dario Massarin committed
276
277
}

Urs Wolfer's avatar
Urs Wolfer committed
278
void Transfer::setStatus(Job::Status jobStatus, const QString &text, const QPixmap &pix)
Dario Massarin's avatar
Dario Massarin committed
279
{
280
    const bool statusChanged = (status() != jobStatus);
Matthias Fuchs's avatar
Matthias Fuchs committed
281
    QString statusText = text;
282
    if (statusText.isEmpty()) {
283
        statusText = i18nc(STATUSTEXTS[jobStatus].context, STATUSTEXTS[jobStatus].name);
Matthias Fuchs's avatar
Matthias Fuchs committed
284
    }
Dario Massarin's avatar
Dario Massarin committed
285

286
    //always prefer pix, if it is set
287
    if (!pix.isNull()) {
288
        m_statusPixmap = pix;
289
    } else if (statusChanged || m_statusPixmap.isNull()) {
Matthias Fuchs's avatar
Matthias Fuchs committed
290
        m_statusPixmap = SmallIcon(STATUSICONS[jobStatus]);
Matthias Fuchs's avatar
Matthias Fuchs committed
291
292
293
    }

    m_statusText = statusText;
294

295
296
297
298
299
300
301
    if (jobStatus == Job::Running && status() != Job::Running)
    {
        m_runningTime.restart();
        m_runningTime.addSecs(m_runningSeconds);
    }
    if (jobStatus != Job::Running && status() == Job::Running)
        m_runningSeconds = m_runningTime.elapsed() / 1000;
Dario Massarin's avatar
Dario Massarin committed
302
303
304
    /**
    * It's important to call job::setStatus AFTER having changed the 
    * icon or the text or whatever.
Dario Massarin's avatar
Dario Massarin committed
305
    * This because this function also notifies about this change
Dario Massarin's avatar
Dario Massarin committed
306
307
308
309
310
311
312
313
    * the scheduler which could also decide to change it another time
    * as well. For example if a job status is set to Aborted, the scheduler
    * could mark it to Delayed. This could trigger another icon or text
    * change which would be the right one since the status of the Job
    * has changed. If we set the icon or text after calling setStatus(),
    * we can overwrite the last icon or text change.
    */
    Job::setStatus(jobStatus);
Matthias Fuchs's avatar
Matthias Fuchs committed
314

315
}
316

317
void Transfer::setTransferChange(ChangesFlags change, bool postEvent)
318
{
319
320
321
    if (change & Tc_DownloadedSize || change & Tc_Status) {
        change = change | Tc_RemainingTime;
    }
Dario Massarin's avatar
Dario Massarin committed
322
    handler()->setTransferChange(change, postEvent);
Pino Toscano's avatar
Pino Toscano committed
323
}
Matthias Fuchs's avatar
Matthias Fuchs committed
324
325
326

QString Transfer::statusText(Job::Status status)
{
327
    return i18nc(STATUSTEXTS[status].context, STATUSTEXTS[status].name);
Matthias Fuchs's avatar
Matthias Fuchs committed
328
329
330
331
332
333
}

QPixmap Transfer::statusPixmap(Job::Status status)
{
    return SmallIcon(STATUSICONS[status]);
}