diff --git a/qutebrowser/app.py b/qutebrowser/app.py index 845a083c9..264cc4c3f 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -54,6 +54,7 @@ from qutebrowser.config.iniparsers import ReadWriteConfigParser from qutebrowser.config.lineparser import LineConfigParser from qutebrowser.browser.cookies import CookieJar from qutebrowser.browser.downloads import DownloadManager +from qutebrowser.models.downloadmodel import DownloadModel from qutebrowser.utils.message import MessageBridge from qutebrowser.utils.misc import (get_standard_dir, actute_warning, get_qt_args) @@ -134,6 +135,7 @@ class Application(QApplication): self.commandmanager = CommandManager() self.searchmanager = SearchManager() self.downloadmanager = DownloadManager() + self.downloadmodel = DownloadModel(self.downloadmanager) self.mainwindow = MainWindow() self.modeman.mainwindow = self.mainwindow diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 82edc315b..833b7d65b 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -50,11 +50,13 @@ class DownloadItem(QObject): arg: The speed in bytes/s percentage_changed: The download percentage changed. arg: The new percentage, -1 if unknown. + finished: The download was finished. """ REFRESH_INTERVAL = 200 speed_changed = pyqtSignal(float) percentage_changed = pyqtSignal(int) + finished = pyqtSignal() def __init__(self, reply, filename, parent=None): """Constructor. @@ -74,6 +76,7 @@ class DownloadItem(QObject): self.fileobj = open(filename, 'wb') reply.downloadProgress.connect(self.on_download_progress) reply.finished.connect(self.on_finished) + reply.finished.connect(self.finished) self.timer = QTimer() self.timer.timeout.connect(self.update_speed) self.timer.setInterval(self.REFRESH_INTERVAL) @@ -139,7 +142,21 @@ class DownloadItem(QObject): class DownloadManager(QObject): - """Manager for running downloads.""" + """Manager for running downloads. + + Signals: + download_about_to_be_added: A new download will be added. + arg: The index of the new download. + download_added: A new download was added. + download_about_to_be_finished: A download will be finished and removed. + arg: The index of the new download. + download_finished: A download was finished and removed. + """ + + download_about_to_be_added = pyqtSignal(int) + download_added = pyqtSignal() + download_about_to_be_finished = pyqtSignal(int) + download_finished = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) @@ -186,4 +203,15 @@ class DownloadManager(QObject): filename = message.modular_question("Save file to:", PromptMode.text, suggested_filename) if filename is not None: - self.downloads.append(DownloadItem(reply, filename)) + download = DownloadItem(reply, filename) + download.finished.connect(self.on_finished) + self.download_about_to_be_added.emit(len(self.downloads) + 1) + self.downloads.append(download) + self.download_added.emit() + + @pyqtSlot() + def on_finished(self): + idx = self.downloads.index(self.sender()) + self.download_about_to_be_finished.emit(idx) + del self.downloads[idx] + self.download_finished.emit() diff --git a/qutebrowser/models/downloadmodel.py b/qutebrowser/models/downloadmodel.py new file mode 100644 index 000000000..c40f60e26 --- /dev/null +++ b/qutebrowser/models/downloadmodel.py @@ -0,0 +1,54 @@ +# Copyright 2014 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""Glue code for qutebrowser.{browser,widgets}.download.""" + +from PyQt5.QtCore import Qt, QVariant, QAbstractListModel +from PyQt5.QtWidgets import QApplication + + +class DownloadModel(QAbstractListModel): + + def __init__(self, parent=None): + super().__init__(parent) + self.downloadmanager = QApplication.instance().downloadmanager + + def headerData(self, section, orientation, role): + if (section == 0 and orientation == Qt.Horizontal and + role == Qt.DisplayRole): + return "Downloads" + else: + return "" + + def data(self, index, role): + if not index.isValid(): + return QVariant() + elif role != Qt.DisplayRole: + return QVariant() + elif index.parent().isValid() or index.column() != 0: + return QVariant() + try: + item = self.downloadmanager.downloads[index.row()] + except IndexError: + return QVariant() + return str(item.percentage) # FIXME + + def rowCount(self, parent): + if parent.isValid(): + # We don't have children + return 0 + return len(self.downloadmanager.downloads) diff --git a/qutebrowser/widgets/downloads.py b/qutebrowser/widgets/downloads.py new file mode 100644 index 000000000..52e80fe3b --- /dev/null +++ b/qutebrowser/widgets/downloads.py @@ -0,0 +1,31 @@ +# Copyright 2014 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""The ListView to display downloads in.""" + +from PyQt5.QtWidgets import QListView + +from qutebrowser.models.downloadmodel import DownloadModel + + +class DownloadView(QListView): + + def __init__(self, parent=None): + super().__init__(parent) + self.setFlow(QListView.LeftToRight) + self._model = DownloadModel() + self.setModel(self._model) diff --git a/qutebrowser/widgets/mainwindow.py b/qutebrowser/widgets/mainwindow.py index e6b52f38c..f37b75ffd 100644 --- a/qutebrowser/widgets/mainwindow.py +++ b/qutebrowser/widgets/mainwindow.py @@ -30,6 +30,7 @@ import qutebrowser.utils.message as message from qutebrowser.widgets.statusbar.bar import StatusBar from qutebrowser.widgets.tabbedbrowser import TabbedBrowser from qutebrowser.widgets.completion import CompletionView +from qutebrowser.widgets.downloads import DownloadView from qutebrowser.utils.usertypes import PromptMode @@ -43,6 +44,7 @@ class MainWindow(QWidget): Attributes: tabs: The TabbedBrowser widget. status: The StatusBar widget. + downloadview: The DownloadView widget. _vbox: The main QVBoxLayout. """ @@ -71,6 +73,10 @@ class MainWindow(QWidget): self.tabs = TabbedBrowser() self._vbox.addWidget(self.tabs) + self.downloadview = DownloadView() + self._vbox.addWidget(self.downloadview) + self.downloadview.show() + self.completion = CompletionView(self) self.completion.resize_completion.connect(self.resize_completion)