comparison demos/browser/downloadmanager.d @ 73:7bfd46c330dc

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