45
|
1 /****************************************************************************
|
|
2 **
|
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 ** Contact: Qt Software Information (qt-info@nokia.com)
|
|
5 **
|
|
6 ** This file is part of the demonstration applications of the Qt Toolkit.
|
|
7 **
|
|
8 ** $QT_BEGIN_LICENSE:LGPL$
|
|
9 ** Commercial Usage
|
|
10 ** Licensees holding valid Qt Commercial licenses may use this file in
|
|
11 ** accordance with the Qt Commercial License Agreement provided with the
|
|
12 ** Software or, alternatively, in accordance with the terms contained in
|
|
13 ** a written agreement between you and Nokia.
|
|
14 **
|
|
15 ** GNU Lesser General Public License Usage
|
|
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
17 ** General Public License version 2.1 as published by the Free Software
|
|
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
19 ** packaging of this file. Please review the following information to
|
|
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
22 **
|
|
23 ** In addition, as a special exception, Nokia gives you certain
|
|
24 ** additional rights. These rights are described in the Nokia Qt LGPL
|
|
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
|
26 ** package.
|
|
27 **
|
|
28 ** GNU General Public License Usage
|
|
29 ** Alternatively, this file may be used under the terms of the GNU
|
|
30 ** General Public License version 3.0 as published by the Free Software
|
|
31 ** Foundation and appearing in the file LICENSE.GPL included in the
|
|
32 ** packaging of this file. Please review the following information to
|
|
33 ** ensure the GNU General Public License version 3.0 requirements will be
|
|
34 ** met: http://www.gnu.org/copyleft/gpl.html.
|
|
35 **
|
|
36 ** If you are unsure which license is appropriate for your use, please
|
|
37 ** contact the sales department at qt-sales@nokia.com.
|
|
38 ** $QT_END_LICENSE$
|
|
39 **
|
|
40 ****************************************************************************/
|
73
|
41
|
45
|
42 module downloadmanager;
|
|
43
|
|
44
|
73
|
45 import qt.core.QFile;
|
|
46 import qt.core.QTime;
|
|
47 import qt.core.QMetaEnum;
|
|
48 import qt.core.QSettings;
|
|
49 import qt.core.QDebug;
|
45
|
50
|
73
|
51 import qt.gui.QDesktopServices;
|
|
52 import qt.gui.QFileDialog;
|
|
53 import qt.gui.QHeaderView;
|
|
54 import qt.gui.QFileIconProvider;
|
45
|
55
|
73
|
56 import qt.network.QNetworkReply;
|
|
57 import qt.webkit.QWebSettings;
|
45
|
58
|
73
|
59 import math;
|
45
|
60 import autosaver;
|
|
61 import browserapplication;
|
|
62 import networkaccessmanager;
|
73
|
63 import ui_downloads;
|
|
64 import ui_downloaditem;
|
45
|
65
|
|
66
|
|
67 class DownloadItem : public QWidget, public Ui_DownloadItem
|
|
68 {
|
46
|
69 mixin Signal!("statusChanged");
|
45
|
70
|
|
71 public:
|
|
72
|
73
|
73 /*!
|
|
74 DownloadItem is a widget that is displayed in the download manager list.
|
|
75 It moves the data from the QNetworkReply into the QFile as well
|
|
76 as update the information/progressbar and report errors.
|
|
77 */
|
|
78 this(QNetworkReply reply = null, bool requestFileName = false, QWidget parent = null)
|
|
79 {
|
|
80 super(parent);
|
|
81 m_reply = reply;
|
|
82 m_requestFileName = requestFileName;
|
|
83 m_bytesReceived = 0;
|
45
|
84
|
73
|
85 setupUi(this);
|
|
86 QPalette p = downloadInfoLabel.palette();
|
|
87 p.setColor(QPalette.Text, Qt.darkGray);
|
|
88 downloadInfoLabel.setPalette(p);
|
|
89 progressBar.setMaximum(0);
|
|
90 tryAgainButton.hide();
|
|
91 stopButton.clicked.connect(&this.stop);
|
|
92 openButton.clicked.connect(&this.open);
|
|
93 tryAgainButton.clicked.connect(&this.tryAgain);
|
45
|
94
|
73
|
95 init();
|
|
96 }
|
45
|
97
|
73
|
98 bool downloading()
|
|
99 {
|
|
100 return (progressBar.isVisible());
|
|
101 }
|
45
|
102
|
73
|
103 bool downloadedSuccessfully()
|
|
104 {
|
|
105 return (stopButton.isHidden() && tryAgainButton.isHidden());
|
|
106 }
|
45
|
107
|
73
|
108 QUrl m_url;
|
|
109 QFile m_output;
|
|
110 QNetworkReply m_reply;
|
45
|
111
|
73
|
112 private:
|
|
113
|
|
114 void stop()
|
|
115 {
|
|
116 setUpdatesEnabled(false);
|
|
117 stopButton.setEnabled(false);
|
|
118 stopButton.hide();
|
|
119 tryAgainButton.setEnabled(true);
|
|
120 tryAgainButton.show();
|
|
121 setUpdatesEnabled(true);
|
|
122 m_reply.abort();
|
|
123 }
|
45
|
124
|
73
|
125 void tryAgain()
|
|
126 {
|
|
127 if (!tryAgainButton.isEnabled())
|
|
128 return;
|
45
|
129
|
73
|
130 tryAgainButton.setEnabled(false);
|
|
131 tryAgainButton.setVisible(false);
|
|
132 stopButton.setEnabled(true);
|
|
133 stopButton.setVisible(true);
|
|
134 progressBar.setVisible(true);
|
45
|
135
|
73
|
136 QNetworkReply r = BrowserApplication.networkAccessManager().get(QNetworkRequest(m_url));
|
|
137 if (m_reply)
|
|
138 m_reply.deleteLater();
|
|
139 if (m_output.exists())
|
|
140 m_output.remove();
|
|
141 m_reply = r;
|
|
142 init();
|
77
|
143 statusChanged.emit();
|
73
|
144 }
|
45
|
145
|
73
|
146 void open()
|
|
147 {
|
77
|
148 auto info = new QFileInfo(m_output);
|
73
|
149 QUrl url = QUrl.fromLocalFile(info.absolutePath());
|
|
150 QDesktopServices.openUrl(url);
|
|
151 }
|
45
|
152
|
73
|
153 void downloadReadyRead()
|
|
154 {
|
|
155 if (m_requestFileName && m_output.fileName().isEmpty())
|
|
156 return;
|
|
157 if (!m_output.isOpen()) {
|
|
158 // in case someone else has already put a file there
|
|
159 if (!m_requestFileName)
|
|
160 getFileName();
|
|
161 if (!m_output.open(QIODevice.WriteOnly)) {
|
77
|
162 downloadInfoLabel.setText(Format(tr("Error opening save file: {}"), m_output.errorString()));
|
73
|
163 stopButton.click();
|
77
|
164 statusChanged.emit();
|
73
|
165 return;
|
|
166 }
|
77
|
167 statusChanged.emit();
|
73
|
168 }
|
|
169 if (-1 == m_output.write(m_reply.readAll())) {
|
77
|
170 downloadInfoLabel.setText(Format(tr("Error saving: {}"), m_output.errorString()));
|
73
|
171 stopButton.click();
|
|
172 }
|
|
173 }
|
45
|
174
|
73
|
175 void error(QNetworkReply.NetworkError code)
|
|
176 {
|
|
177 qDebug() << "DownloadItem::error" << m_reply.errorString() << m_url;
|
77
|
178 downloadInfoLabel.setText(Format(tr("Network Error: {}"), m_reply.errorString()));
|
73
|
179 tryAgainButton.setEnabled(true);
|
|
180 tryAgainButton.setVisible(true);
|
|
181 }
|
45
|
182
|
74
|
183 void downloadProgress(ulong bytesReceived, ulong bytesTotal)
|
73
|
184 {
|
|
185 m_bytesReceived = bytesReceived;
|
|
186 if (bytesTotal == -1) {
|
|
187 progressBar.setValue(0);
|
|
188 progressBar.setMaximum(0);
|
|
189 } else {
|
|
190 progressBar.setValue(bytesReceived);
|
|
191 progressBar.setMaximum(bytesTotal);
|
|
192 }
|
|
193 updateInfoLabel();
|
|
194 }
|
45
|
195
|
73
|
196 void metaDataChanged()
|
|
197 {
|
|
198 qDebug() << "DownloadItem::metaDataChanged: not handled.";
|
|
199 }
|
45
|
200
|
73
|
201 void finished()
|
|
202 {
|
|
203 progressBar.hide();
|
|
204 stopButton.setEnabled(false);
|
|
205 stopButton.hide();
|
|
206 m_output.close();
|
|
207 updateInfoLabel();
|
77
|
208 statusChanged.emit();
|
73
|
209 }
|
45
|
210
|
|
211 private:
|
73
|
212
|
|
213 void getFileName()
|
|
214 {
|
77
|
215 auto settings = new QSettings;
|
80
|
216 settings.beginGroup("downloadmanager");
|
77
|
217 string defaultLocation = QDesktopServices.storageLocation(QDesktopServices.DesktopLocation);
|
80
|
218 string downloadDirectory = settings.value("downloadDirectory", defaultLocation).toString();
|
73
|
219 if (!downloadDirectory.isEmpty())
|
85
|
220 downloadDirectory ~= "/";
|
45
|
221
|
77
|
222 string defaultFileName = saveFileName(downloadDirectory);
|
|
223 string fileName = defaultFileName;
|
73
|
224 if (m_requestFileName) {
|
|
225 fileName = QFileDialog.getSaveFileName(this, tr("Save File"), defaultFileName);
|
|
226 if (fileName.isEmpty()) {
|
|
227 m_reply.close();
|
77
|
228 fileNameLabel.setText(Format(tr("Download canceled: {}"), (new QFileInfo(defaultFileName)).fileName()));
|
73
|
229 return;
|
|
230 }
|
|
231 }
|
|
232 m_output.setFileName(fileName);
|
77
|
233 fileNameLabel.setText((new QFileInfo(m_output.fileName())).fileName());
|
73
|
234 if (m_requestFileName)
|
|
235 downloadReadyRead();
|
|
236 }
|
45
|
237
|
73
|
238 void init()
|
|
239 {
|
|
240 if (!m_reply)
|
|
241 return;
|
45
|
242
|
73
|
243 // attach to the m_reply
|
|
244 m_url = m_reply.url();
|
|
245 m_reply.setParent(this);
|
|
246 m_reply.readyRead.connect(&this.downloadReadyRead);
|
|
247 m_reply.error.connect(&this.error);
|
|
248 m_reply.downloadProgress.connect(&this.downloadProgress);
|
|
249 m_reply.metaDataChanged.connect(&this.metaDataChanged);
|
|
250 m_reply.finished.connect(&this.finished);
|
45
|
251
|
73
|
252 // reset info
|
|
253 downloadInfoLabel.clear();
|
|
254 progressBar.setValue(0);
|
|
255 getFileName();
|
45
|
256
|
73
|
257 // start timer for the download estimation
|
|
258 m_downloadTime.start();
|
45
|
259
|
73
|
260 if (m_reply.error() != QNetworkReply.NoError) {
|
|
261 error(m_reply.error());
|
|
262 finished();
|
|
263 }
|
|
264 }
|
45
|
265
|
73
|
266 void updateInfoLabel()
|
|
267 {
|
|
268 if (m_reply.error() == QNetworkReply.NoError)
|
|
269 return;
|
45
|
270
|
74
|
271 ulong bytesTotal = progressBar.maximum();
|
73
|
272 bool running = !downloadedSuccessfully();
|
45
|
273
|
73
|
274 // update info label
|
|
275 double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed();
|
74
|
276 double timeRemaining = (cast(double)(bytesTotal - m_bytesReceived)) / speed;
|
77
|
277 string timeRemainingString = tr("seconds");
|
73
|
278 if (timeRemaining > 60) {
|
|
279 timeRemaining = timeRemaining / 60;
|
|
280 timeRemainingString = tr("minutes");
|
|
281 }
|
|
282 timeRemaining = floor(timeRemaining);
|
45
|
283
|
73
|
284 // When downloading the eta should never be 0
|
|
285 if (timeRemaining == 0)
|
|
286 timeRemaining = 1;
|
45
|
287
|
77
|
288 string info;
|
73
|
289 if (running) {
|
77
|
290 string remaining;
|
73
|
291 if (bytesTotal != 0)
|
77
|
292 remaining = Format(tr("- {} {} remaining"), timeRemaining, timeRemainingString);
|
73
|
293
|
77
|
294 info = Format(tr("{} of {} ({}/sec) {}"),
|
|
295 dataString(m_bytesReceived),
|
|
296 bytesTotal == 0 ? tr("?") : dataString(bytesTotal),
|
|
297 dataString(cast(int) speed),
|
|
298 remaining);
|
73
|
299 } else {
|
|
300 if (m_bytesReceived == bytesTotal)
|
|
301 info = dataString(m_output.size());
|
|
302 else
|
77
|
303 info = Format(tr("{} of {} - Stopped"),
|
|
304 dataString(m_bytesReceived),
|
|
305 dataString(bytesTotal));
|
73
|
306 }
|
|
307 downloadInfoLabel.setText(info);
|
|
308 }
|
45
|
309
|
77
|
310 string dataString(int size)
|
73
|
311 {
|
77
|
312 string unit;
|
73
|
313 if (size < 1024) {
|
|
314 unit = tr("bytes");
|
|
315 } else if (size < 1024*1024) {
|
|
316 size /= 1024;
|
|
317 unit = tr("kB");
|
|
318 } else {
|
|
319 size /= 1024*1024;
|
|
320 unit = tr("MB");
|
|
321 }
|
80
|
322 return Format("{} {}", size, unit);
|
73
|
323 }
|
45
|
324
|
77
|
325 string saveFileName(string directory)
|
73
|
326 {
|
|
327 // Move this function into QNetworkReply to also get file name sent from the server
|
77
|
328 string path = m_url.path();
|
|
329 auto info = new QFileInfo(path);
|
|
330 string baseName = info.completeBaseName();
|
|
331 string endName = info.suffix();
|
45
|
332
|
73
|
333 if (baseName.isEmpty()) {
|
80
|
334 baseName = "unnamed_download";
|
73
|
335 qDebug() << "DownloadManager:: downloading unknown file:" << m_url;
|
|
336 }
|
85
|
337 string name = directory ~ baseName ~ "." ~ endName;
|
73
|
338 if (QFile.exists(name)) {
|
|
339 // already exists, don't overwrite
|
|
340 int i = 1;
|
|
341 do {
|
85
|
342 name = directory ~ baseName ~ "-" ~ .toString(i++) ~ "." ~ endName;
|
73
|
343 } while (QFile.exists(name));
|
|
344 }
|
|
345 return name;
|
|
346 }
|
45
|
347
|
73
|
348 bool m_requestFileName;
|
74
|
349 ulong m_bytesReceived;
|
73
|
350 QTime m_downloadTime;
|
|
351 }
|
|
352
|
45
|
353
|
|
354 class DownloadManager : public QDialog, public Ui_DownloadDialog
|
|
355 {
|
73
|
356
|
|
357 public:
|
|
358
|
|
359 enum RemovePolicy {
|
|
360 Never,
|
|
361 Exit,
|
|
362 SuccessFullDownload
|
|
363 };
|
|
364
|
|
365 /*!
|
|
366 DownloadManager is a Dialog that contains a list of DownloadItems
|
|
367
|
|
368 It is a basic download manager. It only downloads the file, doesn't do BitTorrent,
|
|
369 extract zipped files or anything fancy.
|
|
370 */
|
74
|
371 this(QWidget parent = null)
|
|
372 //: QDialog(parent)
|
73
|
373 {
|
|
374 m_autoSaver = new AutoSaver(this);
|
|
375 m_manager = BrowserApplication.networkAccessManager();
|
|
376 m_iconProvider = 0;
|
|
377 m_removePolicy = RemovePolicy.Never;
|
|
378
|
|
379 setupUi(this);
|
|
380 downloadsView.setShowGrid(false);
|
|
381 downloadsView.verticalHeader().hide();
|
|
382 downloadsView.horizontalHeader().hide();
|
|
383 downloadsView.setAlternatingRowColors(true);
|
|
384 downloadsView.horizontalHeader().setStretchLastSection(true);
|
|
385 m_model = new DownloadModel(this);
|
|
386 downloadsView.setModel(m_model);
|
74
|
387 cleanupButton.clicked.connect(&this.cleanup);
|
73
|
388 load();
|
|
389 }
|
|
390
|
|
391 ~this()
|
|
392 {
|
|
393 m_autoSaver.changeOccurred();
|
|
394 m_autoSaver.saveIfNeccessary();
|
|
395 if (m_iconProvider)
|
|
396 delete m_iconProvider;
|
|
397 }
|
|
398
|
|
399 int activeDownloads()
|
|
400 {
|
|
401 int count = 0;
|
77
|
402 for (int i = 0; i < m_downloads.length; ++i) {
|
|
403 if (m_downloads[i].stopButton.isEnabled())
|
73
|
404 ++count;
|
|
405 }
|
|
406 return count;
|
|
407 }
|
|
408
|
|
409 RemovePolicy removePolicy()
|
|
410 {
|
|
411 return m_removePolicy;
|
|
412 }
|
|
413
|
|
414 void setRemovePolicy(RemovePolicy policy)
|
|
415 {
|
|
416 if (policy == m_removePolicy)
|
|
417 return;
|
|
418 m_removePolicy = policy;
|
|
419 m_autoSaver.changeOccurred();
|
|
420 }
|
45
|
421
|
|
422 public:
|
|
423
|
74
|
424 void download(QNetworkRequest request, bool requestFileName = false)
|
73
|
425 {
|
|
426 if (request.url().isEmpty())
|
|
427 return;
|
|
428 handleUnsupportedContent(m_manager.get(request), requestFileName);
|
|
429 }
|
45
|
430
|
73
|
431 void download(QUrl url, bool requestFileName = false)
|
|
432 {
|
|
433 download(QNetworkRequest(url), requestFileName);
|
|
434 }
|
|
435
|
74
|
436 void handleUnsupportedContent(QNetworkReply reply, bool requestFileName = false)
|
73
|
437 {
|
|
438 if (!reply || reply.url().isEmpty())
|
|
439 return;
|
|
440 QVariant header = reply.header(QNetworkRequest.ContentLengthHeader);
|
|
441 bool ok;
|
|
442 int size = header.toInt(&ok);
|
|
443 if (ok && size == 0)
|
|
444 return;
|
|
445
|
|
446 qDebug() << "DownloadManager::handleUnsupportedContent" << reply.url() << "requestFileName" << requestFileName;
|
|
447 DownloadItem item = new DownloadItem(reply, requestFileName, this);
|
|
448 addItem(item);
|
|
449 }
|
|
450
|
|
451 void cleanup()
|
|
452 {
|
77
|
453 if (m_downloads.length == 0)
|
73
|
454 return;
|
77
|
455 m_model.removeRows(0, m_downloads.length);
|
73
|
456 updateItemCount();
|
77
|
457 if (m_downloads.length == 0 && m_iconProvider) {
|
73
|
458 delete m_iconProvider;
|
|
459 m_iconProvider = 0;
|
|
460 }
|
|
461 m_autoSaver.changeOccurred();
|
|
462 }
|
|
463
|
|
464 private:
|
|
465
|
|
466 void save()
|
|
467 {
|
|
468 QSettings settings;
|
80
|
469 settings.beginGroup("downloadmanager");
|
73
|
470 QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy"));
|
80
|
471 settings.setValue("removeDownloadsPolicy", removePolicyEnum.valueToKey(m_removePolicy));
|
|
472 settings.setValue("size", size());
|
73
|
473 if (m_removePolicy == Exit)
|
|
474 return;
|
|
475
|
77
|
476 for (int i = 0; i < m_downloads.length; ++i) {
|
80
|
477 string key = Format("download_{}_", i);
|
|
478 settings.setValue(key ~ "url", m_downloads[i].m_url);
|
|
479 settings.setValue(key ~ "location", (new QFileInfo(m_downloads[i].m_output)).filePath());
|
|
480 settings.setValue(key ~ "done", m_downloads[i].downloadedSuccessfully());
|
73
|
481 }
|
77
|
482 int i = m_downloads.length;
|
80
|
483 string key = Format("download_{}_", i);
|
|
484 while (settings.contains(key ~ "url")) {
|
|
485 settings.remove(key ~ "url");
|
|
486 settings.remove(key ~ "location");
|
|
487 settings.remove(key ~ "done");
|
|
488 key = Format("download_{}_", ++i);
|
73
|
489 }
|
|
490 }
|
|
491
|
|
492 void updateRow()
|
|
493 {
|
77
|
494 DownloadItem item = cast(DownloadItem) signalSender();
|
73
|
495 int row = m_downloads.indexOf(item);
|
|
496 if (-1 == row)
|
|
497 return;
|
|
498 if (!m_iconProvider)
|
|
499 m_iconProvider = new QFileIconProvider();
|
|
500 QIcon icon = m_iconProvider.icon(item.m_output.fileName());
|
|
501 if (icon.isNull())
|
|
502 icon = style().standardIcon(QStyle.SP_FileIcon);
|
|
503 item.fileIcon.setPixmap(icon.pixmap(48, 48));
|
|
504 downloadsView.setRowHeight(row, item.minimumSizeHint().height());
|
|
505
|
|
506 bool remove = false;
|
|
507 QWebSettings globalSettings = QWebSettings.globalSettings();
|
|
508 if (!item.downloading() && globalSettings.testAttribute(QWebSettings.PrivateBrowsingEnabled))
|
|
509 remove = true;
|
|
510
|
|
511 if (item.downloadedSuccessfully() && removePolicy() == DownloadManager.SuccessFullDownload) {
|
|
512 remove = true;
|
|
513 }
|
|
514 if (remove)
|
|
515 m_model.removeRow(row);
|
|
516
|
77
|
517 cleanupButton.setEnabled(m_downloads.length - activeDownloads() > 0);
|
73
|
518 }
|
|
519
|
|
520 private:
|
|
521
|
|
522 void addItem(DownloadItem item)
|
|
523 {
|
|
524 item.statusChanged.connect(&this.updateRow);
|
77
|
525 int row = m_downloads.length;
|
73
|
526 m_model.beginInsertRows(QModelIndex(), row, row);
|
77
|
527 m_downloads ~= item;
|
73
|
528 m_model.endInsertRows();
|
|
529 updateItemCount();
|
|
530 if (row == 0)
|
|
531 show();
|
|
532 downloadsView.setIndexWidget(m_model.index(row, 0), item);
|
|
533 QIcon icon = style().standardIcon(QStyle.SP_FileIcon);
|
|
534 item.fileIcon.setPixmap(icon.pixmap(48, 48));
|
|
535 downloadsView.setRowHeight(row, item.sizeHint().height());
|
|
536 }
|
|
537
|
|
538
|
|
539 void updateItemCount()
|
|
540 {
|
77
|
541 int count = m_downloads.length;
|
|
542 itemCount.setText(count == 1 ? tr("1 Download") : tr("{} Downloads").arg(count));
|
73
|
543 }
|
|
544
|
|
545 void load()
|
|
546 {
|
|
547 QSettings settings;
|
80
|
548 settings.beginGroup("downloadmanager");
|
|
549 QSize size = settings.value("size").toSize();
|
73
|
550 if (size.isValid())
|
|
551 resize(size);
|
80
|
552 QByteArray value = settings.value("removeDownloadsPolicy", "Never").toByteArray();
|
73
|
553 QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy"));
|
|
554 m_removePolicy = removePolicyEnum.keyToValue(value) == -1 ? Never :
|
74
|
555 cast(RemovePolicy) removePolicyEnum.keyToValue(value);
|
73
|
556
|
|
557 int i = 0;
|
80
|
558 string key = Format("download_{}_", i);
|
|
559 while (settings.contains(key ~ "url")) {
|
|
560 QUrl url = settings.value(key ~ "url").toUrl();
|
|
561 string fileName = settings.value(key ~ "location").toString();
|
|
562 bool done = settings.value(key ~ "done", true).toBool();
|
73
|
563 if (!url.isEmpty() && !fileName.isEmpty()) {
|
|
564 DownloadItem item = new DownloadItem(0, this);
|
|
565 item.m_output.setFileName(fileName);
|
77
|
566 item.fileNameLabel.setText((new QFileInfo(item.m_output.fileName())).fileName());
|
73
|
567 item.m_url = url;
|
|
568 item.stopButton.setVisible(false);
|
|
569 item.stopButton.setEnabled(false);
|
|
570 item.tryAgainButton.setVisible(!done);
|
|
571 item.tryAgainButton.setEnabled(!done);
|
|
572 item.progressBar.setVisible(!done);
|
|
573 addItem(item);
|
|
574 }
|
80
|
575 key = Format("download_{}_", ++i);
|
73
|
576 }
|
77
|
577 cleanupButton.setEnabled(m_downloads.length - activeDownloads() > 0);
|
73
|
578 }
|
|
579
|
|
580 AutoSaver m_autoSaver;
|
|
581 DownloadModel m_model;
|
|
582 QNetworkAccessManager m_manager;
|
|
583 QFileIconProvider m_iconProvider;
|
74
|
584 DownloadItem[] m_downloads;
|
73
|
585 RemovePolicy m_removePolicy;
|
45
|
586 }
|
|
587
|
|
588
|
73
|
589 class DownloadModel : public QAbstractListModel
|
45
|
590 {
|
73
|
591
|
|
592 public:
|
|
593
|
|
594 this(DownloadManager downloadManager, QObject parent = null)
|
|
595 {
|
|
596 super(parent);
|
|
597 m_downloadManager = downloadManager;
|
|
598 }
|
45
|
599
|
73
|
600 QVariant data(QModelIndex index, int role = Qt.DisplayRole)
|
|
601 {
|
|
602 if (index.row() < 0 || index.row() >= rowCount(index.parent()))
|
|
603 return QVariant();
|
|
604 if (role == Qt.ToolTipRole)
|
77
|
605 if (!m_downloadManager.m_downloads[index.row()].downloadedSuccessfully())
|
|
606 return m_downloadManager.m_downloads[index.row()].downloadInfoLabel.text();
|
73
|
607 return QVariant();
|
|
608 }
|
45
|
609
|
73
|
610 int rowCount(QModelIndex parent = QModelIndex())
|
|
611 {
|
77
|
612 return (parent.isValid()) ? 0 : m_downloadManager.m_downloads.length;
|
73
|
613 }
|
|
614
|
|
615 bool removeRows(int row, int count, QModelIndex parent = QModelIndex())
|
|
616 {
|
|
617 if (parent.isValid())
|
|
618 return false;
|
45
|
619
|
73
|
620 int lastRow = row + count - 1;
|
|
621 for (int i = lastRow; i >= row; --i) {
|
77
|
622 if (m_downloadManager.m_downloads[i].downloadedSuccessfully()
|
|
623 || m_downloadManager.m_downloads[i].tryAgainButton.isEnabled()) {
|
73
|
624 beginRemoveRows(parent, i, i);
|
|
625 m_downloadManager.m_downloads.takeAt(i).deleteLater();
|
|
626 endRemoveRows();
|
|
627 }
|
|
628 }
|
|
629 m_downloadManager.m_autoSaver.changeOccurred();
|
|
630 return true;
|
|
631 }
|
45
|
632
|
|
633 private:
|
73
|
634
|
|
635 DownloadManager m_downloadManager;
|
45
|
636 }
|