Move config.style into config.config and refactor it

This commit is contained in:
Florian Bruhin 2017-07-02 16:05:04 +02:00
parent 81d6406e14
commit 28670f8e48
17 changed files with 153 additions and 161 deletions

View File

@ -44,7 +44,7 @@ import qutebrowser
import qutebrowser.resources import qutebrowser.resources
from qutebrowser.completion.models import instances as completionmodels from qutebrowser.completion.models import instances as completionmodels
from qutebrowser.commands import cmdutils, runners, cmdexc from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import style, config, websettings, configexc from qutebrowser.config import config, websettings, configexc
from qutebrowser.browser import (urlmarks, adblock, history, browsertab, from qutebrowser.browser import (urlmarks, adblock, history, browsertab,
downloads) downloads)
from qutebrowser.browser.network import proxy from qutebrowser.browser.network import proxy

View File

@ -26,7 +26,7 @@ from PyQt5.QtCore import pyqtSlot, QSize, Qt, QTimer
from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu, QStyleFactory from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu, QStyleFactory
from qutebrowser.browser import downloads from qutebrowser.browser import downloads
from qutebrowser.config import style from qutebrowser.config import config
from qutebrowser.utils import qtutils, utils, objreg from qutebrowser.utils import qtutils, utils, objreg
@ -76,7 +76,7 @@ class DownloadView(QListView):
def __init__(self, win_id, parent=None): def __init__(self, win_id, parent=None):
super().__init__(parent) super().__init__(parent)
self.setStyle(QStyleFactory.create('Fusion')) self.setStyle(QStyleFactory.create('Fusion'))
style.set_register_stylesheet(self) config.set_register_stylesheet(self)
self.setResizeMode(QListView.Adjust) self.setResizeMode(QListView.Adjust)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)

View File

@ -29,7 +29,7 @@ from string import ascii_lowercase
from PyQt5.QtCore import pyqtSlot, QObject, Qt, QUrl from PyQt5.QtCore import pyqtSlot, QObject, Qt, QUrl
from PyQt5.QtWidgets import QLabel from PyQt5.QtWidgets import QLabel
from qutebrowser.config import config, style from qutebrowser.config import config
from qutebrowser.keyinput import modeman, modeparsers from qutebrowser.keyinput import modeman, modeparsers
from qutebrowser.browser import webelem from qutebrowser.browser import webelem
from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners
@ -80,7 +80,7 @@ class HintLabel(QLabel):
self.elem = elem self.elem = elem
self.setAttribute(Qt.WA_StyledBackground, True) self.setAttribute(Qt.WA_StyledBackground, True)
style.set_register_stylesheet(self) config.set_register_stylesheet(self)
self._context.tab.contents_size_changed.connect(self._move_to_elem) self._context.tab.contents_size_changed.connect(self._move_to_elem)
self._move_to_elem() self._move_to_elem()

View File

