Merge branch 'ninja'

This commit is contained in:
Florian Bruhin 2014-08-29 07:33:43 +02:00
commit d059c468af
26 changed files with 359 additions and 321 deletions

3
.gitignore vendored
View File

@ -13,4 +13,5 @@ __pycache__
.ropeproject
# We can probably remove these later
*.asciidoc
*.html
/doc/*.html
/README.html

View File

@ -74,6 +74,7 @@ The following software and libraries are required to run qutebrowser:
(5.3.1 recommended) for Python 3
* https://pypi.python.org/pypi/setuptools/[pkg_resources/setuptools]
* http://fdik.org/pyPEG/[pyPEG2]
* http://jinja.pocoo.org/[jinja2]
The following libraries are optional and provide colored logging in the
console:
@ -85,7 +86,8 @@ On Debian
~~~~~~~~~
----
# apt-get install python3-pyqt5 python3-pyqt5.qtwebkit python3-pkg-resources python3-pip
# apt-get install python3-pyqt5 python3-pyqt5.qtwebkit python3-pkg-resources
python3-pip python3-jinja2
# pip3 install pypeg2 --allow-external pypeg2 --allow-unverified pypeg2
----
@ -129,6 +131,7 @@ to get Qt and PyQt5.
* Get pip as described http://stackoverflow.com/a/12476379[on Stack Overflow].
* Run +pip install --allow-external pypeg2 --allow-unverified pypeg2 pypeg2+ to
install pypeg2.
* Run +pip install jinja2+ to install jinja2.
As soon as v0.1 is out, a standalone .exe (built with
http://cx-freeze.sourceforge.net/[cx_Freeze]) will be provided. In the

View File

@ -9,7 +9,7 @@ arch=(any)
url="http://www.qutebrowser.org/"
license=('GPL')
depends=('python>=3.4' 'python-setuptools' 'python-pyqt5>=5.2' 'qt5-base>=5.2'
'qt5-webkit>=5.2' 'libxkbcommon-x11' 'python-pypeg2')
'qt5-webkit>=5.2' 'libxkbcommon-x11' 'python-pypeg2' 'python-jinja')
makedepends=('python' 'python-setuptools')
optdepends=('python-colorlog: colored logging output')
options=(!emptydirs)

View File

@ -394,7 +394,7 @@ class Application(QApplication):
status.prompt.prompter.ask_question, Qt.DirectConnection)
# config
self.config.style_changed.connect(style.invalidate_caches)
self.config.style_changed.connect(style.get_stylesheet.cache_clear)
for obj in (tabs, completion, self.mainwindow, self.cmd_history,
websettings, kp[utypes.KeyMode.normal], self.modeman,
status, status.txt):

View File

@ -19,10 +19,10 @@
"""The main browser widgets."""
from functools import partial
import functools
import sip
from PyQt5.QtCore import pyqtSignal, pyqtSlot, PYQT_VERSION, Qt, QTimer
from PyQt5.QtCore import pyqtSignal, pyqtSlot, PYQT_VERSION, Qt
from PyQt5.QtNetwork import QNetworkReply
from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtPrintSupport import QPrintDialog
@ -30,7 +30,7 @@ from PyQt5.QtWebKitWidgets import QWebPage
from qutebrowser.config import config
from qutebrowser.network import networkmanager
from qutebrowser.utils import message, usertypes, log, http, utils, qtutils
from qutebrowser.utils import message, usertypes, log, http, jinja, qtutils
class BrowserPage(QWebPage):
@ -118,7 +118,8 @@ class BrowserPage(QWebPage):
log.webview.debug("Error domain: {}, error code: {}".format(
info.domain, info.error))
title = "Error loading page: {}".format(urlstr)
errpage.content = utils.read_file('html/error.html').format(
template = jinja.env.get_template('error.html')
errpage.content = template.render( # pylint: disable=maybe-no-member
title=title, url=urlstr, error=info.errorString, icon='')
return True
@ -197,8 +198,8 @@ class BrowserPage(QWebPage):
if reply.isFinished():
self.display_content(reply, 'image/jpeg')
else:
reply.finished.connect(
partial(self.display_content, reply, 'image/jpeg'))
reply.finished.connect(functools.partial(
self.display_content, reply, 'image/jpeg'))
else:
# Unknown mimetype, so download anyways.
self.start_download.emit(reply)
@ -240,19 +241,16 @@ class BrowserPage(QWebPage):
log.webview.warning("Extension {} not supported!".format(ext))
return super().extension(ext, opt, out)
return handler(opt, out)
except BaseException as e:
except: # pylint: disable=bare-except
# Due to a bug in PyQt, exceptions inside extension() get swallowed
# for some reason. Here we set up a single-shot QTimer to re-raise
# them when we're back in the mainloop.
# for some reason.
# http://www.riverbankcomputing.com/pipermail/pyqt/2014-August/034722.html
#
# Note we somehow can't re-raise with the correct traceback here.
# Using "raise from" or ".with_traceback()" just ignores the
# exception again.
exc = e # needed for the closure
def raise_():
raise exc
QTimer.singleShot(0, raise_)
# We used to re-raise the exception with a single-shot QTimer here,
# but that lead to a strange proble with a KeyError with some
# random jinja template stuff as content. For now, we only log it,
# so it doesn't pass 100% silently.
log.webview.exception("Error inside WebPage::extension")
return False
def javaScriptAlert(self, _frame, msg):

View File

@ -17,41 +17,32 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Utilities related to the look&feel of qutebrowser.
Module attributes:
_colordict: The global cached ColorDict.
_fontdict: The global cached FontDict.
"""
"""Utilities related to the look&feel of qutebrowser."""
import functools
import jinja2
from PyQt5.QtGui import QColor
from qutebrowser.config import config
from qutebrowser.utils import log, utils
_colordict = None
_fontdict = None
def get_stylesheet(template):
@functools.lru_cache(maxsize=16)
def get_stylesheet(template_str):
"""Format a stylesheet based on a template.
Args:
template: The stylesheet template as string.
template_str: The stylesheet template as string.
Return:
The formatted template as string.
"""
global _colordict, _fontdict
if _colordict is None:
_colordict = ColorDict(config.section('colors'))
if _fontdict is None:
_fontdict = FontDict(config.section('fonts'))
return template.strip().format(color=_colordict, font=_fontdict,
config=config.instance())
colordict = ColorDict(config.section('colors'))
fontdict = FontDict(config.section('fonts'))
template = jinja2.Template(template_str)
return template.render(color=colordict, font=fontdict,
config=config.instance())
def set_register_stylesheet(obj):
@ -78,15 +69,6 @@ def _update_stylesheet(obj, _section, _option):
obj.setStyleSheet(get_stylesheet(obj.STYLESHEET))
def invalidate_caches(section, _option):
"""Invalidate cached dicts."""
global _colordict, _fontdict
if section == 'colors':
_colordict = None
elif section == 'fonts':
_fontdict = None
class ColorDict(dict):
"""A dict aimed at Qt stylesheet colors."""
@ -123,20 +105,6 @@ class ColorDict(dict):
else:
return val
def getraw(self, key):
"""Get a value without the transformations done in __getitem__.
Args:
key: The key to get from the dict.
Return:
A value, or None if the value wasn't found.
"""
try:
return super().__getitem__(key)
except KeyError:
return None
class FontDict(dict):
@ -160,17 +128,3 @@ class FontDict(dict):
return ''
else:
return 'font: {};'.format(val)
def getraw(self, key):
"""Get a value without the transformations done in __getitem__.
Args:
key: The key to get from the dict.
Return:
A value, or None if the value wasn't found.
"""
try:
return super().__getitem__(key)
except KeyError:
return None

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<!--
vim: ft=html fileencoding=utf-8 sts=4 sw=4 et:
-->
<html>
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
{% if icon %}
<link rel='icon' type='image/png' href="{{ icon }}">
{% endif %}
<style type="text/css">
{% block style %}
body {
background-color: #fff;
margin: 0;
padding: 0;
}
{% endblock %}
</style>
<script type="text/javascript">
{% block script %}
{% endblock %}
</script>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>

View File

@ -1,67 +1,53 @@
<!DOCTYPE html>
<!--
vim: ft=html fileencoding=utf-8 sts=4 sw=4 et:
Based on html/error.html from dwb
-->
{% extends "base.html" %}
{% block style %}
{{ super() }}
#errorContainer {
background: #fff;
min-width: 35em;
max-width: 35em;
position: absolute;
top: 2em;
left: 1em;
padding: 10px;
border: 2px solid #eee;
-webkit-border-radius: 5px;
}
<html>
<head>
<meta charset="utf-8">
<title>{title}</title>
<!--<link rel='icon' type='image/png' href="{icon}">-->
<style type="text/css">
body {{
background-color: #fff;
margin: 0;
padding: 0;
}}
#errorTitleText {
font-size: 118%;
font-weight: bold;
}
#errorContainer {{
background: #fff;
min-width: 35em;
max-width: 35em;
position: absolute;
top: 2em;
left: 1em;
padding: 10px;
border: 2px solid #eee;
-webkit-border-radius: 5px;
}}
#errorMessageText {
font-size: 80%;
}
{% endblock %}
#errorTitleText {{
font-size: 118%;
font-weight: bold;
}}
{% block script %}
{{ super() }}
function tryagain()
{
location.reload();
}
function searchFor(uri) {
location.href = uri;
}
{% endblock %}
#errorMessageText {{
font-size: 80%;
}}
</style>
<script type="text/javascript">
function tryagain()
{{
location.reload();
}}
function searchFor(uri) {{
location.href = uri;
}}
</script>
</head>
<body>
<div id="errorContainer">
<div id="errorTitle">
<p id="errorTitleText">Unable to load page</p>
</div>
<div id="errorMessage">
<p>Problem occurred while loading the URL {url}</p>
<p id="errorMessageText">{error}</p>
</p>
</div>
{% block content %}
<div id="errorContainer">
<div id="errorTitle">
<p id="errorTitleText">Unable to load page</p>
</div>
<div id="errorMessage">
<p>Problem occurred while loading the URL {{ url }}</p>
<p id="errorMessageText">{{ error }}</p>
</p>
</div>
<form name="bl">
<input type="button" value="Try again" onclick="javascript:tryagain()" />
<!--<input type="button" value="Search" style="visibility:%s" onclick="javascript:searchFor('%s')" />-->
</form>
</div>
</body>
</html>
<form name="bl">
<input type="button" value="Try again" onclick="javascript:tryagain()" />
<!--<input type="button" value="Search" style="visibility:%s" onclick="javascript:searchFor('%s')" />-->
</form>
</div>
{% endblock %}

35
qutebrowser/html/log.html Normal file
View File

@ -0,0 +1,35 @@
{% extends "base.html" %}
{% block style %}
body {
background-color: black;
color: white;
font-size: 11px;
}
table {
border: 1px solid grey;
border-collapse: collapse;
}
pre {
margin: 2px;
}
th, td {
border: 1px solid grey;
padding-left: 5px;
padding-right: 5px;
}
{% endblock %}
{% block content %}
{{ super() }}
{% if content %}
<table>
{{ content | safe() }}
</table>
{% else %}
<p>Log output was disabled.</p>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block content %}
{{ super() }}
<pre>
{{ content }}
</pre>
{% endblock %}

View File

@ -0,0 +1,26 @@
{% extends "base.html" %}
{% block content %}
{{ super() }}
<h1>Version info</h1>
<pre>{{ version }}</pre>
<h1>Copyright info</h1>
<p>{{ copyright }}</p>
<p>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
</p>
<p>
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
</p>
<p>
You should have received a copy of the GNU General Public License
along with this program. If not, see <a href="http://www.gnu.org/licenses/">
http://www.gnu.org/licenses/</a> or open <a href="qute:gpl">qute:gpl</a>.
</p>
{% endblock %}

View File

@ -16,60 +16,28 @@
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
#
# pylint complains when using .render() on jinja templates, so we make it shut
# up for this whole module.
# pylint: disable=maybe-no-member
"""Handler functions for different qute:... pages.
Module attributes:
_HTML_TEMPLATE: The HTML boilerplate used to convert text into html.
pyeval_output: The output of the last :pyeval command.
"""
import html as pyhtml
from PyQt5.QtNetwork import QNetworkReply
import qutebrowser
from qutebrowser.network import schemehandler
from qutebrowser.utils import version, utils
from qutebrowser.utils import version, utils, jinja
from qutebrowser.utils import log as logutils
_HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{title}</title>
{head}
</head>
<body>
{body}
</body>
</html>
"""
pyeval_output = ":pyeval was never called"
def _get_html(title, snippet, head=None):
"""Add HTML boilerplate to a html snippet.
Args:
title: The title the page should have.
snippet: The html snippet.
head: Additional stuff to put in <head>
Return:
HTML content as bytes.
"""
if head is None:
head = ""
html = _HTML_TEMPLATE.format(title=title, body=snippet, head=head).encode(
'UTF-8', errors='xmlcharrefreplace')
return html
class QuteSchemeHandler(schemehandler.SchemeHandler):
"""Scheme handler for qute: URLs."""
@ -110,61 +78,39 @@ class QuteHandlers:
@classmethod
def pyeval(cls):
"""Handler for qute:pyeval. Return HTML content as bytes."""
text = pyhtml.escape(pyeval_output)
return _get_html('pyeval', '<pre>{}</pre>'.format(text))
html = jinja.env.get_template('pre.html').render(
title='pyeval', content=pyeval_output)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@classmethod
def version(cls):
"""Handler for qute:version. Return HTML content as bytes."""
text = pyhtml.escape(version.version())
html = '<h1>Version info</h1>'
html += '<p>{}</p>'.format(text.replace('\n', '<br/>'))
html += '<h1>Copyright info</h1>'
html += '<p>{}</p>'.format(qutebrowser.__copyright__)
html += version.GPL_BOILERPLATE_HTML
return _get_html('Version', html)
html = jinja.env.get_template('version.html').render(
title='Version info', version=version.version(),
copyright=qutebrowser.__copyright__)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@classmethod
def plainlog(cls):
"""Handler for qute:log. Return HTML content as bytes."""
"""Handler for qute:plainlog. Return HTML content as bytes."""
if logutils.ram_handler is None:
text = "Log output was disabled."
else:
text = pyhtml.escape(logutils.ram_handler.dump_log())
return _get_html('log', '<pre>{}</pre>'.format(text))
text = logutils.ram_handler.dump_log()
html = jinja.env.get_template('pre.html').render(
title='log', content=text)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@classmethod
def log(cls):
"""Handler for qute:log. Return HTML content as bytes."""
style = """
<style type="text/css">
body {
background-color: black;
color: white;
font-size: 11px;
}
table {
border: 1px solid grey;
border-collapse: collapse;
}
pre {
margin: 2px;
}
th, td {
border: 1px solid grey;
padding-left: 5px;
padding-right: 5px;
}
</style>
"""
if logutils.ram_handler is None:
html = "<p>Log output was disabled.</p>"
html_log = None
else:
html = logutils.ram_handler.dump_log(html=True)
return _get_html('log', html, head=style)
html_log = logutils.ram_handler.dump_log(html=True)
html = jinja.env.get_template('log.html').render(
title='log', content=html_log)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@classmethod
def gpl(cls):

View File

@ -112,6 +112,7 @@ def main():
earlyinit.check_pyqt_webkit()
earlyinit.check_pkg_resources()
earlyinit.check_pypeg2()
earlyinit.check_jinja2()
# We do this import late as we need to fix harfbuzz first.
from qutebrowser import app
from qutebrowser.utils import debug

View File

@ -29,7 +29,7 @@ from PyQt5.QtCore import pyqtRemoveInputHook, QEvent, QCoreApplication
from qutebrowser.utils import log, utils
from qutebrowser.commands import cmdutils
from qutebrowser.config import config
from qutebrowser.config import config, style
@cmdutils.register(debug=True, name='debug-set-trace')
@ -87,9 +87,11 @@ def debug_all_objects():
@cmdutils.register(debug=True)
def debug_cache_stats():
"""Print config LRU cache stats."""
info = config.instance().get.cache_info()
log.misc.debug(info)
"""Print LRU cache stats."""
config_info = config.instance().get.cache_info()
style_info = style.get_stylesheet.cache_info()
log.misc.debug('config: {}'.format(config_info))
log.misc.debug('style: {}'.format(style_info))
def log_events(klass):

View File

@ -248,3 +248,17 @@ def check_pypeg2():
pip="pypeg2 --allow-external pypeg2 "
"--allow-unverified pypeg2")
_die(text)
def check_jinja2():
"""Check if jinja2 is installed."""
try:
import jinja2 # pylint: disable=unused-variable
except ImportError:
text = _missing_str("jinja2",
debian="apt-get install python3-jinja2",
arch="Install python-jinja from the AUR",
windows="Install from http://www.lfd.uci.edu/"
"~gohlke/pythonlibs/#jinja2 or via pip.",
pip="jinja2")
_die(text)

View File

@ -0,0 +1,58 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Utilities related to jinja2. """
import os.path
import jinja2
from qutebrowser.utils import utils
class Loader(jinja2.BaseLoader):
"""Jinja loader which uses utils.read_file to load templates."""
def __init__(self, subdir):
self.subdir = subdir
def get_source(self, _env, template):
path = os.path.join(self.subdir, template)
try:
source = utils.read_file(path)
except FileNotFoundError:
raise jinja2.TemplateNotFound(template)
# Currently we don't implement auto-reloading, so we always return True
# for up-to-date.
return source, path, lambda: True
def _guess_autoescape(template_name):
"""Turns autoescape on/off based on the filetype.
Based on http://jinja.pocoo.org/docs/dev/api/#autoescaping
"""
if template_name is None or '.' not in template_name:
return False
ext = template_name.rsplit('.', 1)[1]
return ext in ('html', 'htm', 'xml')
env = jinja2.Environment(loader=Loader('html'), autoescape=_guess_autoescape)

View File

@ -341,13 +341,12 @@ class RAMHandler(logging.Handler):
self.data.append(record)
def dump_log(self, html=False):
"""Dump the complete formatted log data as as string."""
if html:
fmt = self.html_formatter.format
lines = ['<table>']
else:
fmt = self.format
lines = []
"""Dump the complete formatted log data as as string.
FIXME: We should do all the HTML formatter via jinja2.
"""
lines = []
fmt = self.html_formatter.format if html else self.format
self.acquire()
try:
records = list(self.data)
@ -355,8 +354,6 @@ class RAMHandler(logging.Handler):
self.release()
for record in records:
lines.append(fmt(record))
if html:
lines.append('</table>')
return '\n'.join(lines)

View File

@ -48,25 +48,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/> or use
:open qute:gpl.
"""
GPL_BOILERPLATE_HTML = """
<p>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
</p>
<p>
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
</p>
<p>
You should have received a copy of the GNU General Public License
along with this program. If not, see <a href="http://www.gnu.org/licenses/">
http://www.gnu.org/licenses/</a> or open <a href="qute:gpl">qute:gpl</a>.
"""
def _git_str():
"""Try to find out git version.
@ -179,6 +160,13 @@ def _module_versions():
else:
ver = getattr(pypeg2, '__version__', 'yes')
lines.append('pypeg2: {}'.format(ver))
try:
import jinja2
except ImportError:
pass
else:
ver = getattr(jinja2, '__version__', 'yes')
lines.append('jinja2: {}'.format(ver))
return lines

View File

@ -42,7 +42,6 @@ class CompletionView(QTreeView):
Highlights completions based on marks in the Role.marks data.
Class attributes:
STYLESHEET: The stylesheet template for the CompletionView.
COLUMN_WIDTHS: A list of column widths, in percent.
Attributes:
@ -59,29 +58,31 @@ class CompletionView(QTreeView):
# Drawing the item foreground will be done by CompletionItemDelegate, so we
# don't define that in this stylesheet.
STYLESHEET = """
QTreeView {{
{font[completion]}
{color[completion.bg]}
QTreeView {
{{ font['completion'] }}
{{ color['completion.bg'] }}
outline: 0;
}}
}
QTreeView::item:disabled {{
{color[completion.category.bg]}
border-top: 1px solid {color[completion.category.border.top]};
QTreeView::item:disabled {
{{ color['completion.category.bg'] }}
border-top: 1px solid
{{ color['completion.category.border.top'] }};
border-bottom: 1px solid
{color[completion.category.border.bottom]};
}}
{{ color['completion.category.border.bottom'] }};
}
QTreeView::item:selected, QTreeView::item:selected:hover {{
border-top: 1px solid {color[completion.item.selected.border.top]};
QTreeView::item:selected, QTreeView::item:selected:hover {
border-top: 1px solid
{{ color['completion.item.selected.border.top'] }};
border-bottom: 1px solid
{color[completion.item.selected.border.bottom]};
{color[completion.item.selected.bg]}
}}
{{ color['completion.item.selected.border.bottom'] }};
{{ color['completion.item.selected.bg'] }}
}
QTreeView:item::hover {{
QTreeView:item::hover {
border: 0px;
}}
}
"""
COLUMN_WIDTHS = (20, 70, 10)

View File

@ -189,9 +189,9 @@ class CompletionItemDelegate(QStyledItemDelegate):
self._doc.setDefaultFont(self._opt.font)
self._doc.setDefaultTextOption(text_option)
self._doc.setDefaultStyleSheet(style.get_stylesheet("""
.highlight {{
{color[completion.match.fg]}
}}
.highlight {
{{ color['completion.match.fg'] }}
}
"""))
self._doc.setDocumentMargin(2)

View File

@ -37,14 +37,14 @@ class DownloadView(QListView):
"""
STYLESHEET = """
QListView {{
{color[downloads.bg.bar]}
{font[downloads]}
}}
QListView {
{{ color['downloads.bg.bar'] }}
{{ font['downloads'] }}
}
QListView::item {{
QListView::item {
padding-right: 2px;
}}
}
"""
def __init__(self, parent=None):

View File

@ -40,9 +40,6 @@ class StatusBar(QWidget):
"""The statusbar at the bottom of the mainwindow.
Class attributes:
STYLESHEET: The stylesheet template.
Attributes:
cmd: The Command widget in the statusbar.
txt: The Text widget in the statusbar.
@ -96,26 +93,26 @@ class StatusBar(QWidget):
_insert_active = False
STYLESHEET = """
QWidget#StatusBar {{
{color[statusbar.bg]}
}}
QWidget#StatusBar {
{{ color['statusbar.bg'] }}
}
QWidget#StatusBar[insert_active="true"] {{
{color[statusbar.bg.insert]}
}}
QWidget#StatusBar[insert_active="true"] {
{{ color['statusbar.bg.insert'] }}
}
QWidget#StatusBar[prompt_active="true"] {{
{color[statusbar.bg.prompt]}
}}
QWidget#StatusBar[prompt_active="true"] {
{{ color['statusbar.bg.prompt'] }}
}
QWidget#StatusBar[error="true"] {{
{color[statusbar.bg.error]}
}}
QWidget#StatusBar[error="true"] {
{{ color['statusbar.bg.error'] }}
}
QWidget {{
{color[statusbar.fg]}
{font[statusbar]}
}}
QWidget {
{{ color['statusbar.fg'] }}
{{ font['statusbar'] }}
}
"""
def __init__(self, parent=None):

View File

@ -28,24 +28,20 @@ from qutebrowser.config import style
class Progress(QProgressBar):
"""The progress bar part of the status bar.
Class attributes:
STYLESHEET: The stylesheet template.
"""
"""The progress bar part of the status bar."""
# FIXME for some reason, margin-left is not shown
STYLESHEET = """
QProgressBar {{
QProgressBar {
border-radius: 0px;
border: 2px solid transparent;
margin-left: 1px;
background-color: transparent;
}}
}
QProgressBar::chunk {{
{color[statusbar.progress.bg]}
}}
QProgressBar::chunk {
{{ color['statusbar.progress.bg'] }}
}
"""
def __init__(self, parent=None):

View File

@ -36,9 +36,6 @@ class UrlText(textbase.TextBase):
"""URL displayed in the statusbar.
Class attributes:
STYLESHEET: The stylesheet template.
Attributes:
normal_url: The normal URL to be displayed as a UrlType instance.
normal_url_type: The type of the normal URL as a UrlType instance.
@ -56,25 +53,25 @@ class UrlText(textbase.TextBase):
_urltype = None
STYLESHEET = """
QLabel#UrlText[urltype="normal"] {{
{color[statusbar.url.fg]}
}}
QLabel#UrlText[urltype="normal"] {
{{ color['statusbar.url.fg'] }}
}
QLabel#UrlText[urltype="success"] {{
{color[statusbar.url.fg.success]}
}}
QLabel#UrlText[urltype="success"] {
{{ color['statusbar.url.fg.success'] }}
}
QLabel#UrlText[urltype="error"] {{
{color[statusbar.url.fg.error]}
}}
QLabel#UrlText[urltype="error"] {
{{ color['statusbar.url.fg.error'] }}
}
QLabel#UrlText[urltype="warn"] {{
{color[statusbar.url.fg.warn]}
}}
QLabel#UrlText[urltype="warn"] {
{{ color['statusbar.url.fg.warn'] }}
}
QLabel#UrlText[urltype="hover"] {{
{color[statusbar.url.fg.hover]}
}}
QLabel#UrlText[urltype="hover"] {
{{ color['statusbar.url.fg.hover'] }}
}
"""
def __init__(self, parent=None):

View File

@ -98,7 +98,7 @@ setupdata = {
'description': _get_constant('description'),
'long_description': read_file('README.asciidoc'),
'url': 'http://www.qutebrowser.org/',
'requires': ['pypeg2'],
'requires': ['pypeg2', 'jinja2'],
'author': _get_constant('author'),
'author_email': _get_constant('email'),
'license': _get_constant('license'),

View File

@ -47,7 +47,7 @@ try:
['qutebrowser = qutebrowser.qutebrowser:main']},
test_suite='qutebrowser.test',
zip_safe=True,
install_requires=['pypeg2'],
install_requires=['pypeg2', 'jinja2'],
extras_require={'nice-debugging': ['colorlog', 'colorama'],
'checks': ['flake8', 'pylint', 'check-manifest',
'pyroma']},