comparison demos/browser/downloadmanager.d @ 46:fd6eb3a1759d

license
author eldar
date Sun, 17 May 2009 21:50:06 +0000
parents 71b382c10ef6
children 7bfd46c330dc
comparison
equal deleted inserted replaced
45:71b382c10ef6 46:fd6eb3a1759d
69 69
70 70
71 71
72 class DownloadItem : public QWidget, public Ui_DownloadItem 72 class DownloadItem : public QWidget, public Ui_DownloadItem
73 { 73 {
74 Q_OBJECT 74
75 75 mixin Signal!("statusChanged");
76 signals:
77 void statusChanged();
78 76
79 public: 77 public:
80 78
81 /*! 79 /*!
82 DownloadItem is a widget that is displayed in the download manager list. 80 DownloadItem is a widget that is displayed in the download manager list.
83 It moves the data from the QNetworkReply into the QFile as well 81 It moves the data from the QNetworkReply into the QFile as well
84 as update the information/progressbar and report errors. 82 as update the information/progressbar and report errors.
85 */ 83 */
86 DownloadItem(QNetworkReply *reply = 0, bool requestFileName = false, QWidget *parent = 0) 84 this(QNetworkReply reply = null, bool requestFileName = false, QWidget parent = null)
87 : QWidget(parent) 85 {
88 { 86 super(parent);
89 m_reply = reply; 87 m_reply = reply;
90 m_requestFileName = requestFileName; 88 m_requestFileName = requestFileName;
91 m_bytesReceived = 0; 89 m_bytesReceived = 0;
92 90
93 setupUi(this); 91 setupUi(this);
94 QPalette p = downloadInfoLabel.palette(); 92 QPalette p = downloadInfoLabel.palette();
95 p.setColor(QPalette::Text, Qt.darkGray); 93 p.setColor(QPalette.Text, Qt.darkGray);
96 downloadInfoLabel.setPalette(p); 94 downloadInfoLabel.setPalette(p);
97 progressBar.setMaximum(0); 95 progressBar.setMaximum(0);
98 tryAgainButton.hide(); 96 tryAgainButton.hide();
99 connect(stopButton, SIGNAL(clicked()), this, SLOT(stop())); 97 stopButton.clicked.connect(&this.stop);
100 connect(openButton, SIGNAL(clicked()), this, SLOT(open())); 98 openButton.clicked.connect(&this.open);
101 connect(tryAgainButton, SIGNAL(clicked()), this, SLOT(tryAgain())); 99 tryAgainButton.clicked.connect(&this.tryAgain);
102 100
103 init(); 101 init();
104 } 102 }
105 103
106 104
107 bool downloading() 105 bool downloading()
108 { 106 {
109 return (progressBar.isVisible()); 107 return (progressBar.isVisible());
110 } 108 }
111 109
112 110
113 bool downloadedSuccessfully() 111 bool downloadedSuccessfully()
114 { 112 {
115 return (stopButton.isHidden() && tryAgainButton.isHidden()); 113 return (stopButton.isHidden() && tryAgainButton.isHidden());
116 } 114 }
117 115
118 116
119 QUrl m_url; 117 QUrl m_url;
120 118
121 QFile m_output; 119 QFile m_output;
122 QNetworkReply *m_reply; 120 QNetworkReply *m_reply;
123 121
124 private slots: 122 private: // slots:
125 void stop() 123 void stop()
126 { 124 {
127 setUpdatesEnabled(false); 125 setUpdatesEnabled(false);
128 stopButton.setEnabled(false); 126 stopButton.setEnabled(false);
129 stopButton.hide(); 127 stopButton.hide();
130 tryAgainButton.setEnabled(true); 128 tryAgainButton.setEnabled(true);
131 tryAgainButton.show(); 129 tryAgainButton.show();
132 setUpdatesEnabled(true); 130 setUpdatesEnabled(true);
133 m_reply.abort(); 131 m_reply.abort();
134 } 132 }
135 133
136 void tryAgain() 134 void tryAgain()
137 { 135 {
138 if (!tryAgainButton.isEnabled()) 136 if (!tryAgainButton.isEnabled())
139 return; 137 return;
140 138
141 tryAgainButton.setEnabled(false); 139 tryAgainButton.setEnabled(false);
142 tryAgainButton.setVisible(false); 140 tryAgainButton.setVisible(false);
143 stopButton.setEnabled(true); 141 stopButton.setEnabled(true);
144 stopButton.setVisible(true); 142 stopButton.setVisible(true);
145 progressBar.setVisible(true); 143 progressBar.setVisible(true);
146 144
147 QNetworkReply *r = BrowserApplication::networkAccessManager().get(QNetworkRequest(m_url)); 145 QNetworkReply *r = BrowserApplication.networkAccessManager().get(QNetworkRequest(m_url));
148 if (m_reply) 146 if (m_reply)
149 m_reply.deleteLater(); 147 m_reply.deleteLater();
150 if (m_output.exists()) 148 if (m_output.exists())
151 m_output.remove(); 149 m_output.remove();
152 m_reply = r; 150 m_reply = r;
153 init(); 151 init();
154 emit statusChanged(); 152 emit statusChanged();
155 } 153 }
156 154
157 void open() 155 void open()
158 { 156 {
159 QFileInfo info(m_output); 157 QFileInfo info(m_output);
160 QUrl url = QUrl::fromLocalFile(info.absolutePath()); 158 QUrl url = QUrl.fromLocalFile(info.absolutePath());
161 QDesktopServices::openUrl(url); 159 QDesktopServices.openUrl(url);
162 } 160 }
163 161
164 void downloadReadyRead() 162 void downloadReadyRead()
165 { 163 {
166 if (m_requestFileName && m_output.fileName().isEmpty()) 164 if (m_requestFileName && m_output.fileName().isEmpty())
167 return; 165 return;
168 if (!m_output.isOpen()) { 166 if (!m_output.isOpen()) {
169 // in case someone else has already put a file there 167 // in case someone else has already put a file there
170 if (!m_requestFileName) 168 if (!m_requestFileName)
171 getFileName(); 169 getFileName();
172 if (!m_output.open(QIODevice::WriteOnly)) { 170 if (!m_output.open(QIODevice.WriteOnly)) {
173 downloadInfoLabel.setText(tr("Error opening save file: %1") 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")
174 .arg(m_output.errorString())); 181 .arg(m_output.errorString()));
175 stopButton.click(); 182 stopButton.click();
176 emit statusChanged(); 183 }
177 return; 184 }
178 } 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();
179 emit statusChanged(); 221 emit statusChanged();
180 } 222 }
181 if (-1 == m_output.write(m_reply.readAll())) {
182 downloadInfoLabel.setText(tr("Error saving: %1")
183 .arg(m_output.errorString()));
184 stopButton.click();
185 }
186 }
187
188 void error(QNetworkReply::NetworkError code)
189 {
190 qDebug() << "DownloadItem::error" << m_reply.errorString() << m_url;
191 downloadInfoLabel.setText(tr("Network Error: %1").arg(m_reply.errorString()));
192 tryAgainButton.setEnabled(true);
193 tryAgainButton.setVisible(true);
194 }
195
196
197 void downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
198 {
199 m_bytesReceived = bytesReceived;
200 if (bytesTotal == -1) {
201 progressBar.setValue(0);
202 progressBar.setMaximum(0);
203 } else {
204 progressBar.setValue(bytesReceived);
205 progressBar.setMaximum(bytesTotal);
206 }
207 updateInfoLabel();
208 }
209
210
211 void metaDataChanged()
212 {
213 qDebug() << "DownloadItem::metaDataChanged: not handled.";
214 }
215
216 void finished()
217 {
218 progressBar.hide();
219 stopButton.setEnabled(false);
220 stopButton.hide();
221 m_output.close();
222 updateInfoLabel();
223 emit statusChanged();
224 }
225 223
226 private: 224 private:
227 void getFileName() 225 void getFileName()
228 { 226 {
229 QSettings settings; 227 QSettings settings;
230 settings.beginGroup(QLatin1String("downloadmanager")); 228 settings.beginGroup(QLatin1String("downloadmanager"));
231 QString defaultLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); 229 QString defaultLocation = QDesktopServices.storageLocation(QDesktopServices.DesktopLocation);
232 QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString(); 230 QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString();
233 if (!downloadDirectory.isEmpty()) 231 if (!downloadDirectory.isEmpty())
234 downloadDirectory += QLatin1Char('/'); 232 downloadDirectory += QLatin1Char('/');
235 233
236 QString defaultFileName = saveFileName(downloadDirectory); 234 QString defaultFileName = saveFileName(downloadDirectory);
237 QString fileName = defaultFileName; 235 QString fileName = defaultFileName;
238 if (m_requestFileName) { 236 if (m_requestFileName) {
239 fileName = QFileDialog::getSaveFileName(this, tr("Save File"), defaultFileName); 237 fileName = QFileDialog.getSaveFileName(this, tr("Save File"), defaultFileName);
240 if (fileName.isEmpty()) { 238 if (fileName.isEmpty()) {
241 m_reply.close(); 239 m_reply.close();
242 fileNameLabel.setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName())); 240 fileNameLabel.setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName()));
241 return;
242 }
243 }
244 m_output.setFileName(fileName);
245 fileNameLabel.setText(QFileInfo(m_output.fileName()).fileName());
246 if (m_requestFileName)
247 downloadReadyRead();
248 }
249
250 void init()
251 {
252 if (!m_reply)
243 return; 253 return;
244 } 254
245 } 255 // attach to the m_reply
246 m_output.setFileName(fileName); 256 m_url = m_reply.url();
247 fileNameLabel.setText(QFileInfo(m_output.fileName()).fileName()); 257 m_reply.setParent(this);
248 if (m_requestFileName) 258 connect(m_reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
249 downloadReadyRead(); 259 connect(m_reply, SIGNAL(error(QNetworkReply.NetworkError)),
250 } 260 this, SLOT(error(QNetworkReply.NetworkError)));
251 261 connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)),
252 void init() 262 this, SLOT(downloadProgress(qint64, qint64)));
253 { 263 connect(m_reply, SIGNAL(metaDataChanged()),
254 if (!m_reply) 264 this, SLOT(metaDataChanged()));
255 return; 265 connect(m_reply, SIGNAL(finished()),
256 266 this, SLOT(finished()));
257 // attach to the m_reply 267
258 m_url = m_reply.url(); 268 // reset info
259 m_reply.setParent(this); 269 downloadInfoLabel.clear();
260 connect(m_reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead())); 270 progressBar.setValue(0);
261 connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), 271 getFileName();
262 this, SLOT(error(QNetworkReply::NetworkError))); 272
263 connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), 273 // start timer for the download estimation
264 this, SLOT(downloadProgress(qint64, qint64))); 274 m_downloadTime.start();
265 connect(m_reply, SIGNAL(metaDataChanged()), 275
266 this, SLOT(metaDataChanged())); 276 if (m_reply.error() != QNetworkReply.NoError) {
267 connect(m_reply, SIGNAL(finished()), 277 error(m_reply.error());
268 this, SLOT(finished())); 278 finished();
269 279 }
270 // reset info 280 }
271 downloadInfoLabel.clear();
272 progressBar.setValue(0);
273 getFileName();
274
275 // start timer for the download estimation
276 m_downloadTime.start();
277
278 if (m_reply.error() != QNetworkReply::NoError) {
279 error(m_reply.error());
280 finished();
281 }
282 }
283 281
284 void updateInfoLabel() 282 void updateInfoLabel()
285 { 283 {
286 if (m_reply.error() == QNetworkReply::NoError) 284 if (m_reply.error() == QNetworkReply.NoError)
287 return; 285 return;
288 286
289 qint64 bytesTotal = progressBar.maximum(); 287 qint64 bytesTotal = progressBar.maximum();
290 bool running = !downloadedSuccessfully(); 288 bool running = !downloadedSuccessfully();
291 289
292 // update info label 290 // update info label
293 double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed(); 291 double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed();
294 double timeRemaining = ((double)(bytesTotal - m_bytesReceived)) / speed; 292 double timeRemaining = ((double)(bytesTotal - m_bytesReceived)) / speed;
295 QString timeRemainingString = tr("seconds"); 293 QString timeRemainingString = tr("seconds");
296 if (timeRemaining > 60) { 294 if (timeRemaining > 60) {
297 timeRemaining = timeRemaining / 60; 295 timeRemaining = timeRemaining / 60;
298 timeRemainingString = tr("minutes"); 296 timeRemainingString = tr("minutes");
299 } 297 }
300 timeRemaining = floor(timeRemaining); 298 timeRemaining = floor(timeRemaining);
301 299
302 // When downloading the eta should never be 0 300 // When downloading the eta should never be 0
303 if (timeRemaining == 0) 301 if (timeRemaining == 0)
304 timeRemaining = 1; 302 timeRemaining = 1;
305 303
306 QString info; 304 QString info;
307 if (running) { 305 if (running) {
308 QString remaining; 306 QString remaining;
309 if (bytesTotal != 0) 307 if (bytesTotal != 0)
310 remaining = tr("- %4 %5 remaining") 308 remaining = tr("- %4 %5 remaining")
311 .arg(timeRemaining) 309 .arg(timeRemaining)
312 .arg(timeRemainingString); 310 .arg(timeRemainingString);
313 info = QString(tr("%1 of %2 (%3/sec) %4")) 311 info = QString(tr("%1 of %2 (%3/sec) %4"))
314 .arg(dataString(m_bytesReceived))
315 .arg(bytesTotal == 0 ? tr("?") : dataString(bytesTotal))
316 .arg(dataString((int)speed))
317 .arg(remaining);
318 } else {
319 if (m_bytesReceived == bytesTotal)
320 info = dataString(m_output.size());
321 else
322 info = tr("%1 of %2 - Stopped")
323 .arg(dataString(m_bytesReceived)) 312 .arg(dataString(m_bytesReceived))
324 .arg(dataString(bytesTotal)); 313 .arg(bytesTotal == 0 ? tr("?") : dataString(bytesTotal))
325 } 314 .arg(dataString((int)speed))
326 downloadInfoLabel.setText(info); 315 .arg(remaining);
327 } 316 } else {
317 if (m_bytesReceived == bytesTotal)
318 info = dataString(m_output.size());
319 else
320 info = tr("%1 of %2 - Stopped")
321 .arg(dataString(m_bytesReceived))
322 .arg(dataString(bytesTotal));
323 }
324 downloadInfoLabel.setText(info);
325 }
328 326
329 QString dataString(int size) 327 QString dataString(int size)
330 { 328 {
331 QString unit; 329 QString unit;
332 if (size < 1024) { 330 if (size < 1024) {
333 unit = tr("bytes"); 331 unit = tr("bytes");
334 } else if (size < 1024*1024) { 332 } else if (size < 1024*1024) {
335 size /= 1024; 333 size /= 1024;
336 unit = tr("kB"); 334 unit = tr("kB");
337 } else { 335 } else {
338 size /= 1024*1024; 336 size /= 1024*1024;
339 unit = tr("MB"); 337 unit = tr("MB");
340 } 338 }
341 return QString(QLatin1String("%1 %2")).arg(size).arg(unit); 339 return QString(QLatin1String("%1 %2")).arg(size).arg(unit);
342 } 340 }
343 341
344 QString saveFileName(const QString &directory); 342 QString saveFileName(const QString &directory);
345 { 343 {
346 // Move this function into QNetworkReply to also get file name sent from the server 344 // Move this function into QNetworkReply to also get file name sent from the server
347 QString path = m_url.path(); 345 QString path = m_url.path();
348 QFileInfo info(path); 346 QFileInfo info(path);
349 QString baseName = info.completeBaseName(); 347 QString baseName = info.completeBaseName();
350 QString endName = info.suffix(); 348 QString endName = info.suffix();
351 349
352 if (baseName.isEmpty()) { 350 if (baseName.isEmpty()) {
353 baseName = QLatin1String("unnamed_download"); 351 baseName = QLatin1String("unnamed_download");
354 qDebug() << "DownloadManager:: downloading unknown file:" << m_url; 352 qDebug() << "DownloadManager:: downloading unknown file:" << m_url;
355 } 353 }
356 QString name = directory + baseName + QLatin1Char('.') + endName; 354 QString name = directory + baseName + QLatin1Char('.') + endName;
357 if (QFile::exists(name)) { 355 if (QFile.exists(name)) {
358 // already exists, don't overwrite 356 // already exists, don't overwrite
359 int i = 1; 357 int i = 1;
360 do { 358 do {
361 name = directory + baseName + QLatin1Char('-') + QString::number(i++) + QLatin1Char('.') + endName; 359 name = directory + baseName + QLatin1Char('-') + QString.number(i++) + QLatin1Char('.') + endName;
362 } while (QFile::exists(name)); 360 } while (QFile.exists(name));
363 } 361 }
364 return name; 362 return name;
365 } 363 }
366 364
367 bool m_requestFileName; 365 bool m_requestFileName;
368 qint64 m_bytesReceived; 366 qint64 m_bytesReceived;
369 QTime m_downloadTime; 367 QTime m_downloadTime;
370 }; 368 };
395 extract zipped files or anything fancy. 393 extract zipped files or anything fancy.
396 */ 394 */
397 this(QWidget *parent = null) 395 this(QWidget *parent = null)
398 : QDialog(parent) 396 : QDialog(parent)
399 , m_autoSaver(new AutoSaver(this)) 397 , m_autoSaver(new AutoSaver(this))
400 , m_manager(BrowserApplication::networkAccessManager()) 398 , m_manager(BrowserApplication.networkAccessManager())
401 , m_iconProvider(0) 399 , m_iconProvider(0)
402 , m_removePolicy(Never) 400 , m_removePolicy(Never)
403 { 401 {
404 setupUi(this); 402 setupUi(this);
405 downloadsView.setShowGrid(false); 403 downloadsView.setShowGrid(false);
458 { download(QNetworkRequest(url), requestFileName); } 456 { download(QNetworkRequest(url), requestFileName); }
459 void handleUnsupportedContent(QNetworkReply *reply, bool requestFileName = false); 457 void handleUnsupportedContent(QNetworkReply *reply, bool requestFileName = false);
460 { 458 {
461 if (!reply || reply.url().isEmpty()) 459 if (!reply || reply.url().isEmpty())
462 return; 460 return;
463 QVariant header = reply.header(QNetworkRequest::ContentLengthHeader); 461 QVariant header = reply.header(QNetworkRequest.ContentLengthHeader);
464 bool ok; 462 bool ok;
465 int size = header.toInt(&ok); 463 int size = header.toInt(&ok);
466 if (ok && size == 0) 464 if (ok && size == 0)
467 return; 465 return;
468 466
519 return; 517 return;
520 if (!m_iconProvider) 518 if (!m_iconProvider)
521 m_iconProvider = new QFileIconProvider(); 519 m_iconProvider = new QFileIconProvider();
522 QIcon icon = m_iconProvider.icon(item.m_output.fileName()); 520 QIcon icon = m_iconProvider.icon(item.m_output.fileName());
523 if (icon.isNull()) 521 if (icon.isNull())
524 icon = style().standardIcon(QStyle::SP_FileIcon); 522 icon = style().standardIcon(QStyle.SP_FileIcon);
525 item.fileIcon.setPixmap(icon.pixmap(48, 48)); 523 item.fileIcon.setPixmap(icon.pixmap(48, 48));
526 downloadsView.setRowHeight(row, item.minimumSizeHint().height()); 524 downloadsView.setRowHeight(row, item.minimumSizeHint().height());
527 525
528 bool remove = false; 526 bool remove = false;
529 QWebSettings *globalSettings = QWebSettings::globalSettings(); 527 QWebSettings *globalSettings = QWebSettings.globalSettings();
530 if (!item.downloading() 528 if (!item.downloading()
531 && globalSettings.testAttribute(QWebSettings::PrivateBrowsingEnabled)) 529 && globalSettings.testAttribute(QWebSettings.PrivateBrowsingEnabled))
532 remove = true; 530 remove = true;
533 531
534 if (item.downloadedSuccessfully() 532 if (item.downloadedSuccessfully()
535 && removePolicy() == DownloadManager::SuccessFullDownload) { 533 && removePolicy() == DownloadManager.SuccessFullDownload) {
536 remove = true; 534 remove = true;
537 } 535 }
538 if (remove) 536 if (remove)
539 m_model.removeRow(row); 537 m_model.removeRow(row);
540 538
551 m_model.endInsertRows(); 549 m_model.endInsertRows();
552 updateItemCount(); 550 updateItemCount();
553 if (row == 0) 551 if (row == 0)
554 show(); 552 show();
555 downloadsView.setIndexWidget(m_model.index(row, 0), item); 553 downloadsView.setIndexWidget(m_model.index(row, 0), item);
556 QIcon icon = style().standardIcon(QStyle::SP_FileIcon); 554 QIcon icon = style().standardIcon(QStyle.SP_FileIcon);
557 item.fileIcon.setPixmap(icon.pixmap(48, 48)); 555 item.fileIcon.setPixmap(icon.pixmap(48, 48));
558 downloadsView.setRowHeight(row, item.sizeHint().height()); 556 downloadsView.setRowHeight(row, item.sizeHint().height());
559 } 557 }
560 558
561 559
563 { 561 {
564 int count = m_downloads.count(); 562 int count = m_downloads.count();
565 itemCount.setText(count == 1 ? tr("1 Download") : tr("%1 Downloads").arg(count)); 563 itemCount.setText(count == 1 ? tr("1 Download") : tr("%1 Downloads").arg(count));
566 } 564 }
567 565
568 DownloadModel::DownloadModel(DownloadManager *downloadManager, QObject *parent) 566 DownloadModel.DownloadModel(DownloadManager *downloadManager, QObject *parent)
569 : QAbstractListModel(parent) 567 : QAbstractListModel(parent)
570 , m_downloadManager(downloadManager) 568 , m_downloadManager(downloadManager)
571 { 569 {
572 } 570 }
573 571