~michael-sheldon/ubuntu-download-manager/fix-1557771

« back to all changes in this revision

Viewing changes to src/common/priv/ubuntu/transfers/queue.cpp

  • Committer: CI Train Bot
  • Author(s): Michael Sheldon
  • Date: 2016-03-08 17:45:57 UTC
  • mfrom: (347.3.2 implement-per-app-queueing)
  • Revision ID: ci-train-bot@canonical.com-20160308174557-1p5az22r7usysv5x
Implement per-app queueing instead of having one global queue for all apps
Approved by: Ken VanDine, PS Jenkins bot

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
namespace Transfers {
29
29
 
30
30
Queue::Queue(QObject* parent)
31
 
    : QObject(parent),
32
 
      _current("") {
 
31
    : QObject(parent) {
33
32
    CHECK(connect(NetworkSession::instance(),
34
33
        &NetworkSession::sessionTypeChanged,
35
34
        this, &Queue::onSessionTypeChanged))
42
41
    auto path = transfer->path();
43
42
    TRACE << path;
44
43
 
45
 
    _sortedPaths.append(path);
 
44
    if (!_sortedPaths.contains(transfer->transferAppId())) {
 
45
        _sortedPaths[transfer->transferAppId()] = new QStringList();
 
46
    }
 
47
    _sortedPaths[transfer->transferAppId()]->append(path);
46
48
    _transfers[path] = transfer;
47
49
 
48
50
    if (transfer->addToQueue()) {
63
65
    TRACE << path;
64
66
 
65
67
    auto transfer = _transfers[path];
66
 
    _sortedPaths.removeOne(path);
 
68
    _sortedPaths[transfer->transferAppId()]->removeOne(path);
67
69
    _transfers.remove(path);
68
70
 
69
71
    transfer->deleteLater();
71
73
}
72
74
 
73
75
QString
74
 
Queue::currentTransfer() {
75
 
    return _current;
 
76
Queue::currentTransfer(const QString& appId) {
 
77
    if(_current.contains(appId)) {
 
78
        return _current[appId];
 
79
    } else {
 
80
        return "";
 
81
    }
76
82
}
77
83
 
78
84
QStringList
79
85
Queue::paths() {
80
 
    return _sortedPaths;
 
86
    QStringList allPaths;
 
87
    foreach(QStringList* list, _sortedPaths.values()) {
 
88
        allPaths += *list;
 
89
    }
 
90
    return allPaths;
81
91
}
82
92
 
83
93
QHash<QString, Transfer*>
84
94
Queue::transfers() {
85
95
    QHash<QString, Transfer*> transfers;
86
 
    foreach(const QString& path, _sortedPaths) {
 
96
    foreach(const QString& path, paths()) {
87
97
        transfers[path] = _transfers[path];
88
98
    }
89
99
    return transfers;
101
111
    // decide what to do with it
102
112
    auto transfer = qobject_cast<Transfer*>(sender());
103
113
    switch (transfer->state()) {
 
114
        case Transfer::RESUME:
104
115
        case Transfer::START:
105
 
            // only start the transfer in the update method
106
 
            if (_current.isEmpty())
107
 
                updateCurrentTransfer();
 
116
            if (!_current.contains(transfer->transferAppId()) 
 
117
                    || (_current.contains(transfer->transferAppId()) 
 
118
                        && _current[transfer->transferAppId()].isEmpty())) {
 
119
                // only start or resume the transfer in the update method
 
120
                updateCurrentTransfer(transfer->transferAppId());
 
121
            }
108
122
            break;
109
123
        case Transfer::PAUSE:
110
124
            transfer->pauseTransfer();
111
 
            if (!_current.isEmpty()  && _current == transfer->path())
112
 
                updateCurrentTransfer();
113
 
            break;
114
 
        case Transfer::RESUME:
115
 
            // only resume the transfer in the update method
116
 
            if (_current.isEmpty()) {
117
 
                updateCurrentTransfer();
118
 
            }
 
125
            updateCurrentTransfer(transfer->transferAppId());
119
126
            break;
120
127
        case Transfer::CANCEL:
121
128
            // cancel and remove the transfer
122
129
            transfer->cancelTransfer();
123
 
            if (!_current.isEmpty() && _current == transfer->path())
124
 
                updateCurrentTransfer();
 
130
            if (_current.contains(transfer->transferAppId()) && _current[transfer->transferAppId()] == transfer->path())
 
131
                updateCurrentTransfer(transfer->transferAppId());
125
132
            else
126
133
                remove(transfer->path());
127
134
            break;
129
136
        case Transfer::UNCOLLECTED:
130
137
            // remove the registered object in dbus, remove the transfer
131
138
            // and the adapter from the list
132
 
            if (!_current.isEmpty() && _current == transfer->path())
133
 
                updateCurrentTransfer();
 
139
            if (_current.contains(transfer->transferAppId()) && _current[transfer->transferAppId()] == transfer->path())
 
140
                updateCurrentTransfer(transfer->transferAppId());
134
141
            break;
135
142
        case Transfer::FINISH:
136
 
            if (!_current.isEmpty() && _current == transfer->path()) {
137
 
                updateCurrentTransfer();
 
143
            if (_current.contains(transfer->transferAppId()) && _current[transfer->transferAppId()] == transfer->path()) {
 
144
                updateCurrentTransfer(transfer->transferAppId());
138
145
            } else {
139
146
                // Remove from the queue even if it wasn't the current transfer
140
147
                // (finished signals can be received for downloads that completed
176
183
}
177
184
 
178
185
void
179
 
Queue::updateCurrentTransfer() {
 
186
Queue::updateCurrentTransfer(const QString& appIdToUpdate) {
180
187
    TRACE;
181
 
    if (!_current.isEmpty()) {
182
 
        // check if it was canceled/finished
183
 
        auto currentTransfer = _transfers[_current];
184
 
        auto state = currentTransfer->state();
185
 
        if (state == Transfer::CANCEL || state == Transfer::FINISH
186
 
            || state == Transfer::ERROR) {
187
 
            LOG(INFO) << "State is CANCEL || FINISH || ERROR";
188
 
            remove(_current);
189
 
            _current = "";
190
 
        } else if (state == Transfer::UNCOLLECTED) {
191
 
            LOG(INFO) << "State is UNCOLLECTED";
192
 
            _current = "";
193
 
        } else if (!currentTransfer->canTransfer()
194
 
                || state == Transfer::PAUSE) {
195
 
            LOG(INFO) << "States is Cannot Transfer || PAUSE";
196
 
            _current = "";
 
188
 
 
189
    // If we don't get given a specific appId to update transfers for
 
190
    // we update all the transfers
 
191
    QStringList appIds;
 
192
    if (appIdToUpdate.isEmpty()) {
 
193
        appIds = _sortedPaths.keys();
 
194
    } else {
 
195
        appIds.append(appIdToUpdate);
 
196
    }
 
197
 
 
198
    foreach(QString appId, appIds) {
 
199
        if (_current.contains(appId)) {
 
200
            // check if it was canceled/finished
 
201
            auto currentTransfer = _transfers[_current[appId]];
 
202
            auto state = currentTransfer->state();
 
203
            if (state == Transfer::CANCEL || state == Transfer::FINISH
 
204
                || state == Transfer::ERROR) {
 
205
                LOG(INFO) << "State is CANCEL || FINISH || ERROR";
 
206
                remove(_current[appId]);
 
207
                _current.remove(appId);
 
208
            } else if (state == Transfer::UNCOLLECTED) {
 
209
                LOG(INFO) << "State is UNCOLLECTED";
 
210
                _current.remove(appId);
 
211
            } else if (!currentTransfer->canTransfer()
 
212
                    || state == Transfer::PAUSE) {
 
213
                LOG(INFO) << "States is Cannot Transfer || PAUSE";
 
214
                _current.remove(appId);
 
215
            } else {
 
216
                break;
 
217
            }
 
218
        }
 
219
 
 
220
        // loop via the transfers and choose the first that is
 
221
        // started or resumed
 
222
        foreach(const QString& path, *_sortedPaths[appId]) {
 
223
            auto transfer = _transfers[path];
 
224
            auto state = transfer->state();
 
225
            if (transfer->canTransfer()
 
226
                    && (state == Transfer::START
 
227
                        || state == Transfer::RESUME)) {
 
228
                _current[appId] = path;
 
229
                if (state == Transfer::START) {
 
230
                    transfer->startTransfer();
 
231
                } else
 
232
                    transfer->resumeTransfer();
 
233
                break;
 
234
            }
 
235
        }
 
236
        if (_current.contains(appId) && !_current[appId].isEmpty()) {
 
237
            emit currentChanged(appId, _current[appId]);
197
238
        } else {
198
 
            return;
199
 
        }
200
 
    }
201
 
 
202
 
    // loop via the transfers and choose the first that is
203
 
    // started or resumed
204
 
    foreach(const QString& path, _sortedPaths) {
205
 
        auto transfer = _transfers[path];
206
 
        auto state = transfer->state();
207
 
        if (transfer->canTransfer()
208
 
                && (state == Transfer::START
209
 
                    || state == Transfer::RESUME)) {
210
 
            _current = path;
211
 
            if (state == Transfer::START)
212
 
                transfer->startTransfer();
213
 
            else
214
 
                transfer->resumeTransfer();
215
 
            break;
216
 
        }
217
 
    }
218
 
 
219
 
    emit currentChanged(_current);
 
239
            emit currentChanged(appId, "");
 
240
        }
 
241
    }
220
242
}
221
243
 
222
244
}  // Transfers