--- a/eric6/Helpviewer/Download/DownloadManager.py Sat Sep 07 14:45:27 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,537 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2010 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing the download manager class. -""" - -from __future__ import unicode_literals - -from PyQt5.QtCore import pyqtSlot, Qt, QModelIndex, QFileInfo -from PyQt5.QtGui import QCursor -from PyQt5.QtWidgets import QDialog, QStyle, QFileIconProvider, QMenu, \ - QApplication -from PyQt5.QtNetwork import QNetworkRequest -from PyQt5.QtWebKit import QWebSettings - -from E5Gui import E5MessageBox - -from .Ui_DownloadManager import Ui_DownloadManager - -from .DownloadModel import DownloadModel - -import Helpviewer.HelpWindow - -from Utilities.AutoSaver import AutoSaver -import UI.PixmapCache -import Preferences - - -class DownloadManager(QDialog, Ui_DownloadManager): - """ - Class implementing the download manager. - """ - RemoveNever = 0 - RemoveExit = 1 - RemoveSuccessFullDownload = 2 - - def __init__(self, parent=None): - """ - Constructor - - @param parent reference to the parent widget (QWidget) - """ - super(DownloadManager, self).__init__(parent) - self.setupUi(self) - self.setWindowFlags(Qt.Window) - - self.__saveTimer = AutoSaver(self, self.save) - - self.__model = DownloadModel(self) - self.__manager = Helpviewer.HelpWindow.HelpWindow\ - .networkAccessManager() - - self.__iconProvider = None - self.__downloads = [] - self.__downloadDirectory = "" - self.__loaded = False - - self.__rowHeightMultiplier = 1.1 - - self.setDownloadDirectory(Preferences.getUI("DownloadPath")) - - self.downloadsView.setShowGrid(False) - self.downloadsView.verticalHeader().hide() - self.downloadsView.horizontalHeader().hide() - self.downloadsView.setAlternatingRowColors(True) - self.downloadsView.horizontalHeader().setStretchLastSection(True) - self.downloadsView.setModel(self.__model) - self.downloadsView.setContextMenuPolicy(Qt.CustomContextMenu) - self.downloadsView.customContextMenuRequested.connect( - self.__customContextMenuRequested) - - self.__load() - - def __customContextMenuRequested(self, pos): - """ - Private slot to handle the context menu request for the bookmarks tree. - - @param pos position the context menu was requested (QPoint) - """ - menu = QMenu() - - selectedRowsCount = len( - self.downloadsView.selectionModel().selectedRows()) - - if selectedRowsCount == 1: - row = self.downloadsView.selectionModel().selectedRows()[0].row() - itm = self.__downloads[row] - if itm.downloadCanceled(): - menu.addAction( - UI.PixmapCache.getIcon("restart.png"), - self.tr("Retry"), self.__contextMenuRetry) - else: - if itm.downloadedSuccessfully(): - menu.addAction( - UI.PixmapCache.getIcon("open.png"), - self.tr("Open"), self.__contextMenuOpen) - elif itm.downloading(): - menu.addAction( - UI.PixmapCache.getIcon("stopLoading.png"), - self.tr("Cancel"), self.__contextMenuCancel) - menu.addSeparator() - menu.addAction( - self.tr("Open Containing Folder"), - self.__contextMenuOpenFolder) - menu.addSeparator() - menu.addAction( - self.tr("Go to Download Page"), - self.__contextMenuGotoPage) - menu.addAction( - self.tr("Copy Download Link"), - self.__contextMenuCopyLink) - menu.addSeparator() - menu.addAction(self.tr("Select All"), self.__contextMenuSelectAll) - if selectedRowsCount > 1 or \ - (selectedRowsCount == 1 and - not self.__downloads[ - self.downloadsView.selectionModel().selectedRows()[0].row()] - .downloading()): - menu.addSeparator() - menu.addAction( - self.tr("Remove From List"), - self.__contextMenuRemoveSelected) - - menu.exec_(QCursor.pos()) - - def shutdown(self): - """ - Public method to stop the download manager. - """ - self.__saveTimer.changeOccurred() - self.__saveTimer.saveIfNeccessary() - self.close() - - def activeDownloads(self): - """ - Public method to get the number of active downloads. - - @return number of active downloads (integer) - """ - count = 0 - - for download in self.__downloads: - if download.downloading(): - count += 1 - return count - - def allowQuit(self): - """ - Public method to check, if it is ok to quit. - - @return flag indicating allowance to quit (boolean) - """ - if self.activeDownloads() > 0: - res = E5MessageBox.yesNo( - self, - self.tr(""), - self.tr("""There are %n downloads in progress.\n""" - """Do you want to quit anyway?""", "", - self.activeDownloads()), - icon=E5MessageBox.Warning) - if not res: - self.show() - return False - return True - - def download(self, requestOrUrl, requestFileName=False, mainWindow=None): - """ - Public method to download a file. - - @param requestOrUrl reference to a request object (QNetworkRequest) - or a URL to be downloaded (QUrl) - @keyparam requestFileName flag indicating to ask for the - download file name (boolean) - @keyparam mainWindow reference to the main window (HelpWindow) - """ - request = QNetworkRequest(requestOrUrl) - if request.url().isEmpty(): - return - self.handleUnsupportedContent( - self.__manager.get(request), - requestFileName=requestFileName, - download=True, - mainWindow=mainWindow) - - def handleUnsupportedContent(self, reply, requestFileName=False, - webPage=None, download=False, - mainWindow=None): - """ - Public method to handle unsupported content by downloading the - referenced resource. - - @param reply reference to the reply object (QNetworkReply) - @keyparam requestFileName indicating to ask for a filename - (boolean) - @keyparam webPage reference to the web page (HelpWebPage) - @keyparam download flag indicating a download request (boolean) - @keyparam mainWindow reference to the main window (HelpWindow) - """ - if reply is None or reply.url().isEmpty(): - return - - size = reply.header(QNetworkRequest.ContentLengthHeader) - if size == 0: - return - - from .DownloadItem import DownloadItem - itm = DownloadItem( - reply=reply, requestFilename=requestFileName, - webPage=webPage, download=download, parent=self, - mainWindow=mainWindow) - self.__addItem(itm) - - if itm.canceledFileSelect(): - return - - if not self.isVisible(): - self.show() - - self.activateWindow() - self.raise_() - - def __addItem(self, itm, append=False): - """ - Private method to add a download to the list of downloads. - - @param itm reference to the download item - @type DownloadItem - @param append flag indicating to append the item - @type bool - """ - itm.statusChanged.connect(lambda: self.__updateRow(itm)) - itm.downloadFinished.connect(self.__finished) - - # insert at top of window - if append: - row = len(self.__downloads) - else: - row = 0 - self.__model.beginInsertRows(QModelIndex(), row, row) - if append: - self.__downloads.append(itm) - else: - self.__downloads.insert(0, itm) - self.__model.endInsertRows() - - self.downloadsView.setIndexWidget(self.__model.index(row, 0), itm) - icon = self.style().standardIcon(QStyle.SP_FileIcon) - itm.setIcon(icon) - self.downloadsView.setRowHeight( - row, itm.sizeHint().height() * self.__rowHeightMultiplier) - # just in case the download finished before the constructor returned - self.__updateRow(itm) - self.changeOccurred() - self.__updateActiveItemCount() - - def __updateRow(self, itm): - """ - Private slot to update a download item. - - @param itm reference to the download item - @type DownloadItem - """ - if itm not in self.__downloads: - return - - row = self.__downloads.index(itm) - - if self.__iconProvider is None: - self.__iconProvider = QFileIconProvider() - - icon = self.__iconProvider.icon(QFileInfo(itm.fileName())) - if icon.isNull(): - icon = self.style().standardIcon(QStyle.SP_FileIcon) - itm.setIcon(icon) - - self.downloadsView.setRowHeight( - row, - itm.minimumSizeHint().height() * self.__rowHeightMultiplier) - - remove = False - globalSettings = QWebSettings.globalSettings() - if not itm.downloading() and \ - globalSettings.testAttribute(QWebSettings.PrivateBrowsingEnabled): - remove = True - - if itm.downloadedSuccessfully() and \ - self.removePolicy() == DownloadManager.RemoveSuccessFullDownload: - remove = True - - if remove: - self.__model.removeRow(row) - - self.cleanupButton.setEnabled( - (len(self.__downloads) - self.activeDownloads()) > 0) - - # record the change - self.changeOccurred() - - def removePolicy(self): - """ - Public method to get the remove policy. - - @return remove policy (integer) - """ - return Preferences.getHelp("DownloadManagerRemovePolicy") - - def setRemovePolicy(self, policy): - """ - Public method to set the remove policy. - - @param policy policy to be set - (DownloadManager.RemoveExit, DownloadManager.RemoveNever, - DownloadManager.RemoveSuccessFullDownload) - """ - assert policy in (DownloadManager.RemoveExit, - DownloadManager.RemoveNever, - DownloadManager.RemoveSuccessFullDownload) - - if policy == self.removePolicy(): - return - - Preferences.setHelp("DownloadManagerRemovePolicy", self.policy) - - def save(self): - """ - Public method to save the download settings. - """ - if not self.__loaded: - return - - Preferences.setHelp("DownloadManagerSize", self.size()) - Preferences.setHelp("DownloadManagerPosition", self.pos()) - if self.removePolicy() == DownloadManager.RemoveExit: - return - - downloads = [] - for download in self.__downloads: - downloads.append(download.getData()) - Preferences.setHelp("DownloadManagerDownloads", downloads) - - def __load(self): - """ - Private method to load the download settings. - """ - if self.__loaded: - return - - size = Preferences.getHelp("DownloadManagerSize") - if size.isValid(): - self.resize(size) - pos = Preferences.getHelp("DownloadManagerPosition") - self.move(pos) - - downloads = Preferences.getHelp("DownloadManagerDownloads") - for download in downloads: - if not download[0].isEmpty() and \ - download[1] != "": - from .DownloadItem import DownloadItem - itm = DownloadItem(parent=self) - itm.setData(download) - self.__addItem(itm, append=True) - self.cleanupButton.setEnabled( - (len(self.__downloads) - self.activeDownloads()) > 0) - - self.__loaded = True - self.__updateActiveItemCount() - - def cleanup(self): - """ - Public slot to cleanup the downloads. - """ - self.on_cleanupButton_clicked() - - @pyqtSlot() - def on_cleanupButton_clicked(self): - """ - Private slot cleanup the downloads. - """ - if len(self.__downloads) == 0: - return - - self.__model.removeRows(0, len(self.__downloads)) - if len(self.__downloads) == 0 and \ - self.__iconProvider is not None: - self.__iconProvider = None - - self.changeOccurred() - self.__updateActiveItemCount() - - def __updateItemCount(self): - """ - Private method to update the count label. - """ - count = len(self.__downloads) - self.countLabel.setText(self.tr("%n Download(s)", "", count)) - - def __updateActiveItemCount(self): - """ - Private method to update the window title. - """ - count = self.activeDownloads() - 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) - - def setDownloadDirectory(self, directory): - """ - Public method to set the current download directory. - - @param directory current download directory (string) - """ - self.__downloadDirectory = directory - if self.__downloadDirectory != "": - self.__downloadDirectory += "/" - - def downloadDirectory(self): - """ - Public method to get the current download directory. - - @return current download directory (string) - """ - return self.__downloadDirectory - - def count(self): - """ - Public method to get the number of downloads. - - @return number of downloads (integer) - """ - return len(self.__downloads) - - def downloads(self): - """ - Public method to get a reference to the downloads. - - @return reference to the downloads (list of DownloadItem) - """ - return self.__downloads - - def changeOccurred(self): - """ - Public method to signal a change. - """ - self.__saveTimer.changeOccurred() - self.__updateItemCount() - - ########################################################################### - ## Context menu related methods below - ########################################################################### - - def __currentItem(self): - """ - Private method to get a reference to the current item. - - @return reference to the current item (DownloadItem) - """ - index = self.downloadsView.currentIndex() - if index and index.isValid(): - row = index.row() - return self.__downloads[row] - - return None - - def __contextMenuRetry(self): - """ - Private method to retry of the download. - """ - itm = self.__currentItem() - if itm is not None: - itm.retry() - - def __contextMenuOpen(self): - """ - Private method to open the downloaded file. - """ - itm = self.__currentItem() - if itm is not None: - itm.openFile() - - def __contextMenuOpenFolder(self): - """ - Private method to open the folder containing the downloaded file. - """ - itm = self.__currentItem() - if itm is not None: - itm.openFolder() - - def __contextMenuCancel(self): - """ - Private method to cancel the current download. - """ - itm = self.__currentItem() - if itm is not None: - itm.cancelDownload() - - def __contextMenuGotoPage(self): - """ - Private method to open the download page. - """ - itm = self.__currentItem() - if itm is not None: - url = itm.getPageUrl() - Helpviewer.HelpWindow.HelpWindow.mainWindow().openUrl(url, "") - - def __contextMenuCopyLink(self): - """ - Private method to copy the download link to the clipboard. - """ - itm = self.__currentItem() - if itm is not None: - url = itm.getPageUrl().toString() - QApplication.clipboard().setText(url) - - def __contextMenuSelectAll(self): - """ - Private method to select all downloads. - """ - self.downloadsView.selectAll() - - def __contextMenuRemoveSelected(self): - """ - Private method to remove the selected downloads from the list. - """ - self.downloadsView.removeSelected()