@ -30,8 +30,8 @@ from PyQt5.QtCore import QRectF, QSize, Qt
from PyQt5.QtGui import (QIcon, QPalette, QTextDocument, QTextOption, from PyQt5.QtGui import (QIcon, QPalette, QTextDocument, QTextOption,
QAbstractTextDocumentLayout) QAbstractTextDocumentLayout)
from qutebrowser.config import config, style from qutebrowser.config import config
from qutebrowser.utils import qtutils from qutebrowser.utils import qtutils, jinja
class CompletionItemDelegate(QStyledItemDelegate): class CompletionItemDelegate(QStyledItemDelegate):
@ -187,12 +187,15 @@ class CompletionItemDelegate(QStyledItemDelegate):
self._doc = QTextDocument(self) self._doc = QTextDocument(self)
self._doc.setDefaultFont(self._opt.font) self._doc.setDefaultFont(self._opt.font)
self._doc.setDefaultTextOption(text_option) self._doc.setDefaultTextOption(text_option)
self._doc.setDefaultStyleSheet(style.get_stylesheet(""" self._doc.setDocumentMargin(2)
stylesheet = """
.highlight { .highlight {
color: {{ conf.colors.completion.match.fg }}; color: {{ conf.colors.completion.match.fg }};
} }
""")) """
self._doc.setDocumentMargin(2) template = jinja.environment.from_string(stylesheet)
self._doc.setDefaultStyleSheet(template.render(conf=config.val))
if index.parent().isValid(): if index.parent().isValid():
pattern = index.model().pattern pattern = index.model().pattern

View File

@ -26,7 +26,7 @@ subclasses to provide completions.
from PyQt5.QtWidgets import QStyle, QTreeView, QSizePolicy, QStyleFactory from PyQt5.QtWidgets import QStyle, QTreeView, QSizePolicy, QStyleFactory
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel, QSize from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel, QSize
from qutebrowser.config import config, style from qutebrowser.config import config
from qutebrowser.completion import completiondelegate from qutebrowser.completion import completiondelegate
from qutebrowser.completion.models import base from qutebrowser.completion.models import base
from qutebrowser.utils import utils, usertypes from qutebrowser.utils import utils, usertypes
@ -118,7 +118,7 @@ class CompletionView(QTreeView):
self._delegate = completiondelegate.CompletionItemDelegate(self) self._delegate = completiondelegate.CompletionItemDelegate(self)
self.setItemDelegate(self._delegate) self.setItemDelegate(self._delegate)
self.setStyle(QStyleFactory.create('Fusion')) self.setStyle(QStyleFactory.create('Fusion'))
style.set_register_stylesheet(self) config.set_register_stylesheet(self)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.setHeaderHidden(True) self.setHeaderHidden(True)
self.setAlternatingRowColors(True) self.setAlternatingRowColors(True)

View File

@ -24,11 +24,12 @@ import os.path
import contextlib import contextlib
import functools import functools
from PyQt5.QtCore import pyqtSignal, QObject, QUrl import sip
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QUrl
from qutebrowser.config import configdata, configexc, configtypes, configfiles from qutebrowser.config import configdata, configexc, configtypes, configfiles
from qutebrowser.utils import (utils, objreg, message, standarddir, log, from qutebrowser.utils import (utils, objreg, message, standarddir, log,
usertypes) usertypes, jinja)
from qutebrowser.commands import cmdexc, cmdutils, runners from qutebrowser.commands import cmdexc, cmdutils, runners
@ -539,6 +540,67 @@ class ConfigContainer:
return attr return attr
def set_register_stylesheet(obj, *, stylesheet=None, update=True):
"""Set the stylesheet for an object based on it's STYLESHEET attribute.
Also, register an update when the config is changed.
Args:
obj: The object to set the stylesheet for and register.
Must have a STYLESHEET attribute if stylesheet is not given.
stylesheet: The stylesheet to use.
update: Whether to update the stylesheet on config changes.
"""
observer = StyleSheetObserver(obj, stylesheet=stylesheet)
observer.register(update=update)
class StyleSheetObserver(QObject):
"""Set the stylesheet on the given object and update it on changes.
Attributes:
_obj: The object to observe.
_stylesheet: The stylesheet template to use.
"""
def __init__(self, obj, stylesheet):
super().__init__(parent=obj)
self._obj = obj
if stylesheet is None:
self._stylesheet = obj.STYLESHEET
else:
self._stylesheet = stylesheet
def _get_stylesheet(self):
"""Format a stylesheet based on a template.
Return:
The formatted template as string.
"""
template = jinja.environment.from_string(self._stylesheet)
return template.render(conf=val)
@pyqtSlot()
def _update_stylesheet(self):
"""Update the stylesheet for obj."""
if not sip.isdeleted(self._obj):
self._obj.setStyleSheet(self._get_stylesheet())
def register(self, update):
"""Do a first update and listen for more.
Args:
update: if False, don't listen for future updates.
"""
qss = self._get_stylesheet()
log.config.vdebug("stylesheet for {}: {}".format(
self._obj.__class__.__name__, qss))
self._obj.setStyleSheet(qss)
if update:
instance.changed.connect(self._update_stylesheet)
def init(parent=None): def init(parent=None):
"""Initialize the config. """Initialize the config.

View File

@ -1,62 +0,0 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 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 the look&feel of qutebrowser."""
import functools
import sip
from qutebrowser.config import config
from qutebrowser.utils import log, jinja
def get_stylesheet(template_str):
"""Format a stylesheet based on a template.
Args:
template_str: The stylesheet template as string.
Return:
The formatted template as string.
"""
template = jinja.environment.from_string(template_str)
return template.render(conf=config.val)
def set_register_stylesheet(obj):
"""Set the stylesheet for an object based on it's STYLESHEET attribute.
Also, register an update when the config is changed.
Args:
obj: The object to set the stylesheet for and register.
Must have a STYLESHEET attribute.
"""
qss = get_stylesheet(obj.STYLESHEET)
log.config.vdebug("stylesheet for {}: {}".format(
obj.__class__.__name__, qss))
obj.setStyleSheet(qss)
config.instance.changed.connect(functools.partial(_update_stylesheet, obj))
def _update_stylesheet(obj):
"""Update the stylesheet for obj."""
if not sip.isdeleted(obj):
obj.setStyleSheet(get_stylesheet(obj.STYLESHEET))

View File

@ -23,7 +23,7 @@
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QTimer, Qt, QSize from PyQt5.QtCore import pyqtSlot, pyqtSignal, QTimer, Qt, QSize
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QSizePolicy from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QSizePolicy
from qutebrowser.config import config, style from qutebrowser.config import config
from qutebrowser.utils import usertypes from qutebrowser.utils import usertypes
@ -65,7 +65,7 @@ class Message(QLabel):
raise ValueError("Invalid level {!r}".format(level)) raise ValueError("Invalid level {!r}".format(level))
# We don't bother with set_register_stylesheet here as it's short-lived # We don't bother with set_register_stylesheet here as it's short-lived
# anyways. # anyways.
self.setStyleSheet(style.get_stylesheet(stylesheet)) config.set_register_stylesheet(self, stylesheet=stylesheet, update=False)
class MessageView(QWidget): class MessageView(QWidget):

View File

@ -30,7 +30,7 @@ from PyQt5.QtWidgets import (QWidget, QGridLayout, QVBoxLayout, QLineEdit,
QLabel, QFileSystemModel, QTreeView, QSizePolicy) QLabel, QFileSystemModel, QTreeView, QSizePolicy)
from qutebrowser.browser import downloads from qutebrowser.browser import downloads
from qutebrowser.config import style, config from qutebrowser.config import config
from qutebrowser.utils import usertypes, log, utils, qtutils, objreg, message from qutebrowser.utils import usertypes, log, utils, qtutils, objreg, message
from qutebrowser.keyinput import modeman from qutebrowser.keyinput import modeman
from qutebrowser.commands import cmdutils, cmdexc from qutebrowser.commands import cmdutils, cmdexc
@ -268,7 +268,7 @@ class PromptContainer(QWidget):
self.setObjectName('PromptContainer') self.setObjectName('PromptContainer')
self.setAttribute(Qt.WA_StyledBackground, True) self.setAttribute(Qt.WA_StyledBackground, True)
style.set_register_stylesheet(self) config.set_register_stylesheet(self)
message.global_bridge.prompt_done.connect(self._on_prompt_done) message.global_bridge.prompt_done.connect(self._on_prompt_done)
prompt_queue.show_prompts.connect(self._on_show_prompts) prompt_queue.show_prompts.connect(self._on_show_prompts)

View File

@ -23,7 +23,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt, QSize, QTimer
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy
from qutebrowser.browser import browsertab from qutebrowser.browser import browsertab
from qutebrowser.config import config, style from qutebrowser.config import config
from qutebrowser.utils import usertypes, log, objreg, utils from qutebrowser.utils import usertypes, log, objreg, utils
from qutebrowser.mainwindow.statusbar import (command, progress, keystring, from qutebrowser.mainwindow.statusbar import (command, progress, keystring,
percentage, url, tabindex) percentage, url, tabindex)
@ -147,7 +147,7 @@ class StatusBar(QWidget):
objreg.register('statusbar', self, scope='window', window=win_id) objreg.register('statusbar', self, scope='window', window=win_id)
self.setObjectName(self.__class__.__name__) self.setObjectName(self.__class__.__name__)
self.setAttribute(Qt.WA_StyledBackground) self.setAttribute(Qt.WA_StyledBackground)
style.set_register_stylesheet(self) config.set_register_stylesheet(self)
self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
@ -259,7 +259,7 @@ class StatusBar(QWidget):
self._color_flags.caret = ColorFlags.CaretMode.on self._color_flags.caret = ColorFlags.CaretMode.on
else: else:
self._color_flags.caret = ColorFlags.CaretMode.off self._color_flags.caret = ColorFlags.CaretMode.off
self.setStyleSheet(style.get_stylesheet(self.STYLESHEET)) config.set_register_stylesheet(self, update=False)
def _set_mode_text(self, mode): def _set_mode_text(self, mode):
"""Set the mode text.""" """Set the mode text."""

View File

@ -22,7 +22,7 @@
from PyQt5.QtCore import pyqtSlot, QSize from PyQt5.QtCore import pyqtSlot, QSize
from PyQt5.QtWidgets import QProgressBar, QSizePolicy from PyQt5.QtWidgets import QProgressBar, QSizePolicy
from qutebrowser.config import style from qutebrowser.config import config
from qutebrowser.utils import utils, usertypes from qutebrowser.utils import utils, usertypes
@ -45,7 +45,7 @@ class Progress(QProgressBar):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
style.set_register_stylesheet(self) config.set_register_stylesheet(self)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.setTextVisible(False) self.setTextVisible(False)
self.hide() self.hide()

View File

@ -22,7 +22,7 @@
from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt, QUrl from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt, QUrl
from qutebrowser.mainwindow.statusbar import textbase from qutebrowser.mainwindow.statusbar import textbase
from qutebrowser.config import style from qutebrowser.config import config
from qutebrowser.utils import usertypes, urlutils from qutebrowser.utils import usertypes, urlutils
@ -81,7 +81,7 @@ class UrlText(textbase.TextBase):
"""Override TextBase.__init__ to elide in the middle by default.""" """Override TextBase.__init__ to elide in the middle by default."""
super().__init__(parent, Qt.ElideMiddle) super().__init__(parent, Qt.ElideMiddle)
self.setObjectName(self.__class__.__name__) self.setObjectName(self.__class__.__name__)
style.set_register_stylesheet(self) config.set_register_stylesheet(self)
self._hover_url = None self._hover_url = None
self._normal_url = None self._normal_url = None
self._normal_url_type = UrlType.normal self._normal_url_type = UrlType.normal
@ -109,7 +109,7 @@ class UrlText(textbase.TextBase):
else: else:
self.setText('') self.setText('')
self._urltype = UrlType.normal self._urltype = UrlType.normal
self.setStyleSheet(style.get_stylesheet(self.STYLESHEET)) config.set_register_stylesheet(self, update=False)
@pyqtSlot(str) @pyqtSlot(str)
def on_load_status_changed(self, status_str): def on_load_status_changed(self, status_str):

View File

@ -30,7 +30,7 @@ import fnmatch
from PyQt5.QtWidgets import QLabel, QSizePolicy from PyQt5.QtWidgets import QLabel, QSizePolicy
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt
from qutebrowser.config import config, style from qutebrowser.config import config
from qutebrowser.utils import objreg, utils, usertypes from qutebrowser.utils import objreg, utils, usertypes
@ -68,7 +68,7 @@ class KeyHintView(QLabel):
self.hide() self.hide()
self._show_timer = usertypes.Timer(self, 'keyhint_show') self._show_timer = usertypes.Timer(self, 'keyhint_show')
self._show_timer.timeout.connect(self.show) self._show_timer.timeout.connect(self.show)
style.set_register_stylesheet(self) config.set_register_stylesheet(self)
def __repr__(self): def __repr__(self):
return utils.get_repr(self, win_id=self._win_id) return utils.get_repr(self, win_id=self._win_id)

View File

@ -37,7 +37,7 @@ from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
from qutebrowser.browser import qutescheme from qutebrowser.browser import qutescheme
from qutebrowser.utils import log, objreg, usertypes, message, debug, utils from qutebrowser.utils import log, objreg, usertypes, message, debug, utils
from qutebrowser.commands import cmdutils, runners, cmdexc from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import style, configdata from qutebrowser.config import configdata
from qutebrowser.misc import consolewidget from qutebrowser.misc import consolewidget

View File

@ -444,9 +444,9 @@ class ConfigStub(QObject):
"""Set a value in the config.""" """Set a value in the config."""
try: try:
self.data[name] = value self.data[name] = value
self.changed.emit(name)
except KeyError: except KeyError:
raise configexc.NoOptionError(name) raise configexc.NoOptionError(name)
self.changed.emit(name)
class UrlMarkManagerStub(QObject): class UrlMarkManagerStub(QObject):

View File

@ -18,4 +18,62 @@
"""Tests for qutebrowser.config.config.""" """Tests for qutebrowser.config.config."""
import pytest
from PyQt5.QtCore import QObject
from qutebrowser.config import config from qutebrowser.config import config
class Obj(QObject):
def __init__(self, stylesheet=None, parent=None):
super().__init__(parent)
if stylesheet is not None:
self.STYLESHEET = stylesheet # pylint: disable=invalid-name
self.rendered_stylesheet = None
def setStyleSheet(self, stylesheet):
self.rendered_stylesheet = stylesheet
def test_get_stylesheet(config_stub):
config_stub.val.colors.completion.bg = 'magenta'
observer = config.StyleSheetObserver(
Obj(), stylesheet="{{ conf.colors.completion.bg }}")
assert observer._get_stylesheet() == 'magenta'
@pytest.mark.parametrize('delete', [True, False])
@pytest.mark.parametrize('stylesheet_param', [True, False])
@pytest.mark.parametrize('update', [True, False])
def test_set_register_stylesheet(delete, stylesheet_param, update, qtbot,
config_stub, caplog):
config_stub.val.colors.completion.fg = 'magenta'
stylesheet = "{{ conf.colors.completion.fg }}"
with caplog.at_level(9): # VDEBUG
if stylesheet_param:
obj = Obj()
config.set_register_stylesheet(obj, stylesheet=stylesheet,
update=update)
else:
obj = Obj(stylesheet)
config.set_register_stylesheet(obj, update=update)
assert len(caplog.records) == 1
assert caplog.records[0].message == 'stylesheet for Obj: magenta'
assert obj.rendered_stylesheet == 'magenta'
if delete:
with qtbot.waitSignal(obj.destroyed):
obj.deleteLater()
config_stub.val.colors.completion.fg = 'yellow'
if delete or not update:
expected = 'magenta'
else:
expected = 'yellow'
assert obj.rendered_stylesheet == expected

View File

@ -1,69 +0,0 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 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/>.
"""Tests for qutebrowser.config.style."""
import logging
import pytest
from PyQt5.QtCore import QObject
from qutebrowser.config import style
def test_get_stylesheet(config_stub):
config_stub.val.colors.completion.bg = 'magenta'
rendered = style.get_stylesheet("{{ conf.colors.completion.bg }}")
assert rendered == 'magenta'
class Obj(QObject):
def __init__(self, stylesheet, parent=None):
super().__init__(parent)
self.STYLESHEET = stylesheet # pylint: disable=invalid-name
self.rendered_stylesheet = None
def setStyleSheet(self, stylesheet):
self.rendered_stylesheet = stylesheet
@pytest.mark.parametrize('delete', [True, False])
def test_set_register_stylesheet(delete, qtbot, config_stub, caplog):
config_stub.val.colors.completion.fg = 'magenta'
obj = Obj("{{ conf.colors.completion.fg }}")
with caplog.at_level(9): # VDEBUG
style.set_register_stylesheet(obj)
assert len(caplog.records) == 1
assert caplog.records[0].message == 'stylesheet for Obj: magenta'
assert obj.rendered_stylesheet == 'magenta'
if delete:
with qtbot.waitSignal(obj.destroyed):
obj.deleteLater()
config_stub.val.colors.completion.fg = 'yellow'
if delete:
expected = 'magenta'
else:
expected = 'yellow'
assert obj.rendered_stylesheet == expected