1# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: 2 3# Copyright 2014-2021 Florian Bruhin (The Compiler) <mail@qutebrowser.org> 4# 5# This file is part of qutebrowser. 6# 7# qutebrowser is free software: you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation, either version 3 of the License, or 10# (at your option) any later version. 11# 12# qutebrowser is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with qutebrowser. If not, see <https://www.gnu.org/licenses/>. 19 20"""URL displayed in the statusbar.""" 21 22import enum 23 24from PyQt5.QtCore import (pyqtSlot, pyqtProperty, # type: ignore[attr-defined] 25 QUrl) 26 27from qutebrowser.mainwindow.statusbar import textbase 28from qutebrowser.config import stylesheet 29from qutebrowser.utils import usertypes, urlutils 30 31 32class UrlType(enum.Enum): 33 34 """The type/color of the URL being shown. 35 36 Note this has entries for success/error/warn from widgets.webview:LoadStatus. 37 """ 38 39 success = enum.auto() 40 success_https = enum.auto() 41 error = enum.auto() 42 warn = enum.auto() 43 hover = enum.auto() 44 normal = enum.auto() 45 46 47class UrlText(textbase.TextBase): 48 49 """URL displayed in the statusbar. 50 51 Attributes: 52 _normal_url: The normal URL to be displayed as a UrlType instance. 53 _normal_url_type: The type of the normal URL as a UrlType instance. 54 _hover_url: The URL we're currently hovering over. 55 _ssl_errors: Whether SSL errors occurred while loading. 56 _urltype: The URL type to show currently (normal/ok/error/warn/hover). 57 Accessed via the urltype property. 58 """ 59 60 STYLESHEET = """ 61 QLabel#UrlText[urltype="normal"] { 62 color: {{ conf.colors.statusbar.url.fg }}; 63 } 64 65 QLabel#UrlText[urltype="success"] { 66 color: {{ conf.colors.statusbar.url.success.http.fg }}; 67 } 68 69 QLabel#UrlText[urltype="success_https"] { 70 color: {{ conf.colors.statusbar.url.success.https.fg }}; 71 } 72 73 QLabel#UrlText[urltype="error"] { 74 color: {{ conf.colors.statusbar.url.error.fg }}; 75 } 76 77 QLabel#UrlText[urltype="warn"] { 78 color: {{ conf.colors.statusbar.url.warn.fg }}; 79 } 80 81 QLabel#UrlText[urltype="hover"] { 82 color: {{ conf.colors.statusbar.url.hover.fg }}; 83 } 84 """ 85 86 def __init__(self, parent=None): 87 super().__init__(parent) 88 self._urltype = None 89 self.setObjectName(self.__class__.__name__) 90 stylesheet.set_register(self) 91 self._hover_url = None 92 self._normal_url = None 93 self._normal_url_type = UrlType.normal 94 95 @pyqtProperty(str) 96 def urltype(self): 97 """Getter for self.urltype, so it can be used as Qt property. 98 99 Return: 100 The urltype as a string (!) 101 """ 102 if self._urltype is None: 103 return "" 104 else: 105 return self._urltype.name 106 107 def _update_url(self): 108 """Update the displayed URL if the url or the hover url changed.""" 109 old_urltype = self._urltype 110 if self._hover_url is not None: 111 self.setText(self._hover_url) 112 self._urltype = UrlType.hover 113 elif self._normal_url is not None: 114 self.setText(self._normal_url) 115 self._urltype = self._normal_url_type 116 else: 117 self.setText('') 118 self._urltype = UrlType.normal 119 if old_urltype != self._urltype: 120 # We can avoid doing an unpolish here because the new style will 121 # always override the old one. 122 self.style().polish(self) 123 124 @pyqtSlot(usertypes.LoadStatus) 125 def on_load_status_changed(self, status): 126 """Slot for load_status_changed. Sets URL color accordingly. 127 128 Args: 129 status: The usertypes.LoadStatus. 130 """ 131 assert isinstance(status, usertypes.LoadStatus), status 132 if status in [usertypes.LoadStatus.success, 133 usertypes.LoadStatus.success_https, 134 usertypes.LoadStatus.error, 135 usertypes.LoadStatus.warn]: 136 self._normal_url_type = UrlType[status.name] 137 else: 138 self._normal_url_type = UrlType.normal 139 self._update_url() 140 141 @pyqtSlot(QUrl) 142 def set_url(self, url): 143 """Setter to be used as a Qt slot. 144 145 Args: 146 url: The URL to set as QUrl, or None. 147 """ 148 if url is None: 149 self._normal_url = None 150 elif not url.isValid(): 151 self._normal_url = "Invalid URL!" 152 else: 153 self._normal_url = urlutils.safe_display_string(url) 154 self._normal_url_type = UrlType.normal 155 self._update_url() 156 157 @pyqtSlot(str) 158 def set_hover_url(self, link): 159 """Setter to be used as a Qt slot. 160 161 Saves old shown URL in self._old_url and restores it later if a link is 162 "un-hovered" when it gets called with empty parameters. 163 164 Args: 165 link: The link which was hovered (string) 166 """ 167 if link: 168 qurl = QUrl(link) 169 if qurl.isValid(): 170 self._hover_url = urlutils.safe_display_string(qurl) 171 else: 172 self._hover_url = '(invalid URL!) {}'.format(link) 173 else: 174 self._hover_url = None 175 self._update_url() 176 177 def on_tab_changed(self, tab): 178 """Update URL if the tab changed.""" 179 self._hover_url = None 180 if tab.url().isValid(): 181 self._normal_url = urlutils.safe_display_string(tab.url()) 182 else: 183 self._normal_url = '' 184 self.on_load_status_changed(tab.load_status()) 185 self._update_url() 186