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

eric ide

mercurial