diff -r dd4a8b507144 -r 35ec993034e1 WebBrowser/Download/DownloadManager.py --- a/WebBrowser/Download/DownloadManager.py Sat Apr 07 16:40:21 2018 +0200 +++ b/WebBrowser/Download/DownloadManager.py Sun Apr 08 15:54:34 2018 +0200 @@ -9,7 +9,8 @@ from __future__ import unicode_literals -from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QModelIndex, QFileInfo, QUrl +from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QModelIndex, QFileInfo, \ + QUrl, QBasicTimer from PyQt5.QtGui import QCursor, QKeySequence from PyQt5.QtWidgets import QDialog, QStyle, QFileIconProvider, QMenu, \ QApplication, QShortcut @@ -19,12 +20,14 @@ from .Ui_DownloadManager import Ui_DownloadManager from .DownloadModel import DownloadModel +from .DownloadUtilities import speedString, timeString from WebBrowser.WebBrowserWindow import WebBrowserWindow from Utilities.AutoSaver import AutoSaver import UI.PixmapCache import Preferences +import Globals class DownloadManager(QDialog, Ui_DownloadManager): @@ -38,6 +41,8 @@ RemoveExit = 1 RemoveSuccessFullDownload = 2 + UpdateTimerTimeout = 1000 + downloadsCountChanged = pyqtSignal() def __init__(self, parent=None): @@ -50,6 +55,8 @@ self.setupUi(self) self.setWindowFlags(Qt.Window) + self.__winTaskbarButton = None + self.__saveTimer = AutoSaver(self, self.save) self.__model = DownloadModel(self) @@ -78,6 +85,8 @@ self.__clearShortcut.activated.connect(self.on_cleanupButton_clicked) self.__load() + + self.__updateTimer = QBasicTimer() def __customContextMenuRequested(self, pos): """ @@ -165,6 +174,52 @@ return False return True + def __testWebBrowserView(self, view, url): + """ + Private method to test a web browser view against an URL. + + @param view reference to the web browser view to be tested + @type WebBrowserView + @param url URL to test against + @type QUrl + @return flag indicating, that the view is the one for the URL + @rtype bool + """ + if view.tabWidget().count() < 2: + return False + + page = view.page() + if page.history().count() != 0: + return False + + if not page.url().isEmpty() and \ + page.url().host() == url.host(): + return True + + requestedUrl = page.requestedUrl() + if requestedUrl.isEmpty(): + requestedUrl = QUrl(view.tabWidget().urlBarForView(view).text()) + return requestedUrl.isEmpty() or requestedUrl.host() == url.host() + + def __closeDownloadTab(self, url): + """ + Private method to close an empty tab, that was opened only for loading + the download URL. + + @param url download URL + @type QUrl + """ + if self.__testWebBrowserView( + WebBrowserWindow.getWindow().currentBrowser(), url): + WebBrowserWindow.getWindow().closeCurrentBrowser() + return + + for window in WebBrowserWindow.mainWindows(): + for browser in window.browsers(): + if self.__testWebBrowserView(browser, url): + window.closeBrowser(browser) + return + def download(self, downloadItem): """ Public method to download a file. @@ -177,6 +232,8 @@ if url.isEmpty(): return + self.__closeDownloadTab(url) + # Safe Browsing from WebBrowser.SafeBrowsing.SafeBrowsingManager import \ SafeBrowsingManager @@ -206,12 +263,15 @@ parent=self) self.__addItem(itm) - if itm.canceledFileSelect(): - return + self.__startUpdateTimer() + + def show(self): + """ + Public slot to show the download manager dialog. + """ + self.__startUpdateTimer() - if not self.isVisible(): - self.show() - + super(DownloadManager, self).show() self.activateWindow() self.raise_() @@ -247,7 +307,6 @@ # just in case the download finished before the constructor returned self.__updateRow(itm) self.changeOccurred() - self.__updateActiveItemCount() self.downloadsCountChanged.emit() @@ -363,7 +422,6 @@ (self.downloadsCount() - self.activeDownloadsCount()) > 0) self.__loaded = True - self.__updateActiveItemCount() self.downloadsCountChanged.emit() @@ -385,7 +443,7 @@ @pyqtSlot() def on_cleanupButton_clicked(self): """ - Private slot cleanup the downloads. + Private slot to cleanup the downloads. """ if self.downloadsCount() == 0: return @@ -396,33 +454,13 @@ self.__iconProvider = None self.changeOccurred() - self.__updateActiveItemCount() self.downloadsCountChanged.emit() - def __updateItemCount(self): - """ - Private method to update the count label. - """ - count = self.downloadsCount() - self.countLabel.setText(self.tr("%n Download(s)", "", count)) - - def __updateActiveItemCount(self): - """ - Private method to update the window title. - """ - count = self.activeDownloadsCount() - if count > 0: - self.setWindowTitle( - self.tr("Downloading %n file(s)", "", count)) - else: - self.setWindowTitle(self.tr("Downloads")) - def __finished(self): """ Private slot to handle a finished download. """ - self.__updateActiveItemCount() if self.isVisible(): QApplication.alert(self) @@ -468,7 +506,95 @@ Public method to signal a change. """ self.__saveTimer.changeOccurred() - self.__updateItemCount() + + def __taskbarButton(self): + """ + Private method to get a reference to the task bar button (Windows + only). + + @return reference to the task bar button + @rtype QWinTaskbarButton or None + """ + if Globals.isWindowsPlatform(): + from PyQt5.QtWinExtras import QWinTaskbarButton + if self.__winTaskbarButton is None: + window = WebBrowserWindow.mainWindow() + self.__winTaskbarButton = QWinTaskbarButton( + window.windowHandle()) + self.__winTaskbarButton.progress().setRange(0, 100) + + return self.__winTaskbarButton + + def timerEvent(self, evt): + """ + Protected event handler for timer events. + + @param evt reference to the timer event + @type QTimerEvent + """ + if evt.timerId() == self.__updateTimer.timerId(): + if self.activeDownloadsCount() == 0: + self.__stopUpdateTimer() + self.infoLabel.clear() + self.setWindowTitle(self.tr("Download Manager")) + if Globals.isWindowsPlatform(): + self.__taskbarButton.progress().hide() + else: + progresses = [] + for itm in self.__downloads: + if itm is None or \ + itm.downloadCanceled() or \ + not itm.downloading(): + continue + + progresses.append(( + itm.downloadProgress(), + itm.remainingTime(), + itm.currentSpeed() + )) + + if not progresses: + return + + remaining = 0 + progress = 0 + speed = 0.0 + + for progressData in progresses: + if progressData[1] > remaining: + remaining = progressData[1] + progress += progressData[0] + speed += progressData[2] + progress = progress / len(progresses) + + if self.isVisible(): + self.infoLabel.setText(self.tr( + "{0}% of %n file(s) ({1}) {2}", "", + len(progresses)).format( + progress, + speedString(speed), + timeString(remaining), + )) + self.setWindowTitle(self.tr("{0}% - Download Manager")) + + if Globals.isWindowsPlatform(): + self.taskbarButton().progress().show() + self.taskbarButton().progress().setValue(progress) + + super(DownloadManager, self).timerEvent(evt) + + def __startUpdateTimer(self): + """ + Private slot to start the update timer. + """ + if self.activeDownloadsCount() and not self.__updateTimer.isActive(): + self.__updateTimer.start(DownloadManager.UpdateTimerTimeout, self) + + def __stopUpdateTimer(self): + """ + Private slot to stop the update timer. + """ + self.__updateTimer.stop() ########################################################################### ## Context menu related methods below