5 |
5 |
6 """ |
6 """ |
7 Module implementing a widget controlling a download. |
7 Module implementing a widget controlling a download. |
8 """ |
8 """ |
9 |
9 |
10 from PyQt4.QtCore import pyqtSlot, pyqtSignal, Qt, QTime, QFile, QFileInfo, QUrl, \ |
10 from PyQt4.QtCore import pyqtSlot, pyqtSignal, Qt, QTime, QFile, QFileInfo, \ |
11 QIODevice, QCryptographicHash |
11 QUrl, QIODevice, QCryptographicHash |
12 from PyQt4.QtGui import QWidget, QPalette, QStyle, QDesktopServices, QDialog |
12 from PyQt4.QtGui import QWidget, QPalette, QStyle, QDesktopServices, QDialog |
13 from PyQt4.QtNetwork import QNetworkRequest, QNetworkReply |
13 from PyQt4.QtNetwork import QNetworkRequest, QNetworkReply |
14 |
14 |
15 from E5Gui import E5FileDialog |
15 from E5Gui import E5FileDialog |
16 |
16 |
42 download=False, parent=None, mainWindow=None): |
42 download=False, parent=None, mainWindow=None): |
43 """ |
43 """ |
44 Constructor |
44 Constructor |
45 |
45 |
46 @keyparam reply reference to the network reply object (QNetworkReply) |
46 @keyparam reply reference to the network reply object (QNetworkReply) |
47 @keyparam requestFilename flag indicating to ask the user for a filename (boolean) |
47 @keyparam requestFilename flag indicating to ask the user for a |
48 @keyparam webPage reference to the web page object the download originated |
48 filename (boolean) |
49 from (QWebPage) |
49 @keyparam webPage reference to the web page object the download |
|
50 originated from (QWebPage) |
50 @keyparam download flag indicating a download operation (boolean) |
51 @keyparam download flag indicating a download operation (boolean) |
51 @keyparam parent reference to the parent widget (QWidget) |
52 @keyparam parent reference to the parent widget (QWidget) |
52 @keyparam mainWindow reference to the main window (HelpWindow) |
53 @keyparam mainWindow reference to the main window (HelpWindow) |
53 """ |
54 """ |
54 super().__init__(parent) |
55 super().__init__(parent) |
58 p.setColor(QPalette.Text, Qt.darkGray) |
59 p.setColor(QPalette.Text, Qt.darkGray) |
59 self.infoLabel.setPalette(p) |
60 self.infoLabel.setPalette(p) |
60 |
61 |
61 self.progressBar.setMaximum(0) |
62 self.progressBar.setMaximum(0) |
62 |
63 |
63 self.__isFtpDownload = reply is not None and reply.url().scheme() == "ftp" |
64 self.__isFtpDownload = reply is not None and \ |
|
65 reply.url().scheme() == "ftp" |
64 |
66 |
65 self.tryAgainButton.setIcon(UI.PixmapCache.getIcon("restart.png")) |
67 self.tryAgainButton.setIcon(UI.PixmapCache.getIcon("restart.png")) |
66 self.tryAgainButton.setEnabled(False) |
68 self.tryAgainButton.setEnabled(False) |
67 self.tryAgainButton.setVisible(False) |
69 self.tryAgainButton.setVisible(False) |
68 self.stopButton.setIcon(UI.PixmapCache.getIcon("stopLoading.png")) |
70 self.stopButton.setIcon(UI.PixmapCache.getIcon("stopLoading.png")) |
101 |
103 |
102 self.__sha1Hash = QCryptographicHash(QCryptographicHash.Sha1) |
104 self.__sha1Hash = QCryptographicHash(QCryptographicHash.Sha1) |
103 self.__md5Hash = QCryptographicHash(QCryptographicHash.Md5) |
105 self.__md5Hash = QCryptographicHash(QCryptographicHash.Md5) |
104 |
106 |
105 if not requestFilename: |
107 if not requestFilename: |
106 self.__requestFilename = Preferences.getUI("RequestDownloadFilename") |
108 self.__requestFilename = \ |
|
109 Preferences.getUI("RequestDownloadFilename") |
107 |
110 |
108 self.__initialize() |
111 self.__initialize() |
109 |
112 |
110 def __initialize(self, tryAgain=False): |
113 def __initialize(self, tryAgain=False): |
111 """ |
114 """ |
161 fileName = self.__fileName |
164 fileName = self.__fileName |
162 originalFileName = self.__originalFileName |
165 originalFileName = self.__originalFileName |
163 self.__toDownload = True |
166 self.__toDownload = True |
164 ask = False |
167 ask = False |
165 else: |
168 else: |
166 defaultFileName, originalFileName = self.__saveFileName(downloadDirectory) |
169 defaultFileName, originalFileName = \ |
|
170 self.__saveFileName(downloadDirectory) |
167 fileName = defaultFileName |
171 fileName = defaultFileName |
168 self.__originalFileName = originalFileName |
172 self.__originalFileName = originalFileName |
169 ask = True |
173 ask = True |
170 self.__autoOpen = False |
174 self.__autoOpen = False |
171 if not self.__toDownload: |
175 if not self.__toDownload: |
178 self) |
182 self) |
179 if dlg.exec_() == QDialog.Rejected or dlg.getAction() == "cancel": |
183 if dlg.exec_() == QDialog.Rejected or dlg.getAction() == "cancel": |
180 self.progressBar.setVisible(False) |
184 self.progressBar.setVisible(False) |
181 self.__reply.close() |
185 self.__reply.close() |
182 self.on_stopButton_clicked() |
186 self.on_stopButton_clicked() |
183 self.filenameLabel.setText(self.trUtf8("Download canceled: {0}").format( |
187 self.filenameLabel.setText( |
184 QFileInfo(defaultFileName).fileName())) |
188 self.trUtf8("Download canceled: {0}").format( |
|
189 QFileInfo(defaultFileName).fileName())) |
185 self.__canceledFileSelect = True |
190 self.__canceledFileSelect = True |
186 return |
191 return |
187 |
192 |
188 if dlg.getAction() == "scan": |
193 if dlg.getAction() == "scan": |
189 self.__mainWindow.requestVirusTotalScan(url) |
194 self.__mainWindow.requestVirusTotalScan(url) |
196 QFileInfo(defaultFileName).fileName())) |
201 QFileInfo(defaultFileName).fileName())) |
197 self.__canceledFileSelect = True |
202 self.__canceledFileSelect = True |
198 return |
203 return |
199 |
204 |
200 self.__autoOpen = dlg.getAction() == "open" |
205 self.__autoOpen = dlg.getAction() == "open" |
201 fileName = QDesktopServices.storageLocation(QDesktopServices.TempLocation) + \ |
206 fileName = QDesktopServices.storageLocation( |
202 '/' + QFileInfo(fileName).completeBaseName() |
207 QDesktopServices.TempLocation) + \ |
|
208 '/' + QFileInfo(fileName).completeBaseName() |
203 |
209 |
204 if ask and not self.__autoOpen and self.__requestFilename: |
210 if ask and not self.__autoOpen and self.__requestFilename: |
205 self.__gettingFileName = True |
211 self.__gettingFileName = True |
206 fileName = E5FileDialog.getSaveFileName( |
212 fileName = E5FileDialog.getSaveFileName( |
207 None, |
213 None, |
211 self.__gettingFileName = False |
217 self.__gettingFileName = False |
212 if not fileName: |
218 if not fileName: |
213 self.progressBar.setVisible(False) |
219 self.progressBar.setVisible(False) |
214 self.__reply.close() |
220 self.__reply.close() |
215 self.on_stopButton_clicked() |
221 self.on_stopButton_clicked() |
216 self.filenameLabel.setText(self.trUtf8("Download canceled: {0}")\ |
222 self.filenameLabel.setText( |
217 .format(QFileInfo(defaultFileName).fileName())) |
223 self.trUtf8("Download canceled: {0}")\ |
|
224 .format(QFileInfo(defaultFileName).fileName())) |
218 self.__canceledFileSelect = True |
225 self.__canceledFileSelect = True |
219 return |
226 return |
220 |
227 |
221 fileInfo = QFileInfo(fileName) |
228 fileInfo = QFileInfo(fileName) |
222 Helpviewer.HelpWindow.HelpWindow.downloadManager().setDownloadDirectory( |
229 Helpviewer.HelpWindow.HelpWindow.downloadManager()\ |
223 fileInfo.absoluteDir().absolutePath()) |
230 .setDownloadDirectory(fileInfo.absoluteDir().absolutePath()) |
224 self.filenameLabel.setText(fileInfo.fileName()) |
231 self.filenameLabel.setText(fileInfo.fileName()) |
225 |
232 |
226 self.__output.setFileName(fileName + ".part") |
233 self.__output.setFileName(fileName + ".part") |
227 self.__fileName = fileName |
234 self.__fileName = fileName |
228 |
235 |
230 saveDirPath = QFileInfo(self.__fileName).dir() |
237 saveDirPath = QFileInfo(self.__fileName).dir() |
231 if not saveDirPath.exists(): |
238 if not saveDirPath.exists(): |
232 if not saveDirPath.mkpath(saveDirPath.absolutePath()): |
239 if not saveDirPath.mkpath(saveDirPath.absolutePath()): |
233 self.progressBar.setVisible(False) |
240 self.progressBar.setVisible(False) |
234 self.on_stopButton_clicked() |
241 self.on_stopButton_clicked() |
235 self.infoLabel.setText( |
242 self.infoLabel.setText(self.trUtf8( |
236 self.trUtf8("Download directory ({0}) couldn't be created.")\ |
243 "Download directory ({0}) couldn't be created.")\ |
237 .format(saveDirPath.absolutePath())) |
244 .format(saveDirPath.absolutePath())) |
238 return |
245 return |
239 |
246 |
240 self.filenameLabel.setText(QFileInfo(self.__fileName).fileName()) |
247 self.filenameLabel.setText(QFileInfo(self.__fileName).fileName()) |
241 if self.__requestFilename: |
248 if self.__requestFilename: |
248 @param directory name of the directory to store the file into (string) |
255 @param directory name of the directory to store the file into (string) |
249 @return proposed filename and original filename (string, string) |
256 @return proposed filename and original filename (string, string) |
250 """ |
257 """ |
251 path = "" |
258 path = "" |
252 if self.__reply.hasRawHeader("Content-Disposition"): |
259 if self.__reply.hasRawHeader("Content-Disposition"): |
253 header = bytes(self.__reply.rawHeader("Content-Disposition")).decode() |
260 header = bytes(self.__reply.rawHeader("Content-Disposition"))\ |
|
261 .decode() |
254 if header: |
262 if header: |
255 pos = header.find("filename=") |
263 pos = header.find("filename=") |
256 if pos != -1: |
264 if pos != -1: |
257 path = header[pos + 9:] |
265 path = header[pos + 9:] |
258 if path.startswith('"') and path.endswith('"'): |
266 if path.startswith('"') and path.endswith('"'): |
405 if not self.__output.isOpen(): |
413 if not self.__output.isOpen(): |
406 # in case someone else has already put a file there |
414 # in case someone else has already put a file there |
407 if not self.__requestFilename: |
415 if not self.__requestFilename: |
408 self.__getFileName() |
416 self.__getFileName() |
409 if not self.__output.open(QIODevice.WriteOnly): |
417 if not self.__output.open(QIODevice.WriteOnly): |
410 self.infoLabel.setText(self.trUtf8("Error opening save file: {0}")\ |
418 self.infoLabel.setText( |
|
419 self.trUtf8("Error opening save file: {0}")\ |
411 .format(self.__output.errorString())) |
420 .format(self.__output.errorString())) |
412 self.on_stopButton_clicked() |
421 self.on_stopButton_clicked() |
413 self.statusChanged.emit() |
422 self.statusChanged.emit() |
414 return |
423 return |
415 self.statusChanged.emit() |
424 self.statusChanged.emit() |
443 """ |
452 """ |
444 locationHeader = self.__reply.header(QNetworkRequest.LocationHeader) |
453 locationHeader = self.__reply.header(QNetworkRequest.LocationHeader) |
445 if locationHeader and locationHeader.isValid(): |
454 if locationHeader and locationHeader.isValid(): |
446 self.__url = QUrl(locationHeader) |
455 self.__url = QUrl(locationHeader) |
447 import Helpviewer.HelpWindow |
456 import Helpviewer.HelpWindow |
448 self.__reply = Helpviewer.HelpWindow.HelpWindow.networkAccessManager().get( |
457 self.__reply = Helpviewer.HelpWindow.HelpWindow\ |
449 QNetworkRequest(self.__url)) |
458 .networkAccessManager().get(QNetworkRequest(self.__url)) |
450 self.__initialize() |
459 self.__initialize() |
451 |
460 |
452 def __downloadProgress(self, bytesReceived, bytesTotal): |
461 def __downloadProgress(self, bytesReceived, bytesTotal): |
453 """ |
462 """ |
454 Private method to show the download progress. |
463 Private method to show the download progress. |
474 Public method to get the total number of bytes of the download. |
483 Public method to get the total number of bytes of the download. |
475 |
484 |
476 @return total number of bytes (integer) |
485 @return total number of bytes (integer) |
477 """ |
486 """ |
478 if self.__bytesTotal == -1: |
487 if self.__bytesTotal == -1: |
479 self.__bytesTotal = self.__reply.header(QNetworkRequest.ContentLengthHeader) |
488 self.__bytesTotal = self.__reply.header( |
|
489 QNetworkRequest.ContentLengthHeader) |
480 if self.__bytesTotal is None: |
490 if self.__bytesTotal is None: |
481 self.__bytesTotal = -1 |
491 self.__bytesTotal = -1 |
482 return self.__bytesTotal |
492 return self.__bytesTotal |
483 |
493 |
484 def bytesReceived(self): |
494 def bytesReceived(self): |
549 remaining) |
560 remaining) |
550 else: |
561 else: |
551 if self.__bytesReceived == bytesTotal or bytesTotal == -1: |
562 if self.__bytesReceived == bytesTotal or bytesTotal == -1: |
552 info = self.trUtf8("{0} downloaded\nSHA1: {1}\nMD5: {2}")\ |
563 info = self.trUtf8("{0} downloaded\nSHA1: {1}\nMD5: {2}")\ |
553 .format(dataString(self.__output.size()), |
564 .format(dataString(self.__output.size()), |
554 str(self.__sha1Hash.result().toHex(), encoding="ascii"), |
565 str(self.__sha1Hash.result().toHex(), |
555 str(self.__md5Hash.result().toHex(), encoding="ascii")) |
566 encoding="ascii"), |
|
567 str(self.__md5Hash.result().toHex(), |
|
568 encoding="ascii") |
|
569 ) |
556 else: |
570 else: |
557 info = self.trUtf8("{0} of {1} - Stopped")\ |
571 info = self.trUtf8("{0} of {1} - Stopped")\ |
558 .format(dataString(self.__bytesReceived), |
572 .format(dataString(self.__bytesReceived), |
559 dataString(bytesTotal)) |
573 dataString(bytesTotal)) |
560 self.infoLabel.setText(info) |
574 self.infoLabel.setText(info) |