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