Add right-click menu to cancel download

This commit is contained in:
Florian Bruhin 2014-06-13 12:19:30 +02:00
parent b5ac700a9e
commit 3e5e8e59c1
3 changed files with 47 additions and 6 deletions

View File

@ -17,6 +17,7 @@
"""Download manager."""
import os
import os.path
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QTimer
@ -44,6 +45,8 @@ class DownloadItem(QObject):
bytes_total: The total count of bytes.
speed: The current download speed, in bytes per second.
fileobj: The file object to download the file to.
filename: The filename of the download.
cancelled: Whether the download was cancelled.
_last_done: The count of bytes which where downloaded when calculating
the speed the last time.
_last_percentage: The remembered percentage for data_changed.
@ -73,6 +76,8 @@ class DownloadItem(QObject):
self.speed = None
self.basename = '???'
self.fileobj = None
self.filename = None
self.cancelled = False
self._do_delayed_write = False
self._last_done = None
self._last_percentage = None
@ -147,10 +152,16 @@ class DownloadItem(QObject):
def cancel(self):
"""Cancel the download."""
logger.debug("cancelled")
self.cancelled = True
self.reply.abort()
self.reply.deleteLater()
if self.fileobj is not None:
self.fileobj.close()
if self.filename is not None:
os.remove(self.filename)
self.finished.emit()
def set_filename(self, filename):
"""Set the filename to save the download to.
@ -158,9 +169,10 @@ class DownloadItem(QObject):
filename: The full filename to save the download to.
None: special value to stop the download.
"""
if self.fileobj is not None:
if self.filename is not None:
raise ValueError("Filename was already set! filename: {}, "
"existing: {}".format(filename, self.fileobj))
"existing: {}".format(filename, self.filename))
self.filename = filename
self.basename = os.path.basename(filename)
try:
self.fileobj = open(filename, 'wb')
@ -209,6 +221,8 @@ class DownloadItem(QObject):
"""
self.bytes_done = self.bytes_total
self.timer.stop()
if self.cancelled:
return
logger.debug("Reply finished, fileobj {}".format(self.fileobj))
if self.fileobj is None:
# We'll handle emptying the buffer and cleaning up as soon as the
@ -334,6 +348,7 @@ class DownloadManager(QObject):
@pyqtSlot()
def on_finished(self):
"""Remove finished download."""
logger.debug("on_finished: {}".format(self.sender()))
idx = self.downloads.index(self.sender())
self.download_about_to_be_finished.emit(idx)
del self.downloads[idx]

View File

@ -22,6 +22,10 @@ from PyQt5.QtCore import (pyqtSlot, Qt, QVariant, QAbstractListModel,
from PyQt5.QtWidgets import QApplication
import qutebrowser.config.config as config
from qutebrowser.utils.usertypes import enum
Role = enum('item', start=Qt.UserRole)
class DownloadModel(QAbstractListModel):
@ -74,6 +78,8 @@ class DownloadModel(QAbstractListModel):
data = config.get('colors', 'downloads.fg')
elif role == Qt.BackgroundRole:
data = item.bg_color()
elif role == Role.item:
data = item
else:
data = QVariant()
return data

View File

@ -17,16 +17,21 @@
"""The ListView to display downloads in."""
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import QListView, QSizePolicy
from PyQt5.QtCore import pyqtSlot, QSize, Qt
from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu
from qutebrowser.models.downloadmodel import DownloadModel
from qutebrowser.models.downloadmodel import DownloadModel, Role
from qutebrowser.config.style import set_register_stylesheet
class DownloadView(QListView):
"""QListView which shows currently running downloads as a bar."""
"""QListView which shows currently running downloads as a bar.
Attributes:
_menu: The QMenu which is currently displayed.
_model: The currently set model.
"""
STYLESHEET = """
QListView {{
@ -40,11 +45,26 @@ class DownloadView(QListView):
set_register_stylesheet(self)
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
self.setFlow(QListView.LeftToRight)
self._menu = None
self._model = DownloadModel()
self._model.rowsInserted.connect(self.updateGeometry)
self._model.rowsRemoved.connect(self.updateGeometry)
self.setModel(self._model)
self.setWrapping(True)
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.show_context_menu)
@pyqtSlot('QPoint')
def show_context_menu(self, point):
"""Show the context menu."""
index = self.indexAt(point)
if not index.isValid():
return
item = self.model().data(index, Role.item)
self._menu = QMenu()
cancel = self._menu.addAction("Cancel")
cancel.triggered.connect(item.cancel)
self._menu.popup(self.viewport().mapToGlobal(point))
def minimumSizeHint(self):
"""Override minimumSizeHint so the size is correct in a layout."""