|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 """ |
|
4 Module implementing the download manager class. |
|
5 """ |
|
6 |
|
7 from PyQt4.QtCore import pyqtSlot, QModelIndex, QFileInfo |
|
8 from PyQt4.QtGui import QDialog, QStyle, QFileIconProvider |
|
9 from PyQt4.QtNetwork import QNetworkRequest |
|
10 from PyQt4.QtWebKit import QWebSettings |
|
11 |
|
12 from E5Gui import E5MessageBox |
|
13 |
|
14 from .Ui_DownloadManager import Ui_DownloadManager |
|
15 |
|
16 from .DownloadItem import DownloadItem |
|
17 from .DownloadModel import DownloadModel |
|
18 |
|
19 import Helpviewer.HelpWindow |
|
20 |
|
21 from Utilities.AutoSaver import AutoSaver |
|
22 import Preferences |
|
23 |
|
24 class DownloadManager(QDialog, Ui_DownloadManager): |
|
25 """ |
|
26 Class implementing the download manager |
|
27 """ |
|
28 RemoveNever = 0 |
|
29 RemoveExit = 1 |
|
30 RemoveSuccessFullDownload = 2 |
|
31 |
|
32 def __init__(self, parent = None): |
|
33 """ |
|
34 Constructor |
|
35 |
|
36 @param parent reference to the parent widget (QWidget) |
|
37 """ |
|
38 QDialog.__init__(self, parent) |
|
39 self.setupUi(self) |
|
40 |
|
41 self.__saveTimer = AutoSaver(self, self.save) |
|
42 |
|
43 self.__model = DownloadModel(self) |
|
44 self.__manager = Helpviewer.HelpWindow.HelpWindow.networkAccessManager() |
|
45 |
|
46 self.__iconProvider = None |
|
47 self.__removePolicy = DownloadManager.RemoveNever |
|
48 self.__downloads = [] |
|
49 self.__downloadDirectory = "" |
|
50 self.__loaded = False |
|
51 |
|
52 self.setDownloadDirectory(Preferences.getUI("DownloadPath")) |
|
53 |
|
54 self.downloadsView.setShowGrid(False) |
|
55 self.downloadsView.verticalHeader().hide() |
|
56 self.downloadsView.horizontalHeader().hide() |
|
57 self.downloadsView.setAlternatingRowColors(True) |
|
58 self.downloadsView.horizontalHeader().setStretchLastSection(True) |
|
59 self.downloadsView.setModel(self.__model) |
|
60 |
|
61 self.__load() |
|
62 |
|
63 def shutdown(self): |
|
64 """ |
|
65 Public method to stop the download manager. |
|
66 """ |
|
67 self.__saveTimer.changeOccurred() |
|
68 self.__saveTimer.saveIfNeccessary() |
|
69 self.close() |
|
70 |
|
71 def activeDownloads(self): |
|
72 """ |
|
73 Public method to get the number of active downloads. |
|
74 |
|
75 @return number of active downloads (integer) |
|
76 """ |
|
77 count = 0 |
|
78 |
|
79 for download in self.__downloads: |
|
80 if download.downloading(): |
|
81 count += 1 |
|
82 return count |
|
83 |
|
84 def allowQuit(self): |
|
85 """ |
|
86 Public method to check, if it is ok to quit. |
|
87 |
|
88 @return flag indicating allowance to quit (boolean) |
|
89 """ |
|
90 if self.activeDownloads() > 0: |
|
91 res = E5MessageBox.yesNo(self, |
|
92 self.trUtf8(""), |
|
93 self.trUtf8("""There are %n downloads in progress.\n""" |
|
94 """Do you want to quit anyway?""", "", |
|
95 self.activeDownloads()), |
|
96 icon = E5MessageBox.Warning) |
|
97 if not res: |
|
98 self.show() |
|
99 return False |
|
100 return True |
|
101 |
|
102 def download(self, requestOrUrl, requestFileName = False): |
|
103 """ |
|
104 Public method to download a file. |
|
105 |
|
106 @param requestOrUrl reference to a request object (QNetworkRequest) |
|
107 or a URL to be downloaded (QUrl) |
|
108 @keyparam requestFileName flag indicating to ask for the |
|
109 download file name (boolean) |
|
110 """ |
|
111 request = QNetworkRequest(requestOrUrl) |
|
112 if request.url().isEmpty(): |
|
113 return |
|
114 self.handleUnsupportedContent(self.__manager.get(request), |
|
115 requestFileName = requestFileName, |
|
116 download = True) |
|
117 |
|
118 def handleUnsupportedContent(self, reply, requestFileName = False, |
|
119 webPage = None, download = False): |
|
120 if reply is None or reply.url().isEmpty(): |
|
121 return |
|
122 |
|
123 size = reply.header(QNetworkRequest.ContentLengthHeader) |
|
124 if size == 0: |
|
125 return |
|
126 |
|
127 itm = DownloadItem(reply = reply, requestFilename = requestFileName, |
|
128 webPage = webPage, download = download, parent = self) |
|
129 self.__addItem(itm) |
|
130 |
|
131 if itm.canceledFileSelect(): |
|
132 return |
|
133 |
|
134 if not self.isVisible(): |
|
135 self.show() |
|
136 |
|
137 self.activateWindow() |
|
138 self.raise_() |
|
139 |
|
140 def __addItem(self, itm): |
|
141 """ |
|
142 Private method to add a download to the list of downloads. |
|
143 |
|
144 @param itm reference to the download item (DownloadItem) |
|
145 """ |
|
146 itm.statusChanged.connect(self.__updateRow) |
|
147 |
|
148 row = len(self.__downloads) |
|
149 self.__model.beginInsertRows(QModelIndex(), row, row) |
|
150 self.__downloads.append(itm) |
|
151 self.__model.endInsertRows() |
|
152 self.__updateItemCount() |
|
153 |
|
154 self.downloadsView.setIndexWidget(self.__model.index(row, 0), itm) |
|
155 icon = self.style().standardIcon(QStyle.SP_FileIcon) |
|
156 itm.setIcon(icon) |
|
157 self.downloadsView.setRowHeight(row, itm.sizeHint().height()) |
|
158 # just in case the download finished before the constructor returned |
|
159 self.__updateRow(itm) |
|
160 |
|
161 def __updateRow(self, itm = None): |
|
162 """ |
|
163 Private slot to update a download item. |
|
164 |
|
165 @param itm reference to the download item (DownloadItem) |
|
166 """ |
|
167 if itm is None: |
|
168 itm = self.sender() |
|
169 |
|
170 if itm not in self.__downloads: |
|
171 return |
|
172 |
|
173 row = self.__downloads.index(itm) |
|
174 |
|
175 if self.__iconProvider is None: |
|
176 self.__iconProvider = QFileIconProvider() |
|
177 |
|
178 icon = self.__iconProvider.icon(QFileInfo(itm.fileName())) |
|
179 if icon.isNull(): |
|
180 icon = self.style().standardIcon(QStyle.SP_FileIcon) |
|
181 itm.setIcon(icon) |
|
182 |
|
183 oldHeight = self.downloadsView.rowHeight(row) |
|
184 self.downloadsView.setRowHeight(row, |
|
185 max(oldHeight, itm.minimumSizeHint().height())) |
|
186 |
|
187 remove = False |
|
188 globalSettings = QWebSettings.globalSettings() |
|
189 if not itm.downloading() and \ |
|
190 globalSettings.testAttribute(QWebSettings.PrivateBrowsingEnabled): |
|
191 remove = True |
|
192 |
|
193 if itm.downloadedSuccessfully() and \ |
|
194 self.removePolicy() == DownloadManager.RemoveSuccessFullDownload: |
|
195 remove = True |
|
196 |
|
197 if remove: |
|
198 self.__model.removeRow(row) |
|
199 |
|
200 self.cleanupButton.setEnabled( |
|
201 (len(self.__downloads) - self.activeDownloads()) > 0) |
|
202 |
|
203 def removePolicy(self): |
|
204 """ |
|
205 Public method to get the remove policy. |
|
206 |
|
207 @return remove policy (integer) |
|
208 """ |
|
209 return self.__removePolicy |
|
210 |
|
211 def setRemovePolicy(self, policy): |
|
212 """ |
|
213 Public method to set the remove policy. |
|
214 |
|
215 @param policy policy to be set |
|
216 (DownloadManager.RemoveExit, DownloadManager.RemoveNever, |
|
217 DownloadManager.RemoveSuccessFullDownload) |
|
218 """ |
|
219 assert policy in (DownloadManager.RemoveExit, DownloadManager.RemoveNever, |
|
220 DownloadManager.RemoveSuccessFullDownload) |
|
221 |
|
222 if policy == self.__removePolicy: |
|
223 return |
|
224 |
|
225 self.__removePolicy = policy |
|
226 self.__saveTimer.changeOccurred() |
|
227 |
|
228 def save(self): |
|
229 """ |
|
230 Public method to save the download settings. |
|
231 """ |
|
232 if not self.__loaded: |
|
233 return |
|
234 |
|
235 Preferences.setHelp("DownloadManagerRemovePolicy", self.__removePolicy) |
|
236 Preferences.setHelp("DownloadManagerSize", self.size()) |
|
237 if self.__removePolicy == DownloadManager.RemoveExit: |
|
238 return |
|
239 |
|
240 downloads = [] |
|
241 for download in self.__downloads: |
|
242 downloads.append(download.getData()) |
|
243 Preferences.setHelp("DownloadManagerDownloads", downloads) |
|
244 |
|
245 def __load(self): |
|
246 """ |
|
247 Public method to load the download settings. |
|
248 """ |
|
249 if self.__loaded: |
|
250 return |
|
251 |
|
252 self.__removePolicy = Preferences.getHelp("DownloadManagerRemovePolicy") |
|
253 size = Preferences.getHelp("DownloadManagerSize") |
|
254 if size.isValid(): |
|
255 self.resize(size) |
|
256 downloads = Preferences.getHelp("DownloadManagerDownloads") |
|
257 for download in downloads: |
|
258 if not download[0].isEmpty() and \ |
|
259 download[1] != "": |
|
260 itm = DownloadItem(parent = self) |
|
261 itm.setData(download) |
|
262 self.__addItem(itm) |
|
263 self.cleanupButton.setEnabled( |
|
264 (len(self.__downloads) - self.activeDownloads()) > 0) |
|
265 |
|
266 self.__loaded = True |
|
267 |
|
268 def cleanup(self): |
|
269 """ |
|
270 Public slot to cleanup the downloads. |
|
271 """ |
|
272 self.on_cleanupButton_clicked() |
|
273 |
|
274 @pyqtSlot() |
|
275 def on_cleanupButton_clicked(self): |
|
276 """ |
|
277 Private slot cleanup the downloads. |
|
278 """ |
|
279 if len(self.__downloads) == 0: |
|
280 return |
|
281 |
|
282 self.__model.removeRows(0, len(self.__downloads)) |
|
283 self.__updateItemCount() |
|
284 if len(self.__downloads) == 0 and \ |
|
285 self.__iconProvider is not None: |
|
286 self.__iconProvider = None |
|
287 |
|
288 self.__saveTimer.changeOccurred() |
|
289 |
|
290 def __updateItemCount(self): |
|
291 """ |
|
292 Private method to update the count label. |
|
293 """ |
|
294 count = len(self.__downloads) |
|
295 self.countLabel.setText(self.trUtf8("%n Download(s)", "", count)) |
|
296 |
|
297 def setDownloadDirectory(self, directory): |
|
298 """ |
|
299 Public method to set the current download directory. |
|
300 |
|
301 @param directory current download directory (string) |
|
302 """ |
|
303 self.__downloadDirectory = directory |
|
304 if self.__downloadDirectory != "": |
|
305 self.__downloadDirectory += "/" |
|
306 |
|
307 def downloadDirectory(self): |
|
308 """ |
|
309 Public method to get the current download directory. |
|
310 |
|
311 @return current download directory (string) |
|
312 """ |
|
313 return self.__downloadDirectory |
|
314 |
|
315 def count(self): |
|
316 """ |
|
317 Public method to get the number of downloads. |
|
318 |
|
319 @return number of downloads (integer) |
|
320 """ |
|
321 return len(self.__downloads) |
|
322 |
|
323 def downloads(self): |
|
324 """ |
|
325 Public method to get a reference to the downloads. |
|
326 |
|
327 @return reference to the downloads (list of DownloadItem) |
|
328 """ |
|
329 return self.__downloads |
|
330 |
|
331 def changeOccurred(self): |
|
332 """ |
|
333 Public method to signal a change. |
|
334 """ |
|
335 self.__saveTimer.changeOccurred() |