eric7/WebBrowser/UrlBar/UrlBar.py

branch
eric7
changeset 8312
800c432b34c8
parent 8268
6b8128e0c9d1
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2010 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the URL bar widget.
8 """
9
10 from PyQt5.QtCore import pyqtSlot, Qt, QPointF, QUrl, QDateTime, QTimer, QPoint
11 from PyQt5.QtGui import QColor, QPalette, QLinearGradient, QIcon
12 from PyQt5.QtWidgets import QDialog, QApplication
13 from PyQt5.QtWebEngineWidgets import QWebEnginePage
14 try:
15 from PyQt5.QtNetwork import QSslCertificate # __IGNORE_EXCEPTION__
16 except ImportError:
17 QSslCertificate = None # __IGNORE_WARNING__
18
19 from E5Gui.E5LineEdit import E5LineEdit, E5LineEditSide
20 from E5Gui.E5LineEditButton import E5LineEditButton
21
22 from WebBrowser.WebBrowserWindow import WebBrowserWindow
23
24 from WebBrowser.SafeBrowsing.SafeBrowsingLabel import SafeBrowsingLabel
25
26 from .FavIconLabel import FavIconLabel
27 from .SslLabel import SslLabel
28
29 import UI.PixmapCache
30 import Preferences
31 import Utilities
32
33
34 class UrlBar(E5LineEdit):
35 """
36 Class implementing a line edit for entering URLs.
37 """
38 def __init__(self, mainWindow, parent=None):
39 """
40 Constructor
41
42 @param mainWindow reference to the main window (WebBrowserWindow)
43 @param parent reference to the parent widget (WebBrowserView)
44 """
45 E5LineEdit.__init__(self, parent)
46 self.setInactiveText(self.tr("Enter the URL here."))
47 self.setWhatsThis(self.tr("Enter the URL here."))
48
49 self.__mw = mainWindow
50 self.__browser = None
51 self.__privateMode = WebBrowserWindow.isPrivate()
52
53 self.__bmActiveIcon = UI.PixmapCache.getIcon("bookmark16")
54 self.__bmInactiveIcon = QIcon(
55 self.__bmActiveIcon.pixmap(16, 16, QIcon.Mode.Disabled))
56
57 self.__safeBrowsingLabel = SafeBrowsingLabel(self)
58 self.addWidget(self.__safeBrowsingLabel, E5LineEditSide.LEFT)
59 self.__safeBrowsingLabel.setVisible(False)
60
61 self.__favicon = FavIconLabel(self)
62 self.addWidget(self.__favicon, E5LineEditSide.LEFT)
63
64 self.__sslLabel = SslLabel(self)
65 self.addWidget(self.__sslLabel, E5LineEditSide.LEFT)
66 self.__sslLabel.setVisible(False)
67
68 self.__rssButton = E5LineEditButton(self)
69 self.__rssButton.setIcon(UI.PixmapCache.getIcon("rss16"))
70 self.addWidget(self.__rssButton, E5LineEditSide.RIGHT)
71 self.__rssButton.setVisible(False)
72
73 self.__bookmarkButton = E5LineEditButton(self)
74 self.addWidget(self.__bookmarkButton, E5LineEditSide.RIGHT)
75 self.__bookmarkButton.setVisible(False)
76
77 self.__clearButton = E5LineEditButton(self)
78 self.__clearButton.setIcon(UI.PixmapCache.getIcon("clearLeft"))
79 self.addWidget(self.__clearButton, E5LineEditSide.RIGHT)
80 self.__clearButton.setVisible(False)
81
82 self.__safeBrowsingLabel.clicked.connect(self.__showThreatInfo)
83 self.__bookmarkButton.clicked.connect(self.__showBookmarkInfo)
84 self.__rssButton.clicked.connect(self.__rssClicked)
85 self.__clearButton.clicked.connect(self.clear)
86 self.textChanged.connect(self.__textChanged)
87
88 self.__mw.bookmarksManager().entryChanged.connect(
89 self.__bookmarkChanged)
90 self.__mw.bookmarksManager().entryAdded.connect(
91 self.__bookmarkChanged)
92 self.__mw.bookmarksManager().entryRemoved.connect(
93 self.__bookmarkChanged)
94 self.__mw.speedDial().pagesChanged.connect(
95 self.__bookmarkChanged)
96
97 def setBrowser(self, browser):
98 """
99 Public method to set the browser connection.
100
101 @param browser reference to the browser widget (WebBrowserView)
102 """
103 self.__browser = browser
104 self.__favicon.setBrowser(browser)
105
106 self.__browser.urlChanged.connect(self.__browserUrlChanged)
107 self.__browser.loadProgress.connect(self.update)
108 self.__browser.loadFinished.connect(self.__loadFinished)
109 self.__browser.loadStarted.connect(self.__loadStarted)
110
111 self.__browser.safeBrowsingBad.connect(
112 self.__safeBrowsingLabel.setThreatInfo)
113
114 self.__sslLabel.clicked.connect(self.__browser.page().showSslInfo)
115 self.__browser.page().sslConfigurationChanged.connect(
116 self.__sslConfigurationChanged)
117
118 def browser(self):
119 """
120 Public method to get the associated browser.
121
122 @return reference to the associated browser (HelpBrowser)
123 """
124 return self.__browser
125
126 def __browserUrlChanged(self, url):
127 """
128 Private slot to handle a URL change of the associated browser.
129
130 @param url new URL of the browser (QUrl)
131 """
132 strUrl = url.toString()
133 if strUrl in ["eric:speeddial", "eric:home",
134 "about:blank", "about:config"]:
135 strUrl = ""
136
137 if self.text() != strUrl:
138 self.setText(strUrl)
139 self.setCursorPosition(0)
140
141 def __loadStarted(self):
142 """
143 Private slot to perform actions before the page is loaded.
144 """
145 self.__bookmarkButton.setVisible(False)
146 self.__rssButton.setVisible(False)
147 self.__sslLabel.setVisible(False)
148
149 def __checkBookmark(self):
150 """
151 Private slot to check the current URL for the bookmarked state.
152 """
153 manager = self.__mw.bookmarksManager()
154 if manager.bookmarkForUrl(self.__browser.url()) is not None:
155 self.__bookmarkButton.setIcon(self.__bmActiveIcon)
156 bookmarks = manager.bookmarksForUrl(self.__browser.url())
157 from WebBrowser.Bookmarks.BookmarkNode import BookmarkNode
158 for bookmark in bookmarks:
159 manager.setTimestamp(bookmark, BookmarkNode.TsVisited,
160 QDateTime.currentDateTime())
161 elif self.__mw.speedDial().pageForUrl(self.__browser.url()).url != "":
162 self.__bookmarkButton.setIcon(self.__bmActiveIcon)
163 else:
164 self.__bookmarkButton.setIcon(self.__bmInactiveIcon)
165
166 def __loadFinished(self, ok):
167 """
168 Private slot to set some data after the page was loaded.
169
170 @param ok flag indicating a successful load (boolean)
171 """
172 if self.__browser.url().scheme() in ["eric", "about"]:
173 self.__bookmarkButton.setVisible(False)
174 else:
175 self.__checkBookmark()
176 self.__bookmarkButton.setVisible(True)
177
178 self.__browserUrlChanged(self.__browser.url())
179 self.__safeBrowsingLabel.setVisible(
180 not self.__browser.getSafeBrowsingStatus())
181
182 if ok:
183 QTimer.singleShot(0, self.__setRssButton)
184
185 def __textChanged(self, txt):
186 """
187 Private slot to handle changes of the text.
188
189 @param txt current text (string)
190 """
191 self.__clearButton.setVisible(txt != "")
192
193 def preferencesChanged(self):
194 """
195 Public slot to handle a change of preferences.
196 """
197 self.update()
198
199 def __showBookmarkInfo(self):
200 """
201 Private slot to show a dialog with some bookmark info.
202 """
203 from .BookmarkActionSelectionDialog import (
204 BookmarkActionSelectionDialog
205 )
206 url = self.__browser.url()
207 dlg = BookmarkActionSelectionDialog(url)
208 if dlg.exec() == QDialog.DialogCode.Accepted:
209 action = dlg.getAction()
210 if action == BookmarkActionSelectionDialog.AddBookmark:
211 self.__browser.addBookmark()
212 elif action == BookmarkActionSelectionDialog.EditBookmark:
213 bookmark = (
214 self.__mw.bookmarksManager().bookmarkForUrl(url)
215 )
216 from .BookmarkInfoDialog import BookmarkInfoDialog
217 dlg = BookmarkInfoDialog(bookmark, self.__browser)
218 dlg.exec()
219 elif action == BookmarkActionSelectionDialog.AddSpeeddial:
220 self.__mw.speedDial().addPage(
221 url, self.__browser.title())
222 elif action == BookmarkActionSelectionDialog.RemoveSpeeddial:
223 self.__mw.speedDial().removePage(url)
224
225 @pyqtSlot()
226 def __bookmarkChanged(self):
227 """
228 Private slot to handle bookmark or speed dial changes.
229 """
230 self.__checkBookmark()
231
232 def paintEvent(self, evt):
233 """
234 Protected method handling a paint event.
235
236 @param evt reference to the paint event (QPaintEvent)
237 """
238 foregroundColor = QApplication.palette().color(QPalette.ColorRole.Text)
239
240 backgroundColor = (
241 Preferences.getWebBrowser("PrivateModeUrlColor")
242 if self.__privateMode else
243 QApplication.palette().color(QPalette.ColorRole.Base)
244 )
245
246 if self.__browser is not None:
247 p = self.palette()
248 progress = self.__browser.progress()
249
250 if not self.__browser.getSafeBrowsingStatus():
251 # malicious web site
252 backgroundColor = Preferences.getWebBrowser(
253 "MaliciousUrlColor")
254 elif self.__browser.url().scheme() == "https":
255 if WebBrowserWindow.networkManager().isInsecureHost(
256 self.__browser.url().host()
257 ):
258 backgroundColor = Preferences.getWebBrowser(
259 "InsecureUrlColor")
260 else:
261 backgroundColor = Preferences.getWebBrowser(
262 "SecureUrlColor")
263
264 if progress in (0, 100):
265 p.setBrush(QPalette.ColorRole.Base, backgroundColor)
266 p.setBrush(QPalette.ColorRole.Text, foregroundColor)
267 else:
268 highlight = QApplication.palette().color(
269 QPalette.ColorRole.Highlight)
270 r = (highlight.red() + 2 * backgroundColor.red()) // 3
271 g = (highlight.green() + 2 * backgroundColor.green()) // 3
272 b = (highlight.blue() + 2 * backgroundColor.blue()) // 3
273
274 loadingColor = QColor(r, g, b)
275 if abs(loadingColor.lightness() -
276 backgroundColor.lightness()) < 20:
277 # special handling for special color schemes (e.g Gaia)
278 r = (2 * highlight.red() + backgroundColor.red()) // 3
279 g = (2 * highlight.green() + backgroundColor.green()) // 3
280 b = (2 * highlight.blue() + backgroundColor.blue()) // 3
281 loadingColor = QColor(r, g, b)
282
283 gradient = QLinearGradient(
284 QPointF(0, 0), QPointF(self.width(), 0))
285 gradient.setColorAt(0, loadingColor)
286 gradient.setColorAt(progress / 100.0 - 0.000001, loadingColor)
287 gradient.setColorAt(progress / 100.0, backgroundColor)
288 p.setBrush(QPalette.ColorRole.Base, gradient)
289
290 self.setPalette(p)
291
292 E5LineEdit.paintEvent(self, evt)
293
294 def focusOutEvent(self, evt):
295 """
296 Protected method to handle focus out event.
297
298 @param evt reference to the focus event (QFocusEvent)
299 """
300 if self.text() == "" and self.__browser is not None:
301 self.__browserUrlChanged(self.__browser.url())
302 E5LineEdit.focusOutEvent(self, evt)
303
304 def mousePressEvent(self, evt):
305 """
306 Protected method called by a mouse press event.
307
308 @param evt reference to the mouse event (QMouseEvent)
309 """
310 if evt.button() == Qt.MouseButton.XButton1:
311 self.__mw.currentBrowser().triggerPageAction(
312 QWebEnginePage.WebAction.Back)
313 elif evt.button() == Qt.MouseButton.XButton2:
314 self.__mw.currentBrowser().triggerPageAction(
315 QWebEnginePage.WebAction.Forward)
316 else:
317 super().mousePressEvent(evt)
318
319 def mouseDoubleClickEvent(self, evt):
320 """
321 Protected method to handle mouse double click events.
322
323 @param evt reference to the mouse event (QMouseEvent)
324 """
325 if evt.button() == Qt.MouseButton.LeftButton:
326 self.selectAll()
327 else:
328 E5LineEdit.mouseDoubleClickEvent(self, evt)
329
330 def keyPressEvent(self, evt):
331 """
332 Protected method to handle key presses.
333
334 @param evt reference to the key press event (QKeyEvent)
335 """
336 if evt.key() == Qt.Key.Key_Escape:
337 if self.__browser is not None:
338 self.setText(
339 str(self.__browser.url().toEncoded(), encoding="utf-8"))
340 self.selectAll()
341 completer = self.completer()
342 if completer:
343 completer.popup().hide()
344 return
345
346 currentText = self.text().strip()
347 if (
348 evt.key() in [Qt.Key.Key_Enter, Qt.Key.Key_Return] and
349 not currentText.lower().startswith(("http://", "https://"))
350 ):
351 append = ""
352 if evt.modifiers() == Qt.KeyboardModifiers(
353 Qt.KeyboardModifier.ControlModifier
354 ):
355 append = ".com"
356 elif (
357 evt.modifiers() == Qt.KeyboardModifiers(
358 Qt.KeyboardModifier.ControlModifier |
359 Qt.KeyboardModifier.ShiftModifier
360 )
361 ):
362 append = ".org"
363 elif evt.modifiers() == Qt.KeyboardModifiers(
364 Qt.KeyboardModifier.ShiftModifier
365 ):
366 append = ".net"
367
368 if append != "":
369 url = QUrl("http://www." + currentText)
370 host = url.host()
371 if not host.lower().endswith(append):
372 host += append
373 url.setHost(host)
374 self.setText(url.toString())
375
376 E5LineEdit.keyPressEvent(self, evt)
377
378 def dragEnterEvent(self, evt):
379 """
380 Protected method to handle drag enter events.
381
382 @param evt reference to the drag enter event (QDragEnterEvent)
383 """
384 mimeData = evt.mimeData()
385 if mimeData.hasUrls() or mimeData.hasText():
386 evt.acceptProposedAction()
387
388 E5LineEdit.dragEnterEvent(self, evt)
389
390 def dropEvent(self, evt):
391 """
392 Protected method to handle drop events.
393
394 @param evt reference to the drop event (QDropEvent)
395 """
396 mimeData = evt.mimeData()
397
398 url = QUrl()
399 if mimeData.hasUrls():
400 url = mimeData.urls()[0]
401 elif mimeData.hasText():
402 url = QUrl.fromEncoded(mimeData.text().encode("utf-8"),
403 QUrl.ParsingMode.TolerantMode)
404
405 if url.isEmpty() or not url.isValid():
406 E5LineEdit.dropEvent(self, evt)
407 return
408
409 self.setText(str(url.toEncoded(), encoding="utf-8"))
410 self.selectAll()
411
412 evt.acceptProposedAction()
413
414 def __setRssButton(self):
415 """
416 Private slot to show the RSS button.
417 """
418 self.__rssButton.setVisible(self.__browser.checkRSS())
419
420 def __rssClicked(self):
421 """
422 Private slot to handle clicking the RSS icon.
423 """
424 from WebBrowser.Feeds.FeedsDialog import FeedsDialog
425 feeds = self.__browser.getRSS()
426 dlg = FeedsDialog(feeds, self.__browser)
427 dlg.exec()
428
429 @pyqtSlot(QPoint)
430 def __showThreatInfo(self, pos):
431 """
432 Private slot to show the threat info widget.
433
434 @param pos position to show the info at
435 @type QPoint
436 """
437 threatInfo = self.__safeBrowsingLabel.getThreatInfo()
438 if threatInfo:
439 from WebBrowser.SafeBrowsing.SafeBrowsingInfoWidget import (
440 SafeBrowsingInfoWidget
441 )
442 widget = SafeBrowsingInfoWidget(threatInfo, self.__browser)
443 widget.showAt(pos)
444
445 @pyqtSlot()
446 def __sslConfigurationChanged(self):
447 """
448 Private slot to handle a change of the associated web page SSL
449 configuration.
450 """
451 sslConfiguration = self.__browser.page().getSslConfiguration()
452 if sslConfiguration is not None and QSslCertificate is not None:
453 sslCertificate = self.__browser.page().getSslCertificate()
454 if sslCertificate is not None:
455 org = Utilities.decodeString(", ".join(
456 sslCertificate.subjectInfo(
457 QSslCertificate.SubjectInfo.Organization)))
458 if org == "":
459 cn = Utilities.decodeString(", ".join(
460 sslCertificate.subjectInfo(
461 QSslCertificate.SubjectInfo.CommonName)))
462 if cn != "":
463 org = cn.split(".", 1)[1]
464 if org == "":
465 org = self.tr("Unknown")
466 self.__sslLabel.setText(" {0} ".format(org))
467 self.__sslLabel.setVisible(True)
468 valid = not sslCertificate.isBlacklisted()
469 if valid:
470 config = self.__browser.page().getSslConfiguration()
471 if config is None or config.sessionCipher().isNull():
472 valid = False
473 self.__sslLabel.setValidity(valid)
474 else:
475 self.__sslLabel.setVisible(False)
476 else:
477 self.__sslLabel.setVisible(False)

eric ide

mercurial