diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 20b911c4e..7c6deafe5 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -67,6 +67,7 @@ constexpr int CacheTimeout = 24 * 60 * 60 * 1000; // 24 hours in microseconds const char DocsetNameProperty[] = "docsetName"; const char DownloadTypeProperty[] = "downloadType"; const char DownloadPreviousReceived[] = "downloadPreviousReceived"; +const char DownloadTotalSize[] = "downloadTotalSize"; const char ListItemIndexProperty[] = "listItem"; } @@ -437,11 +438,12 @@ void DocsetsDialog::downloadProgress(qint64 received, qint64 total) qint64 previousReceived = 0; const QVariant previousReceivedVariant = reply->property(DownloadPreviousReceived); - if (!previousReceivedVariant.isValid()) + if (!previousReceivedVariant.isValid()) { + reply->setProperty(DownloadTotalSize, total); m_combinedTotal += total; - else + } else { previousReceived = previousReceivedVariant.toLongLong(); - + } m_combinedReceived += received - previousReceived; reply->setProperty(DownloadPreviousReceived, received); @@ -572,6 +574,8 @@ void DocsetsDialog::setupAvailableDocsetsTab() using Registry::DocsetRegistry; ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); + ProgressItemDelegate* del = static_cast(ui->availableDocsetList->itemDelegate()); + connect(del, &ProgressItemDelegate::cancelButtonClicked, this, &DocsetsDialog::cancelDownload); connect(m_docsetRegistry, &DocsetRegistry::docsetUnloaded, this, [this](const QString name) { QListWidgetItem *item = findDocsetListItem(name); @@ -702,6 +706,28 @@ QNetworkReply *DocsetsDialog::download(const QUrl &url) return reply; } +void DocsetsDialog::cancelDownload(const QModelIndex &index) +{ + // Find and delete download jobs corresponding to index + for (QNetworkReply *reply : m_replies) { + if (reply->property(ListItemIndexProperty).toInt() == index.row() + && reply->property(DownloadTypeProperty).toInt() == DownloadDocset) { + QListWidgetItem *listItem = ui->availableDocsetList->item(index.row()); + listItem->setData(ProgressItemDelegate::ShowProgressRole, false); + delete m_tmpFiles.take(reply->property(DocsetNameProperty).toString()); + reply->abort(); + + m_combinedReceived -= reply->property(DownloadPreviousReceived).toLongLong(); + m_combinedTotal -= reply->property(DownloadTotalSize).toLongLong(); + } + } + + // As the current download is cancelled, unselect the current selected item + // This also triggers selectionChanged() and the state of downloadDocsetsButton + // is recomputed on the next selection + ui->availableDocsetList->selectionModel()->clearSelection(); +} + void DocsetsDialog::cancelDownloads() { for (QNetworkReply *reply : m_replies) { diff --git a/src/libs/ui/docsetsdialog.h b/src/libs/ui/docsetsdialog.h index 5fb6ffdf4..c20ac4be1 100644 --- a/src/libs/ui/docsetsdialog.h +++ b/src/libs/ui/docsetsdialog.h @@ -112,6 +112,7 @@ private slots: bool updatesAvailable() const; QNetworkReply *download(const QUrl &url); + void cancelDownload(const QModelIndex &index); void cancelDownloads(); void loadUserFeedList(); diff --git a/src/libs/ui/progressitemdelegate.cpp b/src/libs/ui/progressitemdelegate.cpp index 331f3c4b7..f0a4c299b 100644 --- a/src/libs/ui/progressitemdelegate.cpp +++ b/src/libs/ui/progressitemdelegate.cpp @@ -24,7 +24,10 @@ #include "progressitemdelegate.h" #include +#include #include +#include +#include using namespace Zeal::WidgetUi; @@ -51,7 +54,7 @@ void ProgressItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & // Adjust maximum text width QStyleOptionViewItem styleOption = option; - styleOption.rect.setRight(styleOption.rect.right() - progressBarWidth); + styleOption.rect.setRight(styleOption.rect.right() - progressBarWidth - cancelButtonWidth); // Size progress bar QScopedPointer renderer(new QProgressBar()); @@ -69,7 +72,28 @@ void ProgressItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & painter->translate(styleOption.rect.topRight()); renderer->render(painter); + // Button + QScopedPointer buttonRenderer(new QPushButton(tr("Cancel"))); + buttonRenderer->resize(cancelButtonWidth, styleOption.rect.height()); + + painter->translate(progressBarWidth, 0); + buttonRenderer->render(painter); painter->restore(); QStyledItemDelegate::paint(painter, styleOption, index); } + +bool ProgressItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, + const QStyleOptionViewItem &option, const QModelIndex &index) +{ + QMouseEvent* mouseEvent = static_cast(event); + QRect cancelBounds = option.rect; + cancelBounds.setLeft(cancelBounds.right() - cancelButtonWidth); + + if (event->type() == QEvent::MouseButtonRelease + && index.model()->data(index, ShowProgressRole).toBool() + && cancelBounds.contains(mouseEvent->pos())) + emit cancelButtonClicked(index); + + return QStyledItemDelegate::editorEvent(event, model, option, index); +} diff --git a/src/libs/ui/progressitemdelegate.h b/src/libs/ui/progressitemdelegate.h index 89594e317..4daac6d96 100644 --- a/src/libs/ui/progressitemdelegate.h +++ b/src/libs/ui/progressitemdelegate.h @@ -44,8 +44,15 @@ class ProgressItemDelegate : public QStyledItemDelegate void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + bool editorEvent(QEvent *event, QAbstractItemModel *model, + const QStyleOptionViewItem &option, const QModelIndex &index) override; + +signals: + void cancelButtonClicked(const QModelIndex& index); + private: static const int progressBarWidth = 150; + static const int cancelButtonWidth = 50; }; } // namespace WidgetUi