35 |
41 |
36 class SiteInfoDialog(QDialog, Ui_SiteInfoDialog): |
42 class SiteInfoDialog(QDialog, Ui_SiteInfoDialog): |
37 """ |
43 """ |
38 Class implementing a dialog to show some information about a site. |
44 Class implementing a dialog to show some information about a site. |
39 """ |
45 """ |
|
46 |
40 securityStyleFormat = "QLabel {{ background-color : {0}; }}" |
47 securityStyleFormat = "QLabel {{ background-color : {0}; }}" |
41 |
48 |
42 def __init__(self, browser, parent=None): |
49 def __init__(self, browser, parent=None): |
43 """ |
50 """ |
44 Constructor |
51 Constructor |
45 |
52 |
46 @param browser reference to the browser window (HelpBrowser) |
53 @param browser reference to the browser window (HelpBrowser) |
47 @param parent reference to the parent widget (QWidget) |
54 @param parent reference to the parent widget (QWidget) |
48 """ |
55 """ |
49 super().__init__(parent) |
56 super().__init__(parent) |
50 self.setupUi(self) |
57 self.setupUi(self) |
51 self.setWindowFlags(Qt.WindowType.Window) |
58 self.setWindowFlags(Qt.WindowType.Window) |
52 |
59 |
53 # put icons |
60 # put icons |
54 self.tabWidget.setTabIcon( |
61 self.tabWidget.setTabIcon(0, UI.PixmapCache.getIcon("siteinfo-general")) |
55 0, UI.PixmapCache.getIcon("siteinfo-general")) |
62 self.tabWidget.setTabIcon(1, UI.PixmapCache.getIcon("siteinfo-media")) |
56 self.tabWidget.setTabIcon( |
|
57 1, UI.PixmapCache.getIcon("siteinfo-media")) |
|
58 if SSL: |
63 if SSL: |
59 self.tabWidget.setTabIcon( |
64 self.tabWidget.setTabIcon(2, UI.PixmapCache.getIcon("siteinfo-security")) |
60 2, UI.PixmapCache.getIcon("siteinfo-security")) |
65 |
61 |
|
62 self.__imageReply = None |
66 self.__imageReply = None |
63 |
67 |
64 self.__baseUrl = browser.url() |
68 self.__baseUrl = browser.url() |
65 title = browser.title() |
69 title = browser.title() |
66 sslInfo = browser.page().getSslCertificateChain() |
70 sslInfo = browser.page().getSslCertificateChain() |
67 |
71 |
68 #prepare background of image preview |
72 # prepare background of image preview |
69 self.__imagePreviewStandardBackground = ( |
73 self.__imagePreviewStandardBackground = self.imagePreview.backgroundBrush() |
70 self.imagePreview.backgroundBrush() |
|
71 ) |
|
72 color1 = QColor(220, 220, 220) |
74 color1 = QColor(220, 220, 220) |
73 color2 = QColor(160, 160, 160) |
75 color2 = QColor(160, 160, 160) |
74 self.__tilePixmap = QPixmap(8, 8) |
76 self.__tilePixmap = QPixmap(8, 8) |
75 self.__tilePixmap.fill(color1) |
77 self.__tilePixmap.fill(color1) |
76 tilePainter = QPainter(self.__tilePixmap) |
78 tilePainter = QPainter(self.__tilePixmap) |
77 tilePainter.fillRect(0, 0, 4, 4, color2) |
79 tilePainter.fillRect(0, 0, 4, 4, color2) |
78 tilePainter.fillRect(4, 4, 4, 4, color2) |
80 tilePainter.fillRect(4, 4, 4, 4, color2) |
79 tilePainter.end() |
81 tilePainter.end() |
80 |
82 |
81 # populate General tab |
83 # populate General tab |
82 self.heading.setText("<b>{0}</b>".format(title)) |
84 self.heading.setText("<b>{0}</b>".format(title)) |
83 self.siteAddressLabel.setText(self.__baseUrl.toString()) |
85 self.siteAddressLabel.setText(self.__baseUrl.toString()) |
84 if self.__baseUrl.scheme() in ["https"]: |
86 if self.__baseUrl.scheme() in ["https"]: |
85 if WebBrowserWindow.networkManager().isInsecureHost( |
87 if WebBrowserWindow.networkManager().isInsecureHost(self.__baseUrl.host()): |
86 self.__baseUrl.host() |
|
87 ): |
|
88 self.securityIconLabel.setPixmap( |
88 self.securityIconLabel.setPixmap( |
89 UI.PixmapCache.getPixmap("securityMedium")) |
89 UI.PixmapCache.getPixmap("securityMedium") |
|
90 ) |
90 self.securityLabel.setStyleSheet( |
91 self.securityLabel.setStyleSheet( |
91 SiteInfoDialog.securityStyleFormat.format( |
92 SiteInfoDialog.securityStyleFormat.format( |
92 Preferences.getWebBrowser("InsecureUrlColor").name() |
93 Preferences.getWebBrowser("InsecureUrlColor").name() |
93 ) |
94 ) |
94 ) |
95 ) |
95 self.securityLabel.setText(self.tr( |
96 self.securityLabel.setText( |
96 '<b>Connection is encrypted but may be insecure.</b>')) |
97 self.tr("<b>Connection is encrypted but may be insecure.</b>") |
|
98 ) |
97 else: |
99 else: |
98 self.securityIconLabel.setPixmap( |
100 self.securityIconLabel.setPixmap( |
99 UI.PixmapCache.getPixmap("securityHigh")) |
101 UI.PixmapCache.getPixmap("securityHigh") |
|
102 ) |
100 self.securityLabel.setStyleSheet( |
103 self.securityLabel.setStyleSheet( |
101 SiteInfoDialog.securityStyleFormat.format( |
104 SiteInfoDialog.securityStyleFormat.format( |
102 Preferences.getWebBrowser("SecureUrlColor").name() |
105 Preferences.getWebBrowser("SecureUrlColor").name() |
103 ) |
106 ) |
104 ) |
107 ) |
105 self.securityLabel.setText( |
108 self.securityLabel.setText(self.tr("<b>Connection is encrypted.</b>")) |
106 self.tr('<b>Connection is encrypted.</b>')) |
|
107 else: |
109 else: |
108 self.securityIconLabel.setPixmap( |
110 self.securityIconLabel.setPixmap(UI.PixmapCache.getPixmap("securityLow")) |
109 UI.PixmapCache.getPixmap("securityLow")) |
111 self.securityLabel.setText(self.tr("<b>Connection is not encrypted.</b>")) |
110 self.securityLabel.setText( |
|
111 self.tr('<b>Connection is not encrypted.</b>')) |
|
112 browser.page().runJavaScript( |
112 browser.page().runJavaScript( |
113 "document.charset", WebBrowserPage.SafeJsWorld, |
113 "document.charset", |
114 lambda res: self.encodingLabel.setText(res)) |
114 WebBrowserPage.SafeJsWorld, |
115 |
115 lambda res: self.encodingLabel.setText(res), |
|
116 ) |
|
117 |
116 # populate the Security tab |
118 # populate the Security tab |
117 if sslInfo and SSL: |
119 if sslInfo and SSL: |
118 self.sslWidget.showCertificateChain(sslInfo) |
120 self.sslWidget.showCertificateChain(sslInfo) |
119 self.tabWidget.setTabEnabled(2, SSL and bool(sslInfo)) |
121 self.tabWidget.setTabEnabled(2, SSL and bool(sslInfo)) |
120 self.securityDetailsButton.setEnabled(SSL and bool(sslInfo)) |
122 self.securityDetailsButton.setEnabled(SSL and bool(sslInfo)) |
121 |
123 |
122 # populate Meta tags |
124 # populate Meta tags |
123 browser.page().runJavaScript(Scripts.getAllMetaAttributes(), |
125 browser.page().runJavaScript( |
124 WebBrowserPage.SafeJsWorld, |
126 Scripts.getAllMetaAttributes(), |
125 self.__processMetaAttributes) |
127 WebBrowserPage.SafeJsWorld, |
126 |
128 self.__processMetaAttributes, |
|
129 ) |
|
130 |
127 # populate Media tab |
131 # populate Media tab |
128 browser.page().runJavaScript(Scripts.getAllImages(), |
132 browser.page().runJavaScript( |
129 WebBrowserPage.SafeJsWorld, |
133 Scripts.getAllImages(), WebBrowserPage.SafeJsWorld, self.__processImageTags |
130 self.__processImageTags) |
134 ) |
131 |
135 |
132 self.tabWidget.setCurrentIndex(0) |
136 self.tabWidget.setCurrentIndex(0) |
133 |
137 |
134 @pyqtSlot() |
138 @pyqtSlot() |
135 def on_securityDetailsButton_clicked(self): |
139 def on_securityDetailsButton_clicked(self): |
136 """ |
140 """ |
137 Private slot to show security details. |
141 Private slot to show security details. |
138 """ |
142 """ |
139 self.tabWidget.setCurrentIndex( |
143 self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.securityTab)) |
140 self.tabWidget.indexOf(self.securityTab)) |
144 |
141 |
|
142 def __processImageTags(self, res): |
145 def __processImageTags(self, res): |
143 """ |
146 """ |
144 Private method to process the image tags. |
147 Private method to process the image tags. |
145 |
148 |
146 @param res result of the JavaScript script |
149 @param res result of the JavaScript script |
147 @type list of dict |
150 @type list of dict |
148 """ |
151 """ |
149 for img in res: |
152 for img in res: |
150 src = img["src"] |
153 src = img["src"] |
152 if not alt: |
155 if not alt: |
153 if src.find("/") == -1: |
156 if src.find("/") == -1: |
154 alt = src |
157 alt = src |
155 else: |
158 else: |
156 pos = src.rfind("/") |
159 pos = src.rfind("/") |
157 alt = src[pos + 1:] |
160 alt = src[pos + 1 :] |
158 |
161 |
159 if not src or not alt: |
162 if not src or not alt: |
160 continue |
163 continue |
161 |
164 |
162 QTreeWidgetItem(self.imagesTree, [alt, src]) |
165 QTreeWidgetItem(self.imagesTree, [alt, src]) |
163 |
166 |
164 for col in range(self.imagesTree.columnCount()): |
167 for col in range(self.imagesTree.columnCount()): |
165 self.imagesTree.resizeColumnToContents(col) |
168 self.imagesTree.resizeColumnToContents(col) |
166 if self.imagesTree.columnWidth(0) > 300: |
169 if self.imagesTree.columnWidth(0) > 300: |
167 self.imagesTree.setColumnWidth(0, 300) |
170 self.imagesTree.setColumnWidth(0, 300) |
168 self.imagesTree.setCurrentItem(self.imagesTree.topLevelItem(0)) |
171 self.imagesTree.setCurrentItem(self.imagesTree.topLevelItem(0)) |
169 self.imagesTree.setContextMenuPolicy( |
172 self.imagesTree.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) |
170 Qt.ContextMenuPolicy.CustomContextMenu) |
|
171 self.imagesTree.customContextMenuRequested.connect( |
173 self.imagesTree.customContextMenuRequested.connect( |
172 self.__imagesTreeContextMenuRequested) |
174 self.__imagesTreeContextMenuRequested |
173 |
175 ) |
|
176 |
174 def __processMetaAttributes(self, res): |
177 def __processMetaAttributes(self, res): |
175 """ |
178 """ |
176 Private method to process the meta attributes. |
179 Private method to process the meta attributes. |
177 |
180 |
178 @param res result of the JavaScript script |
181 @param res result of the JavaScript script |
179 @type list of dict |
182 @type list of dict |
180 """ |
183 """ |
181 for meta in res: |
184 for meta in res: |
182 content = meta["content"] |
185 content = meta["content"] |
183 name = meta["name"] |
186 name = meta["name"] |
184 if not name: |
187 if not name: |
185 name = meta["httpequiv"] |
188 name = meta["httpequiv"] |
186 |
189 |
187 if not name or not content: |
190 if not name or not content: |
188 continue |
191 continue |
189 |
192 |
190 if meta["charset"]: |
193 if meta["charset"]: |
191 self.encodingLabel.setText(meta["charset"]) |
194 self.encodingLabel.setText(meta["charset"]) |
192 if "charset=" in content: |
195 if "charset=" in content: |
193 self.encodingLabel.setText( |
196 self.encodingLabel.setText(content[content.index("charset=") + 8 :]) |
194 content[content.index("charset=") + 8:]) |
197 |
195 |
|
196 QTreeWidgetItem(self.tagsTree, [name, content]) |
198 QTreeWidgetItem(self.tagsTree, [name, content]) |
197 for col in range(self.tagsTree.columnCount()): |
199 for col in range(self.tagsTree.columnCount()): |
198 self.tagsTree.resizeColumnToContents(col) |
200 self.tagsTree.resizeColumnToContents(col) |
199 |
201 |
200 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
202 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
201 def on_imagesTree_currentItemChanged(self, current, previous): |
203 def on_imagesTree_currentItemChanged(self, current, previous): |
202 """ |
204 """ |
203 Private slot to show a preview of the selected image. |
205 Private slot to show a preview of the selected image. |
204 |
206 |
205 @param current current image entry (QTreeWidgetItem) |
207 @param current current image entry (QTreeWidgetItem) |
206 @param previous old current entry (QTreeWidgetItem) |
208 @param previous old current entry (QTreeWidgetItem) |
207 """ |
209 """ |
208 if current is None: |
210 if current is None: |
209 return |
211 return |
210 |
212 |
211 imageUrl = QUrl(current.text(1)) |
213 imageUrl = QUrl(current.text(1)) |
212 if imageUrl.isRelative(): |
214 if imageUrl.isRelative(): |
213 imageUrl = self.__baseUrl.resolved(imageUrl) |
215 imageUrl = self.__baseUrl.resolved(imageUrl) |
214 |
216 |
215 pixmap = QPixmap() |
217 pixmap = QPixmap() |
216 loading = False |
218 loading = False |
217 |
219 |
218 if imageUrl.scheme() == "data": |
220 if imageUrl.scheme() == "data": |
219 encodedUrl = current.text(1).encode("utf-8") |
221 encodedUrl = current.text(1).encode("utf-8") |
220 imageData = encodedUrl[encodedUrl.find(b",") + 1:] |
222 imageData = encodedUrl[encodedUrl.find(b",") + 1 :] |
221 pixmap = WebBrowserTools.pixmapFromByteArray(imageData) |
223 pixmap = WebBrowserTools.pixmapFromByteArray(imageData) |
222 elif imageUrl.scheme() == "file": |
224 elif imageUrl.scheme() == "file": |
223 pixmap = QPixmap(imageUrl.toLocalFile()) |
225 pixmap = QPixmap(imageUrl.toLocalFile()) |
224 elif imageUrl.scheme() == "qrc": |
226 elif imageUrl.scheme() == "qrc": |
225 pixmap = QPixmap(imageUrl.toString()[3:]) |
227 pixmap = QPixmap(imageUrl.toString()[3:]) |
226 else: |
228 else: |
227 if self.__imageReply is not None: |
229 if self.__imageReply is not None: |
228 self.__imageReply.deleteLater() |
230 self.__imageReply.deleteLater() |
229 self.__imageReply = None |
231 self.__imageReply = None |
230 |
232 |
231 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
233 from WebBrowser.WebBrowserWindow import WebBrowserWindow |
|
234 |
232 self.__imageReply = WebBrowserWindow.networkManager().get( |
235 self.__imageReply = WebBrowserWindow.networkManager().get( |
233 QNetworkRequest(imageUrl)) |
236 QNetworkRequest(imageUrl) |
|
237 ) |
234 self.__imageReply.finished.connect(self.__imageReplyFinished) |
238 self.__imageReply.finished.connect(self.__imageReplyFinished) |
235 loading = True |
239 loading = True |
236 self.__showLoadingText() |
240 self.__showLoadingText() |
237 |
241 |
238 if not loading: |
242 if not loading: |
239 self.__showPixmap(pixmap) |
243 self.__showPixmap(pixmap) |
240 |
244 |
241 @pyqtSlot() |
245 @pyqtSlot() |
242 def __imageReplyFinished(self): |
246 def __imageReplyFinished(self): |
243 """ |
247 """ |
244 Private slot handling the loading of an image. |
248 Private slot handling the loading of an image. |
245 """ |
249 """ |
246 if self.__imageReply.error() != QNetworkReply.NetworkError.NoError: |
250 if self.__imageReply.error() != QNetworkReply.NetworkError.NoError: |
247 return |
251 return |
248 |
252 |
249 data = self.__imageReply.readAll() |
253 data = self.__imageReply.readAll() |
250 self.__showPixmap(QPixmap.fromImage(QImage.fromData(data))) |
254 self.__showPixmap(QPixmap.fromImage(QImage.fromData(data))) |
251 |
255 |
252 def __showPixmap(self, pixmap): |
256 def __showPixmap(self, pixmap): |
253 """ |
257 """ |
254 Private method to show a pixmap in the preview pane. |
258 Private method to show a pixmap in the preview pane. |
255 |
259 |
256 @param pixmap pixmap to be shown |
260 @param pixmap pixmap to be shown |
257 @type QPixmap |
261 @type QPixmap |
258 """ |
262 """ |
259 scene = QGraphicsScene(self.imagePreview) |
263 scene = QGraphicsScene(self.imagePreview) |
260 if pixmap.isNull(): |
264 if pixmap.isNull(): |
261 self.imagePreview.setBackgroundBrush( |
265 self.imagePreview.setBackgroundBrush(self.__imagePreviewStandardBackground) |
262 self.__imagePreviewStandardBackground) |
|
263 scene.addText(self.tr("Preview not available.")) |
266 scene.addText(self.tr("Preview not available.")) |
264 else: |
267 else: |
265 self.imagePreview.setBackgroundBrush(QBrush(self.__tilePixmap)) |
268 self.imagePreview.setBackgroundBrush(QBrush(self.__tilePixmap)) |
266 scene.addPixmap(pixmap) |
269 scene.addPixmap(pixmap) |
267 self.imagePreview.setScene(scene) |
270 self.imagePreview.setScene(scene) |
268 |
271 |
269 def __showLoadingText(self): |
272 def __showLoadingText(self): |
270 """ |
273 """ |
271 Private method to show some text while loading an image. |
274 Private method to show some text while loading an image. |
272 """ |
275 """ |
273 self.imagePreview.setBackgroundBrush( |
276 self.imagePreview.setBackgroundBrush(self.__imagePreviewStandardBackground) |
274 self.__imagePreviewStandardBackground) |
|
275 scene = QGraphicsScene(self.imagePreview) |
277 scene = QGraphicsScene(self.imagePreview) |
276 scene.addText(self.tr("Loading...")) |
278 scene.addText(self.tr("Loading...")) |
277 self.imagePreview.setScene(scene) |
279 self.imagePreview.setScene(scene) |
278 |
280 |
279 def __imagesTreeContextMenuRequested(self, pos): |
281 def __imagesTreeContextMenuRequested(self, pos): |
280 """ |
282 """ |
281 Private slot to show a context menu for the images list. |
283 Private slot to show a context menu for the images list. |
282 |
284 |
283 @param pos position for the menu (QPoint) |
285 @param pos position for the menu (QPoint) |
284 """ |
286 """ |
285 itm = self.imagesTree.itemAt(pos) |
287 itm = self.imagesTree.itemAt(pos) |
286 if itm is None: |
288 if itm is None: |
287 return |
289 return |
288 |
290 |
289 menu = QMenu() |
291 menu = QMenu() |
290 act1 = menu.addAction(self.tr("Copy Image Location to Clipboard")) |
292 act1 = menu.addAction(self.tr("Copy Image Location to Clipboard")) |
291 act1.setData(itm.text(1)) |
293 act1.setData(itm.text(1)) |
292 act1.triggered.connect(lambda: self.__copyAction(act1)) |
294 act1.triggered.connect(lambda: self.__copyAction(act1)) |
293 act2 = menu.addAction(self.tr("Copy Image Name to Clipboard")) |
295 act2 = menu.addAction(self.tr("Copy Image Name to Clipboard")) |
296 menu.addSeparator() |
298 menu.addSeparator() |
297 act3 = menu.addAction(self.tr("Save Image")) |
299 act3 = menu.addAction(self.tr("Save Image")) |
298 act3.setData(self.imagesTree.indexOfTopLevelItem(itm)) |
300 act3.setData(self.imagesTree.indexOfTopLevelItem(itm)) |
299 act3.triggered.connect(lambda: self.__saveImage(act3)) |
301 act3.triggered.connect(lambda: self.__saveImage(act3)) |
300 menu.exec(self.imagesTree.viewport().mapToGlobal(pos)) |
302 menu.exec(self.imagesTree.viewport().mapToGlobal(pos)) |
301 |
303 |
302 def __copyAction(self, act): |
304 def __copyAction(self, act): |
303 """ |
305 """ |
304 Private slot to copy the image URL or the image name to the clipboard. |
306 Private slot to copy the image URL or the image name to the clipboard. |
305 |
307 |
306 @param act reference to the action that triggered |
308 @param act reference to the action that triggered |
307 @type QAction |
309 @type QAction |
308 """ |
310 """ |
309 QApplication.clipboard().setText(act.data()) |
311 QApplication.clipboard().setText(act.data()) |
310 |
312 |
311 def __saveImage(self, act): |
313 def __saveImage(self, act): |
312 """ |
314 """ |
313 Private slot to save the selected image to disk. |
315 Private slot to save the selected image to disk. |
314 |
316 |
315 @param act reference to the action that triggered |
317 @param act reference to the action that triggered |
316 @type QAction |
318 @type QAction |
317 """ |
319 """ |
318 index = act.data() |
320 index = act.data() |
319 itm = self.imagesTree.topLevelItem(index) |
321 itm = self.imagesTree.topLevelItem(index) |
320 if itm is None: |
322 if itm is None: |
321 return |
323 return |
322 |
324 |
323 if ( |
325 if not self.imagePreview.scene() or len(self.imagePreview.scene().items()) == 0: |
324 not self.imagePreview.scene() or |
326 return |
325 len(self.imagePreview.scene().items()) == 0 |
327 |
326 ): |
|
327 return |
|
328 |
|
329 pixmapItem = self.imagePreview.scene().items()[0] |
328 pixmapItem = self.imagePreview.scene().items()[0] |
330 if not isinstance(pixmapItem, QGraphicsPixmapItem): |
329 if not isinstance(pixmapItem, QGraphicsPixmapItem): |
331 return |
330 return |
332 |
331 |
333 if pixmapItem.pixmap().isNull(): |
332 if pixmapItem.pixmap().isNull(): |
334 EricMessageBox.warning( |
333 EricMessageBox.warning( |
335 self, |
334 self, |
336 self.tr("Save Image"), |
335 self.tr("Save Image"), |
337 self.tr( |
336 self.tr("""<p>This preview is not available.</p>"""), |
338 """<p>This preview is not available.</p>""")) |
337 ) |
339 return |
338 return |
340 |
339 |
341 imageFileName = WebBrowserTools.getFileNameFromUrl(QUrl(itm.text(1))) |
340 imageFileName = WebBrowserTools.getFileNameFromUrl(QUrl(itm.text(1))) |
342 index = imageFileName.rfind(".") |
341 index = imageFileName.rfind(".") |
343 if index != -1: |
342 if index != -1: |
344 imageFileName = imageFileName[:index] + ".png" |
343 imageFileName = imageFileName[:index] + ".png" |
345 |
344 |
346 filename = EricFileDialog.getSaveFileName( |
345 filename = EricFileDialog.getSaveFileName( |
347 self, |
346 self, |
348 self.tr("Save Image"), |
347 self.tr("Save Image"), |
349 imageFileName, |
348 imageFileName, |
350 self.tr("All Files (*)"), |
349 self.tr("All Files (*)"), |
351 EricFileDialog.DontConfirmOverwrite) |
350 EricFileDialog.DontConfirmOverwrite, |
352 |
351 ) |
|
352 |
353 if not filename: |
353 if not filename: |
354 return |
354 return |
355 |
355 |
356 if not pixmapItem.pixmap().save(filename, "PNG"): |
356 if not pixmapItem.pixmap().save(filename, "PNG"): |
357 EricMessageBox.critical( |
357 EricMessageBox.critical( |
358 self, |
358 self, |
359 self.tr("Save Image"), |
359 self.tr("Save Image"), |
360 self.tr( |
360 self.tr("""<p>Cannot write to file <b>{0}</b>.</p>""").format(filename), |
361 """<p>Cannot write to file <b>{0}</b>.</p>""") |
361 ) |
362 .format(filename)) |
362 return |
363 return |
|