WebBrowser/Download/DownloadManager.py

changeset 6221
35ec993034e1
parent 6153
0b18c86c03a1
child 6222
baffb22b4467
equal deleted inserted replaced
6220:dd4a8b507144 6221:35ec993034e1
7 Module implementing the download manager class. 7 Module implementing the download manager class.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QModelIndex, QFileInfo, QUrl 12 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QModelIndex, QFileInfo, \
13 QUrl, QBasicTimer
13 from PyQt5.QtGui import QCursor, QKeySequence 14 from PyQt5.QtGui import QCursor, QKeySequence
14 from PyQt5.QtWidgets import QDialog, QStyle, QFileIconProvider, QMenu, \ 15 from PyQt5.QtWidgets import QDialog, QStyle, QFileIconProvider, QMenu, \
15 QApplication, QShortcut 16 QApplication, QShortcut
16 17
17 from E5Gui import E5MessageBox 18 from E5Gui import E5MessageBox
18 19
19 from .Ui_DownloadManager import Ui_DownloadManager 20 from .Ui_DownloadManager import Ui_DownloadManager
20 21
21 from .DownloadModel import DownloadModel 22 from .DownloadModel import DownloadModel
23 from .DownloadUtilities import speedString, timeString
22 24
23 from WebBrowser.WebBrowserWindow import WebBrowserWindow 25 from WebBrowser.WebBrowserWindow import WebBrowserWindow
24 26
25 from Utilities.AutoSaver import AutoSaver 27 from Utilities.AutoSaver import AutoSaver
26 import UI.PixmapCache 28 import UI.PixmapCache
27 import Preferences 29 import Preferences
30 import Globals
28 31
29 32
30 class DownloadManager(QDialog, Ui_DownloadManager): 33 class DownloadManager(QDialog, Ui_DownloadManager):
31 """ 34 """
32 Class implementing the download manager. 35 Class implementing the download manager.
36 """ 39 """
37 RemoveNever = 0 40 RemoveNever = 0
38 RemoveExit = 1 41 RemoveExit = 1
39 RemoveSuccessFullDownload = 2 42 RemoveSuccessFullDownload = 2
40 43
44 UpdateTimerTimeout = 1000
45
41 downloadsCountChanged = pyqtSignal() 46 downloadsCountChanged = pyqtSignal()
42 47
43 def __init__(self, parent=None): 48 def __init__(self, parent=None):
44 """ 49 """
45 Constructor 50 Constructor
47 @param parent reference to the parent widget (QWidget) 52 @param parent reference to the parent widget (QWidget)
48 """ 53 """
49 super(DownloadManager, self).__init__(parent) 54 super(DownloadManager, self).__init__(parent)
50 self.setupUi(self) 55 self.setupUi(self)
51 self.setWindowFlags(Qt.Window) 56 self.setWindowFlags(Qt.Window)
57
58 self.__winTaskbarButton = None
52 59
53 self.__saveTimer = AutoSaver(self, self.save) 60 self.__saveTimer = AutoSaver(self, self.save)
54 61
55 self.__model = DownloadModel(self) 62 self.__model = DownloadModel(self)
56 self.__manager = WebBrowserWindow.networkManager() 63 self.__manager = WebBrowserWindow.networkManager()
76 83
77 self.__clearShortcut = QShortcut(QKeySequence("Ctrl+L"), self) 84 self.__clearShortcut = QShortcut(QKeySequence("Ctrl+L"), self)
78 self.__clearShortcut.activated.connect(self.on_cleanupButton_clicked) 85 self.__clearShortcut.activated.connect(self.on_cleanupButton_clicked)
79 86
80 self.__load() 87 self.__load()
88
89 self.__updateTimer = QBasicTimer()
81 90
82 def __customContextMenuRequested(self, pos): 91 def __customContextMenuRequested(self, pos):
83 """ 92 """
84 Private slot to handle the context menu request for the bookmarks tree. 93 Private slot to handle the context menu request for the bookmarks tree.
85 94
163 if not res: 172 if not res:
164 self.show() 173 self.show()
165 return False 174 return False
166 return True 175 return True
167 176
177 def __testWebBrowserView(self, view, url):
178 """
179 Private method to test a web browser view against an URL.
180
181 @param view reference to the web browser view to be tested
182 @type WebBrowserView
183 @param url URL to test against
184 @type QUrl
185 @return flag indicating, that the view is the one for the URL
186 @rtype bool
187 """
188 if view.tabWidget().count() < 2:
189 return False
190
191 page = view.page()
192 if page.history().count() != 0:
193 return False
194
195 if not page.url().isEmpty() and \
196 page.url().host() == url.host():
197 return True
198
199 requestedUrl = page.requestedUrl()
200 if requestedUrl.isEmpty():
201 requestedUrl = QUrl(view.tabWidget().urlBarForView(view).text())
202 return requestedUrl.isEmpty() or requestedUrl.host() == url.host()
203
204 def __closeDownloadTab(self, url):
205 """
206 Private method to close an empty tab, that was opened only for loading
207 the download URL.
208
209 @param url download URL
210 @type QUrl
211 """
212 if self.__testWebBrowserView(
213 WebBrowserWindow.getWindow().currentBrowser(), url):
214 WebBrowserWindow.getWindow().closeCurrentBrowser()
215 return
216
217 for window in WebBrowserWindow.mainWindows():
218 for browser in window.browsers():
219 if self.__testWebBrowserView(browser, url):
220 window.closeBrowser(browser)
221 return
222
168 def download(self, downloadItem): 223 def download(self, downloadItem):
169 """ 224 """
170 Public method to download a file. 225 Public method to download a file.
171 226
172 @param downloadItem reference to the download object containing the 227 @param downloadItem reference to the download object containing the
174 @type QWebEngineDownloadItem 229 @type QWebEngineDownloadItem
175 """ 230 """
176 url = downloadItem.url() 231 url = downloadItem.url()
177 if url.isEmpty(): 232 if url.isEmpty():
178 return 233 return
234
235 self.__closeDownloadTab(url)
179 236
180 # Safe Browsing 237 # Safe Browsing
181 from WebBrowser.SafeBrowsing.SafeBrowsingManager import \ 238 from WebBrowser.SafeBrowsing.SafeBrowsingManager import \
182 SafeBrowsingManager 239 SafeBrowsingManager
183 if SafeBrowsingManager.isEnabled(): 240 if SafeBrowsingManager.isEnabled():
204 from .DownloadItem import DownloadItem 261 from .DownloadItem import DownloadItem
205 itm = DownloadItem(downloadItem=downloadItem, pageUrl=pageUrl, 262 itm = DownloadItem(downloadItem=downloadItem, pageUrl=pageUrl,
206 parent=self) 263 parent=self)
207 self.__addItem(itm) 264 self.__addItem(itm)
208 265
209 if itm.canceledFileSelect(): 266 self.__startUpdateTimer()
210 return 267
211 268 def show(self):
212 if not self.isVisible(): 269 """
213 self.show() 270 Public slot to show the download manager dialog.
214 271 """
272 self.__startUpdateTimer()
273
274 super(DownloadManager, self).show()
215 self.activateWindow() 275 self.activateWindow()
216 self.raise_() 276 self.raise_()
217 277
218 def __addItem(self, itm, append=False): 278 def __addItem(self, itm, append=False):
219 """ 279 """
245 self.downloadsView.setRowHeight( 305 self.downloadsView.setRowHeight(
246 row, itm.sizeHint().height() * self.__rowHeightMultiplier) 306 row, itm.sizeHint().height() * self.__rowHeightMultiplier)
247 # just in case the download finished before the constructor returned 307 # just in case the download finished before the constructor returned
248 self.__updateRow(itm) 308 self.__updateRow(itm)
249 self.changeOccurred() 309 self.changeOccurred()
250 self.__updateActiveItemCount()
251 310
252 self.downloadsCountChanged.emit() 311 self.downloadsCountChanged.emit()
253 312
254 def __updateRow(self, itm): 313 def __updateRow(self, itm):
255 """ 314 """
361 self.__addItem(itm, append=True) 420 self.__addItem(itm, append=True)
362 self.cleanupButton.setEnabled( 421 self.cleanupButton.setEnabled(
363 (self.downloadsCount() - self.activeDownloadsCount()) > 0) 422 (self.downloadsCount() - self.activeDownloadsCount()) > 0)
364 423
365 self.__loaded = True 424 self.__loaded = True
366 self.__updateActiveItemCount()
367 425
368 self.downloadsCountChanged.emit() 426 self.downloadsCountChanged.emit()
369 427
370 def closeEvent(self, evt): 428 def closeEvent(self, evt):
371 """ 429 """
383 self.on_cleanupButton_clicked() 441 self.on_cleanupButton_clicked()
384 442
385 @pyqtSlot() 443 @pyqtSlot()
386 def on_cleanupButton_clicked(self): 444 def on_cleanupButton_clicked(self):
387 """ 445 """
388 Private slot cleanup the downloads. 446 Private slot to cleanup the downloads.
389 """ 447 """
390 if self.downloadsCount() == 0: 448 if self.downloadsCount() == 0:
391 return 449 return
392 450
393 self.__model.removeRows(0, self.downloadsCount()) 451 self.__model.removeRows(0, self.downloadsCount())
394 if self.downloadsCount() == 0 and \ 452 if self.downloadsCount() == 0 and \
395 self.__iconProvider is not None: 453 self.__iconProvider is not None:
396 self.__iconProvider = None 454 self.__iconProvider = None
397 455
398 self.changeOccurred() 456 self.changeOccurred()
399 self.__updateActiveItemCount()
400 457
401 self.downloadsCountChanged.emit() 458 self.downloadsCountChanged.emit()
402 459
403 def __updateItemCount(self):
404 """
405 Private method to update the count label.
406 """
407 count = self.downloadsCount()
408 self.countLabel.setText(self.tr("%n Download(s)", "", count))
409
410 def __updateActiveItemCount(self):
411 """
412 Private method to update the window title.
413 """
414 count = self.activeDownloadsCount()
415 if count > 0:
416 self.setWindowTitle(
417 self.tr("Downloading %n file(s)", "", count))
418 else:
419 self.setWindowTitle(self.tr("Downloads"))
420
421 def __finished(self): 460 def __finished(self):
422 """ 461 """
423 Private slot to handle a finished download. 462 Private slot to handle a finished download.
424 """ 463 """
425 self.__updateActiveItemCount()
426 if self.isVisible(): 464 if self.isVisible():
427 QApplication.alert(self) 465 QApplication.alert(self)
428 466
429 self.downloadsCountChanged.emit() 467 self.downloadsCountChanged.emit()
430 468
466 def changeOccurred(self): 504 def changeOccurred(self):
467 """ 505 """
468 Public method to signal a change. 506 Public method to signal a change.
469 """ 507 """
470 self.__saveTimer.changeOccurred() 508 self.__saveTimer.changeOccurred()
471 self.__updateItemCount() 509
510 def __taskbarButton(self):
511 """
512 Private method to get a reference to the task bar button (Windows
513 only).
514
515 @return reference to the task bar button
516 @rtype QWinTaskbarButton or None
517 """
518 if Globals.isWindowsPlatform():
519 from PyQt5.QtWinExtras import QWinTaskbarButton
520 if self.__winTaskbarButton is None:
521 window = WebBrowserWindow.mainWindow()
522 self.__winTaskbarButton = QWinTaskbarButton(
523 window.windowHandle())
524 self.__winTaskbarButton.progress().setRange(0, 100)
525
526 return self.__winTaskbarButton
527
528 def timerEvent(self, evt):
529 """
530 Protected event handler for timer events.
531
532 @param evt reference to the timer event
533 @type QTimerEvent
534 """
535 if evt.timerId() == self.__updateTimer.timerId():
536 if self.activeDownloadsCount() == 0:
537 self.__stopUpdateTimer()
538 self.infoLabel.clear()
539 self.setWindowTitle(self.tr("Download Manager"))
540 if Globals.isWindowsPlatform():
541 self.__taskbarButton.progress().hide()
542 else:
543 progresses = []
544 for itm in self.__downloads:
545 if itm is None or \
546 itm.downloadCanceled() or \
547 not itm.downloading():
548 continue
549
550 progresses.append((
551 itm.downloadProgress(),
552 itm.remainingTime(),
553 itm.currentSpeed()
554 ))
555
556 if not progresses:
557 return
558
559 remaining = 0
560 progress = 0
561 speed = 0.0
562
563 for progressData in progresses:
564 if progressData[1] > remaining:
565 remaining = progressData[1]
566 progress += progressData[0]
567 speed += progressData[2]
568 progress = progress / len(progresses)
569
570 if self.isVisible():
571 self.infoLabel.setText(self.tr(
572 "{0}% of %n file(s) ({1}) {2}", "",
573 len(progresses)).format(
574 progress,
575 speedString(speed),
576 timeString(remaining),
577 ))
578 self.setWindowTitle(self.tr("{0}% - Download Manager"))
579
580 if Globals.isWindowsPlatform():
581 self.taskbarButton().progress().show()
582 self.taskbarButton().progress().setValue(progress)
583
584 super(DownloadManager, self).timerEvent(evt)
585
586 def __startUpdateTimer(self):
587 """
588 Private slot to start the update timer.
589 """
590 if self.activeDownloadsCount() and not self.__updateTimer.isActive():
591 self.__updateTimer.start(DownloadManager.UpdateTimerTimeout, self)
592
593 def __stopUpdateTimer(self):
594 """
595 Private slot to stop the update timer.
596 """
597 self.__updateTimer.stop()
472 598
473 ########################################################################### 599 ###########################################################################
474 ## Context menu related methods below 600 ## Context menu related methods below
475 ########################################################################### 601 ###########################################################################
476 602

eric ide

mercurial