From a77789a928e84491742febd78d62bde79e38accc Mon Sep 17 00:00:00 2001 From: Karthik Nishanth Date: Sun, 4 Nov 2018 13:26:16 +0530 Subject: [PATCH 1/3] add cancel button for ongoing docset downloads --- src/libs/ui/docsetsdialog.cpp | 32 +++++++++++++++++++++++++--- src/libs/ui/docsetsdialog.h | 1 + src/libs/ui/progressitemdelegate.cpp | 26 +++++++++++++++++++++- src/libs/ui/progressitemdelegate.h | 7 ++++++ 4 files changed, 62 insertions(+), 4 deletions(-) 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 From c9635c5ed62674a783f437c4169a5348c87531e0 Mon Sep 17 00:00:00 2001 From: Karthik Nishanth Date: Mon, 5 Nov 2018 14:22:43 +0530 Subject: [PATCH 2/3] update progress bar with recalculated percentage immediately after cancellation --- src/libs/ui/docsetsdialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 7c6deafe5..1ca75d813 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -726,6 +726,7 @@ void DocsetsDialog::cancelDownload(const QModelIndex &index) // This also triggers selectionChanged() and the state of downloadDocsetsButton // is recomputed on the next selection ui->availableDocsetList->selectionModel()->clearSelection(); + updateCombinedProgress(); } void DocsetsDialog::cancelDownloads() From 72c73b0fad2bb532ea6170421df05d6c24f7307a Mon Sep 17 00:00:00 2001 From: Karthik Nishanth Date: Thu, 8 Nov 2018 21:23:52 +0530 Subject: [PATCH 3/3] fix bugs and update coding style --- src/libs/ui/docsetsdialog.cpp | 29 ++++++++++++++++------------ src/libs/ui/progressitemdelegate.cpp | 21 +++++++++++--------- src/libs/ui/progressitemdelegate.h | 4 +++- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 1ca75d813..015bf6f89 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -237,6 +237,7 @@ void DocsetsDialog::downloadSelectedDocsets() QAbstractItemModel *model = ui->availableDocsetList->model(); model->setData(index, tr("Downloading: %p%"), ProgressItemDelegate::FormatRole); + model->setData(index, true, ProgressItemDelegate::CancellableRole); model->setData(index, 0, ProgressItemDelegate::ValueRole); model->setData(index, true, ProgressItemDelegate::ShowProgressRole); @@ -392,6 +393,7 @@ void DocsetsDialog::downloadCompleted() QListWidgetItem *item = findDocsetListItem(docsetName); if (item) { item->setData(ProgressItemDelegate::ValueRole, 0); + item->setData(ProgressItemDelegate::CancellableRole, false); item->setData(ProgressItemDelegate::FormatRole, tr("Installing: %p%")); } @@ -573,9 +575,9 @@ 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); + ProgressItemDelegate *delegate = new ProgressItemDelegate(this); + connect(delegate, &ProgressItemDelegate::cancelButtonClicked, this, &DocsetsDialog::cancelDownload); + ui->availableDocsetList->setItemDelegate(delegate); connect(m_docsetRegistry, &DocsetRegistry::docsetUnloaded, this, [this](const QString name) { QListWidgetItem *item = findDocsetListItem(name); @@ -610,6 +612,7 @@ void DocsetsDialog::setupAvailableDocsetsTab() QAbstractItemModel *model = ui->availableDocsetList->model(); model->setData(index, tr("Downloading: %p%"), ProgressItemDelegate::FormatRole); + model->setData(index, true, ProgressItemDelegate::CancellableRole); model->setData(index, 0, ProgressItemDelegate::ValueRole); model->setData(index, true, ProgressItemDelegate::ShowProgressRole); @@ -710,16 +713,18 @@ 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(); + if (reply->property(ListItemIndexProperty).toInt() != index.row() + || reply->property(DownloadTypeProperty).toInt() != DownloadDocset) { + continue; } + + 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 diff --git a/src/libs/ui/progressitemdelegate.cpp b/src/libs/ui/progressitemdelegate.cpp index f0a4c299b..e16daab93 100644 --- a/src/libs/ui/progressitemdelegate.cpp +++ b/src/libs/ui/progressitemdelegate.cpp @@ -23,11 +23,11 @@ #include "progressitemdelegate.h" -#include #include +#include +#include #include #include -#include using namespace Zeal::WidgetUi; @@ -63,6 +63,7 @@ void ProgressItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & renderer->setValue(value); const QString format = index.model()->data(index, FormatRole).toString(); + const bool isCancellable = index.model()->data(index, CancellableRole).toBool(); if (!format.isEmpty()) renderer->setFormat(format); @@ -73,11 +74,12 @@ void ProgressItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & renderer->render(painter); // Button - QScopedPointer buttonRenderer(new QPushButton(tr("Cancel"))); - buttonRenderer->resize(cancelButtonWidth, styleOption.rect.height()); - - painter->translate(progressBarWidth, 0); - buttonRenderer->render(painter); + if (isCancellable) { + 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); @@ -86,14 +88,15 @@ void ProgressItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & bool ProgressItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { - QMouseEvent* mouseEvent = static_cast(event); + 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())) + && 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 4daac6d96..01a94d573 100644 --- a/src/libs/ui/progressitemdelegate.h +++ b/src/libs/ui/progressitemdelegate.h @@ -36,7 +36,8 @@ class ProgressItemDelegate : public QStyledItemDelegate enum ProgressRoles { ValueRole = Qt::UserRole + 10, FormatRole, - ShowProgressRole + ShowProgressRole, + CancellableRole }; explicit ProgressItemDelegate(QObject *parent = nullptr); @@ -44,6 +45,7 @@ class ProgressItemDelegate : public QStyledItemDelegate void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; +protected: bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;