Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cancel button for each of the ongoing docset downloads #1027

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions src/libs/ui/docsetsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}

Expand Down Expand Up @@ -236,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);

Expand Down Expand Up @@ -391,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%"));
}

Expand Down Expand Up @@ -437,11 +440,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);

Expand Down Expand Up @@ -571,7 +575,9 @@ void DocsetsDialog::setupAvailableDocsetsTab()
{
using Registry::DocsetRegistry;

ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this));
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);
Expand Down Expand Up @@ -606,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);

Expand Down Expand Up @@ -702,6 +709,31 @@ 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) {
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
// This also triggers selectionChanged() and the state of downloadDocsetsButton
// is recomputed on the next selection
ui->availableDocsetList->selectionModel()->clearSelection();
updateCombinedProgress();
}

void DocsetsDialog::cancelDownloads()
{
for (QNetworkReply *reply : m_replies) {
Expand Down
1 change: 1 addition & 0 deletions src/libs/ui/docsetsdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ private slots:
bool updatesAvailable() const;

QNetworkReply *download(const QUrl &url);
void cancelDownload(const QModelIndex &index);
void cancelDownloads();

void loadUserFeedList();
Expand Down
29 changes: 28 additions & 1 deletion src/libs/ui/progressitemdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@

#include "progressitemdelegate.h"

#include <QEvent>
nishanthkarthik marked this conversation as resolved.
Show resolved Hide resolved
#include <QMouseEvent>
#include <QPainter>
#include <QProgressBar>
#include <QPushButton>

using namespace Zeal::WidgetUi;

Expand All @@ -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<QProgressBar> renderer(new QProgressBar());
Expand All @@ -60,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);

Expand All @@ -69,7 +73,30 @@ void ProgressItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
painter->translate(styleOption.rect.topRight());
renderer->render(painter);

// Button
if (isCancellable) {
QScopedPointer<QPushButton> 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<QMouseEvent *>(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);
}
11 changes: 10 additions & 1 deletion src/libs/ui/progressitemdelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,25 @@ class ProgressItemDelegate : public QStyledItemDelegate
enum ProgressRoles {
ValueRole = Qt::UserRole + 10,
FormatRole,
ShowProgressRole
ShowProgressRole,
CancellableRole
};

explicit ProgressItemDelegate(QObject *parent = nullptr);

void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;

protected:
bool editorEvent(QEvent *event, QAbstractItemModel *model,
nishanthkarthik marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Down