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