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. |
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() |
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 |
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 """ |
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 |