eric6/Helpviewer/SiteInfo/SiteInfoDialog.py

branch
maintenance
changeset 7286
7eb04391adf7
parent 7226
babe80d84a3e
parent 7285
1ff497f33f31
child 7287
1c17f2191bdd
equal deleted inserted replaced
7226:babe80d84a3e 7286:7eb04391adf7
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2011 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show some information about a site.
8 """
9
10 from __future__ import unicode_literals
11
12 import os
13
14 from PyQt5.QtCore import pyqtSlot, QUrl, Qt, QFile
15 from PyQt5.QtGui import QPixmap, QCursor, QPainter, QColor, QBrush
16 from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QGraphicsScene, QMenu, \
17 QApplication, QListWidgetItem
18 from PyQt5.QtWebKit import QWebSettings
19
20 from E5Gui import E5MessageBox, E5FileDialog
21
22 try:
23 from .Ui_SiteInfoDialog import Ui_SiteInfoDialog # __IGNORE_WARNING__
24 SSL = True
25 except ImportError:
26 from .Ui_SiteInfoNoSslDialog import Ui_SiteInfoDialog # __IGNORE_WARNING__
27 SSL = False
28
29 from ..Download.DownloadUtilities import dataString
30
31 import UI.PixmapCache
32 from Globals import qVersionTuple
33
34
35 class SiteInfoDialog(QDialog, Ui_SiteInfoDialog):
36 """
37 Class implementing a dialog to show some information about a site.
38 """
39 okStyle = "QLabel { color : white; background-color : green; }"
40 nokStyle = "QLabel { color : white; background-color : red; }"
41
42 def __init__(self, browser, parent=None):
43 """
44 Constructor
45
46 @param browser reference to the browser window (HelpBrowser)
47 @param parent reference to the parent widget (QWidget)
48 """
49 super(SiteInfoDialog, self).__init__(parent)
50 self.setupUi(self)
51 self.setWindowFlags(Qt.Window)
52
53 # put icons
54 self.tabWidget.setTabIcon(
55 0, UI.PixmapCache.getIcon("siteinfo-general.png"))
56 self.tabWidget.setTabIcon(
57 1, UI.PixmapCache.getIcon("siteinfo-media.png"))
58 self.tabWidget.setTabIcon(
59 2, UI.PixmapCache.getIcon("siteinfo-databases.png"))
60 if SSL:
61 self.tabWidget.setTabIcon(
62 3, UI.PixmapCache.getIcon("siteinfo-security.png"))
63
64 self.__mainFrame = browser.page().mainFrame()
65 self.__baseUrl = browser.url()
66 title = browser.title()
67 sslInfo = browser.page().getSslCertificateChain()
68
69 #prepare background of image preview
70 self.__imagePreviewStandardBackground = \
71 self.imagePreview.backgroundBrush()
72 color1 = QColor(220, 220, 220)
73 color2 = QColor(160, 160, 160)
74 self.__tilePixmap = QPixmap(8, 8)
75 self.__tilePixmap.fill(color1)
76 tilePainter = QPainter(self.__tilePixmap)
77 tilePainter.fillRect(0, 0, 4, 4, color2)
78 tilePainter.fillRect(4, 4, 4, 4, color2)
79 tilePainter.end()
80
81 # populate General tab
82 self.heading.setText("<b>{0}</b>".format(title))
83 self.siteAddressLabel.setText(self.__mainFrame.baseUrl().toString())
84 self.sizeLabel.setText(dataString(browser.page().totalBytes()))
85 encoding = ""
86
87 # populate Meta tags
88 meta = self.__mainFrame.findAllElements("meta")
89 for element in meta:
90 content = element.attribute("content")
91 name = element.attribute("name")
92 if not name:
93 name = element.attribute("http-equiv")
94 if element.attribute("charset"):
95 encoding = element.attribute("charset")
96 if "charset=" in content:
97 encoding = content[content.index("charset=") + 8:]
98
99 if not content or not name:
100 continue
101
102 QTreeWidgetItem(self.tagsTree, [name, content])
103 for col in range(self.tagsTree.columnCount()):
104 self.tagsTree.resizeColumnToContents(col)
105
106 if not encoding:
107 encoding = QWebSettings.globalSettings().defaultTextEncoding()
108 self.encodingLabel.setText(encoding)
109
110 # populate the Security info and the Security tab
111 if sslInfo and \
112 ((qVersionTuple() >= (5, 0, 0) and
113 not sslInfo[0].isBlacklisted()) or
114 (qVersionTuple() < (5, 0, 0) and sslInfo[0].isValid())):
115 self.securityLabel.setStyleSheet(SiteInfoDialog.okStyle)
116 self.securityLabel.setText('<b>Connection is encrypted.</b>')
117 if SSL:
118 self.sslWidget.showCertificateChain(sslInfo)
119 self.securityDetailsButton.setEnabled(True)
120 else:
121 self.securityDetailsButton.setEnabled(False)
122 else:
123 self.securityLabel.setStyleSheet(SiteInfoDialog.nokStyle)
124 self.securityLabel.setText('<b>Connection is not encrypted.</b>')
125 self.securityDetailsButton.setEnabled(False)
126 self.tabWidget.setTabEnabled(
127 self.tabWidget.indexOf(self.securityTab), False)
128
129 # populate Media tab
130 images = self.__mainFrame.findAllElements("img")
131 for element in images:
132 src = element.attribute("src")
133 alt = element.attribute("alt")
134 if src and src.startswith("data:"):
135 continue
136 if not alt:
137 if src.find("/") == -1:
138 alt = src
139 else:
140 pos = src.find("/")
141 alt = src[pos + 1:]
142
143 if not src or not alt:
144 continue
145
146 QTreeWidgetItem(self.imagesTree, [alt, src])
147 for col in range(self.imagesTree.columnCount()):
148 self.imagesTree.resizeColumnToContents(col)
149 if self.imagesTree.columnWidth(0) > 300:
150 self.imagesTree.setColumnWidth(0, 300)
151 self.imagesTree.setCurrentItem(self.imagesTree.topLevelItem(0))
152 self.imagesTree.setContextMenuPolicy(Qt.CustomContextMenu)
153 self.imagesTree.customContextMenuRequested.connect(
154 self.__imagesTreeContextMenuRequested)
155
156 # populate the Databases tab
157 databases = self.__mainFrame.securityOrigin().databases()
158 counter = 0
159 for database in databases:
160 itm = QListWidgetItem(self.databasesList)
161 itm.setText(database.displayName())
162 itm.setData(Qt.UserRole, counter)
163 counter += 1
164
165 if counter == 0:
166 itm = QListWidgetItem(self.databasesList)
167 itm.setText(self.tr("No databases are used by this page."))
168 itm.setFlags(itm.flags() & Qt.ItemIsSelectable)
169
170 @pyqtSlot()
171 def on_securityDetailsButton_clicked(self):
172 """
173 Private slot to show security details.
174 """
175 self.tabWidget.setCurrentIndex(
176 self.tabWidget.indexOf(self.securityTab))
177
178 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
179 def on_imagesTree_currentItemChanged(self, current, previous):
180 """
181 Private slot to show a preview of the selected image.
182
183 @param current current image entry (QTreeWidgetItem)
184 @param previous old current entry (QTreeWidgetItem)
185 """
186 if current is None:
187 return
188
189 imageUrl = QUrl(current.text(1))
190 if imageUrl.isRelative():
191 imageUrl = self.__baseUrl.resolved(imageUrl)
192
193 import Helpviewer.HelpWindow
194 cache = Helpviewer.HelpWindow.HelpWindow.networkAccessManager().cache()
195 if cache:
196 cacheData = cache.data(imageUrl)
197 else:
198 cacheData = None
199 pixmap = QPixmap()
200 invalidPixmap = False
201 scene = QGraphicsScene(self.imagePreview)
202 if not cacheData:
203 invalidPixmap = True
204 else:
205 pixmap.loadFromData(cacheData.readAll())
206 if pixmap.isNull():
207 invalidPixmap = True
208 if invalidPixmap:
209 self.imagePreview.setBackgroundBrush(
210 self.__imagePreviewStandardBackground)
211 scene.addText(self.tr("Preview not available."))
212 else:
213 self.imagePreview.setBackgroundBrush(QBrush(self.__tilePixmap))
214 scene.addPixmap(pixmap)
215 self.imagePreview.setScene(scene)
216
217 def __imagesTreeContextMenuRequested(self, pos):
218 """
219 Private slot to show a context menu for the images list.
220
221 @param pos position for the menu (QPoint)
222 """
223 itm = self.imagesTree.itemAt(pos)
224 if itm is None:
225 return
226
227 menu = QMenu()
228 act = menu.addAction(self.tr("Copy Image Location to Clipboard"))
229 act.setData(itm.text(1))
230 act.triggered.connect(lambda: self.__copyAction(act))
231 act = menu.addAction(self.tr("Copy Image Name to Clipboard"))
232 act.setData(itm.text(0))
233 act.triggered.connect(lambda: self.__copyAction(act))
234 menu.addSeparator()
235 act = menu.addAction(self.tr("Save Image"))
236 act.setData(self.imagesTree.indexOfTopLevelItem(itm))
237 act.triggered.connect(lambda: self.__saveImage(act))
238 menu.exec_(QCursor.pos())
239
240 def __copyAction(self, act):
241 """
242 Private slot to copy the image URL or the image name to the clipboard.
243
244 @param act reference to the action that triggered
245 @type QAction
246 """
247 QApplication.clipboard().setText(act.data())
248
249 def __saveImage(self, act):
250 """
251 Private slot to save the selected image to disk.
252
253 @param act reference to the action that triggered
254 @type QAction
255 """
256 index = act.data()
257 itm = self.imagesTree.topLevelItem(index)
258 if itm is None:
259 return
260
261 imageUrl = QUrl(itm.text(1))
262 if not imageUrl.host():
263 imageUrl.setHost(QUrl(self.siteAddressLabel.text()).host())
264 imageUrl.setScheme(QUrl(self.siteAddressLabel.text()).scheme())
265
266 import Helpviewer.HelpWindow
267 cache = Helpviewer.HelpWindow.HelpWindow.networkAccessManager().cache()
268 if cache:
269 cacheData = cache.data(imageUrl)
270 else:
271 cacheData = None
272 if not cacheData:
273 E5MessageBox.critical(
274 self,
275 self.tr("Save Image"),
276 self.tr("""This image is not available."""))
277 return
278
279 downloadDirectory = Helpviewer.HelpWindow.HelpWindow\
280 .downloadManager().downloadDirectory()
281 fn = os.path.join(downloadDirectory, os.path.basename(itm.text(1)))
282 filename = E5FileDialog.getSaveFileName(
283 self,
284 self.tr("Save Image"),
285 fn,
286 self.tr("All Files (*)"),
287 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
288
289 if not filename:
290 return
291
292 f = QFile(filename)
293 if not f.open(QFile.WriteOnly):
294 E5MessageBox.critical(
295 self,
296 self.tr("Save Image"),
297 self.tr(
298 """<p>Cannot write to file <b>{0}</b>.</p>""")
299 .format(filename))
300 return
301 f.write(cacheData.readAll())
302 f.close()
303
304 @pyqtSlot(QListWidgetItem, QListWidgetItem)
305 def on_databasesList_currentItemChanged(self, current, previous):
306 """
307 Private slot to show data about the selected database.
308
309 @param current current database entry (QTreeWidgetItem)
310 @param previous old current entry (QTreeWidgetItem)
311 """
312 if current is None:
313 return
314
315 dbId = current.data(Qt.UserRole)
316 databases = self.__mainFrame.securityOrigin().databases()
317
318 if dbId >= len(databases):
319 return
320
321 db = databases[dbId]
322 self.databaseName.setText(
323 "{0} ({1})".format(db.displayName(), db.name()))
324 self.databasePath.setText(db.fileName())
325 self.databaseSize.setText(dataString(db.size()))

eric ide

mercurial