Merge branch 'issue549-fix'

This commit is contained in:
Florian Bruhin 2015-03-16 18:03:00 +01:00
commit 4157cfe86f

View File

@ -22,176 +22,351 @@
Module attributes:
ATTRIBUTES: A mapping from internal setting names to QWebSetting enum
constants.
SETTERS: A mapping from setting names to QWebSetting setter method names.
settings: The global QWebSettings singleton instance.
"""
import os.path
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtCore import QUrl
from qutebrowser.config import config
from qutebrowser.utils import usertypes, standarddir, objreg, log
from qutebrowser.utils import standarddir, objreg, log, utils, debug
MapType = usertypes.enum('MapType', ['attribute', 'setter', 'static_setter'])
UNSET = object()
class Base:
"""Base class for QWebSetting wrappers.
Attributes:
_default: The default value of this setting.
"""
def __init__(self):
self._default = UNSET
def _get_qws(self, qws):
"""Get the QWebSettings object to use.
Args:
qws: The QWebSettings instance to use, or None to use the global
instance.
"""
if qws is None:
return QWebSettings.globalSettings()
else:
return qws
def save_default(self, qws=None):
"""Save the default value based on the currently set one.
This does nothing if no getter is configured for this setting.
Args:
qws: The QWebSettings instance to use, or None to use the global
instance.
Return:
The saved default value.
"""
try:
self._default = self.get(qws)
return self._default
except AttributeError:
return None
def restore_default(self, qws=None):
"""Restore the default value from the saved one.
This does nothing if the default has never been set.
Args:
qws: The QWebSettings instance to use, or None to use the global
instance.
"""
log.misc.vdebug("Restoring default {!r}.".format(self._default))
if self._default is not UNSET:
self._set(self._default, qws=qws)
def get(self, qws=None):
"""Get the value of this setting.
Must be overridden by subclasses.
Args:
qws: The QWebSettings instance to use, or None to use the global
instance.
"""
raise NotImplementedError
def set(self, value, qws=None):
"""Set the value of this setting.
Args:
value: The value to set.
qws: The QWebSettings instance to use, or None to use the global
instance.
"""
if value is None:
self.restore_default(qws)
else:
self._set(value, qws=qws)
def _set(self, value, qws):
"""Inner function to set the value of this setting.
Must be overridden by subclasses.
Args:
value: The value to set.
qws: The QWebSettings instance to use, or None to use the global
instance.
"""
raise NotImplementedError
class Attribute(Base):
"""A setting set via QWebSettings::setAttribute.
Attributes:
self._attribute: A QWebSettings::WebAttribute instance.
"""
def __init__(self, attribute):
super().__init__()
self._attribute = attribute
def __repr__(self):
return utils.get_repr(
self, attribute=debug.qenum_key(QWebSettings, self._attribute),
constructor=True)
def get(self, qws=None):
return self._get_qws(qws).attribute(self._attribute)
def _set(self, value, qws=None):
self._get_qws(qws).setAttribute(self._attribute, value)
class Setter(Base):
"""A setting set via QWebSettings getter/setter methods.
This will pass the QWebSettings instance ("self") as first argument to the
methods, so self._getter/self._setter are the *unbound* methods.
Attributes:
_getter: The unbound QWebSettings method to get this value, or None.
_setter: The unbound QWebSettings method to set this value.
_args: An iterable of the arguments to pass to the setter/getter
(before the value, for the setter).
_unpack: Whether to unpack args (True) or pass them directly (False).
"""
def __init__(self, getter, setter, args=(), unpack=False):
super().__init__()
self._getter = getter
self._setter = setter
self._args = args
self._unpack = unpack
def __repr__(self):
return utils.get_repr(self, getter=self._getter, setter=self._setter,
args=self._args, unpack=self._unpack,
constructor=True)
def get(self, qws=None):
if self._getter is None:
raise AttributeError("No getter set!")
return self._getter(self._get_qws(qws), *self._args)
def _set(self, value, qws=None):
args = [self._get_qws(qws)]
args.extend(self._args)
if self._unpack:
args.extend(value)
else:
args.append(value)
self._setter(*args)
class NullStringSetter(Setter):
"""A setter for settings requiring a null QString as default.
This overrides save_default so None is saved for an empty string. This is
needed for the CSS media type, because it returns an empty Python string
when getting the value, but setting it to the default requires passing None
(a null QString) instead of an empty string.
"""
def save_default(self, qws=None):
try:
val = self.get(qws)
except AttributeError:
return None
if val == '':
self._set(None, qws=qws)
else:
self._set(val, qws=qws)
return val
class GlobalSetter(Setter):
"""A setting set via static QWebSettings getter/setter methods.
self._getter/self._setter are the *bound* methods.
"""
def get(self, qws=None):
if qws is not None:
raise ValueError("qws may not be set with GlobalSetters!")
if self._getter is None:
raise AttributeError("No getter set!")
return self._getter(*self._args)
def _set(self, value, qws=None):
if qws is not None:
raise ValueError("qws may not be set with GlobalSetters!")
args = list(self._args)
if self._unpack:
args.extend(value)
else:
args.append(value)
self._setter(*args)
MAPPINGS = {
'content': {
'allow-images':
(MapType.attribute, QWebSettings.AutoLoadImages),
Attribute(QWebSettings.AutoLoadImages),
'allow-javascript':
(MapType.attribute, QWebSettings.JavascriptEnabled),
Attribute(QWebSettings.JavascriptEnabled),
'javascript-can-open-windows':
(MapType.attribute, QWebSettings.JavascriptCanOpenWindows),
Attribute(QWebSettings.JavascriptCanOpenWindows),
'javascript-can-close-windows':
(MapType.attribute, QWebSettings.JavascriptCanCloseWindows),
Attribute(QWebSettings.JavascriptCanCloseWindows),
'javascript-can-access-clipboard':
(MapType.attribute, QWebSettings.JavascriptCanAccessClipboard),
Attribute(QWebSettings.JavascriptCanAccessClipboard),
#'allow-java':
# (MapType.attribute, QWebSettings.JavaEnabled),
# Attribute(QWebSettings.JavaEnabled),
'allow-plugins':
(MapType.attribute, QWebSettings.PluginsEnabled),
Attribute(QWebSettings.PluginsEnabled),
'local-content-can-access-remote-urls':
(MapType.attribute, QWebSettings.LocalContentCanAccessRemoteUrls),
Attribute(QWebSettings.LocalContentCanAccessRemoteUrls),
'local-content-can-access-file-urls':
(MapType.attribute, QWebSettings.LocalContentCanAccessFileUrls),
Attribute(QWebSettings.LocalContentCanAccessFileUrls),
},
'network': {
'dns-prefetch':
(MapType.attribute, QWebSettings.DnsPrefetchEnabled),
Attribute(QWebSettings.DnsPrefetchEnabled),
},
'input': {
'spatial-navigation':
(MapType.attribute, QWebSettings.SpatialNavigationEnabled),
Attribute(QWebSettings.SpatialNavigationEnabled),
'links-included-in-focus-chain':
(MapType.attribute, QWebSettings.LinksIncludedInFocusChain),
Attribute(QWebSettings.LinksIncludedInFocusChain),
},
'fonts': {
'web-family-standard':
(MapType.setter, lambda qws, v:
qws.setFontFamily(QWebSettings.StandardFont, v),
""),
Setter(getter=QWebSettings.fontFamily,
setter=QWebSettings.setFontFamily,
args=[QWebSettings.StandardFont]),
'web-family-fixed':
(MapType.setter, lambda qws, v:
qws.setFontFamily(QWebSettings.FixedFont, v),
""),
Setter(getter=QWebSettings.fontFamily,
setter=QWebSettings.setFontFamily,
args=[QWebSettings.FixedFont]),
'web-family-serif':
(MapType.setter, lambda qws, v:
qws.setFontFamily(QWebSettings.SerifFont, v),
""),
Setter(getter=QWebSettings.fontFamily,
setter=QWebSettings.setFontFamily,
args=[QWebSettings.SerifFont]),
'web-family-sans-serif':
(MapType.setter, lambda qws, v:
qws.setFontFamily(QWebSettings.SansSerifFont, v),
""),
Setter(getter=QWebSettings.fontFamily,
setter=QWebSettings.setFontFamily,
args=[QWebSettings.SansSerifFont]),
'web-family-cursive':
(MapType.setter, lambda qws, v:
qws.setFontFamily(QWebSettings.CursiveFont, v),
""),
Setter(getter=QWebSettings.fontFamily,
setter=QWebSettings.setFontFamily,
args=[QWebSettings.CursiveFont]),
'web-family-fantasy':
(MapType.setter, lambda qws, v:
qws.setFontFamily(QWebSettings.FantasyFont, v),
""),
Setter(getter=QWebSettings.fontFamily,
setter=QWebSettings.setFontFamily,
args=[QWebSettings.FantasyFont]),
'web-size-minimum':
(MapType.setter, lambda qws, v:
qws.setFontSize(QWebSettings.MinimumFontSize, v)),
Setter(getter=QWebSettings.fontSize,
setter=QWebSettings.setFontSize,
args=[QWebSettings.MinimumFontSize]),
'web-size-minimum-logical':
(MapType.setter, lambda qws, v:
qws.setFontSize(QWebSettings.MinimumLogicalFontSize, v)),
Setter(getter=QWebSettings.fontSize,
setter=QWebSettings.setFontSize,
args=[QWebSettings.MinimumLogicalFontSize]),
'web-size-default':
(MapType.setter, lambda qws, v:
qws.setFontSize(QWebSettings.DefaultFontSize, v)),
Setter(getter=QWebSettings.fontSize,
setter=QWebSettings.setFontSize,
args=[QWebSettings.DefaultFontSize]),
'web-size-default-fixed':
(MapType.setter, lambda qws, v:
qws.setFontSize(QWebSettings.DefaultFixedFontSize, v)),
Setter(getter=QWebSettings.fontSize,
setter=QWebSettings.setFontSize,
args=[QWebSettings.DefaultFixedFontSize]),
},
'ui': {
'zoom-text-only':
(MapType.attribute, QWebSettings.ZoomTextOnly),
Attribute(QWebSettings.ZoomTextOnly),
'frame-flattening':
(MapType.attribute, QWebSettings.FrameFlatteningEnabled),
Attribute(QWebSettings.FrameFlatteningEnabled),
'user-stylesheet':
(MapType.setter, lambda qws, v:
qws.setUserStyleSheetUrl(v),
QUrl()),
Setter(getter=QWebSettings.userStyleSheetUrl,
setter=QWebSettings.setUserStyleSheetUrl),
'css-media-type':
(MapType.setter, lambda qws, v:
qws.setCSSMediaType(v)),
NullStringSetter(getter=QWebSettings.cssMediaType,
setter=QWebSettings.setCSSMediaType),
#'accelerated-compositing':
# (MapType.attribute, QWebSettings.AcceleratedCompositingEnabled),
# Attribute(QWebSettings.AcceleratedCompositingEnabled),
#'tiled-backing-store':
# (MapType.attribute, QWebSettings.TiledBackingStoreEnabled),
# Attribute(QWebSettings.TiledBackingStoreEnabled),
},
'storage': {
'offline-storage-database':
(MapType.attribute, QWebSettings.OfflineStorageDatabaseEnabled),
Attribute(QWebSettings.OfflineStorageDatabaseEnabled),
'offline-web-application-storage':
(MapType.attribute,
QWebSettings.OfflineWebApplicationCacheEnabled),
Attribute(QWebSettings.OfflineWebApplicationCacheEnabled),
'local-storage':
(MapType.attribute, QWebSettings.LocalStorageEnabled),
Attribute(QWebSettings.LocalStorageEnabled),
'maximum-pages-in-cache':
(MapType.static_setter, lambda v:
QWebSettings.setMaximumPagesInCache(v)),
GlobalSetter(getter=QWebSettings.maximumPagesInCache,
setter=QWebSettings.setMaximumPagesInCache),
'object-cache-capacities':
(MapType.static_setter, lambda v:
QWebSettings.setObjectCacheCapacities(*v)),
GlobalSetter(getter=None,
setter=QWebSettings.setObjectCacheCapacities,
unpack=True),
'offline-storage-default-quota':
(MapType.static_setter, lambda v:
QWebSettings.setOfflineStorageDefaultQuota(v)),
GlobalSetter(getter=QWebSettings.offlineStorageDefaultQuota,
setter=QWebSettings.setOfflineStorageDefaultQuota),
'offline-web-application-cache-quota':
(MapType.static_setter, lambda v:
QWebSettings.setOfflineWebApplicationCacheQuota(v)),
GlobalSetter(
getter=QWebSettings.offlineWebApplicationCacheQuota,
setter=QWebSettings.setOfflineWebApplicationCacheQuota),
},
'general': {
'private-browsing':
(MapType.attribute, QWebSettings.PrivateBrowsingEnabled),
Attribute(QWebSettings.PrivateBrowsingEnabled),
'developer-extras':
(MapType.attribute, QWebSettings.DeveloperExtrasEnabled),
Attribute(QWebSettings.DeveloperExtrasEnabled),
'print-element-backgrounds':
(MapType.attribute, QWebSettings.PrintElementBackgrounds),
Attribute(QWebSettings.PrintElementBackgrounds),
'xss-auditing':
(MapType.attribute, QWebSettings.XSSAuditingEnabled),
Attribute(QWebSettings.XSSAuditingEnabled),
'site-specific-quirks':
(MapType.attribute, QWebSettings.SiteSpecificQuirksEnabled),
Attribute(QWebSettings.SiteSpecificQuirksEnabled),
'default-encoding':
(MapType.setter, lambda qws, v: qws.setDefaultTextEncoding(v), ""),
Setter(getter=QWebSettings.defaultTextEncoding,
setter=QWebSettings.setDefaultTextEncoding),
}
}
settings = None
UNSET = object()
def _set_setting(typ, arg, default=UNSET, value=UNSET):
"""Set a QWebSettings setting.
Args:
typ: The type of the item.
arg: The argument (attribute/handler)
default: The value to use if the user set an empty string.
value: The value to set.
"""
if not isinstance(typ, MapType):
raise TypeError("Type {} is no MapType member!".format(typ))
if value is UNSET:
raise TypeError("No value given!")
if value is None:
if default is UNSET:
return
else:
value = default
if typ == MapType.attribute:
settings.setAttribute(arg, value)
elif typ == MapType.setter:
arg(settings, value)
elif typ == MapType.static_setter:
arg(value)
def init():
"""Initialize the global QWebSettings."""
QWebSettings.setIconDatabasePath(standarddir.cache())
@ -202,14 +377,15 @@ def init():
QWebSettings.setOfflineStoragePath(
os.path.join(standarddir.data(), 'offline-storage'))
global settings
settings = QWebSettings.globalSettings()
for sectname, section in MAPPINGS.items():
for optname, mapping in section.items():
default = mapping.save_default()
log.misc.vdebug("Saved default for {} -> {}: {!r}".format(
sectname, optname, default))
value = config.get(sectname, optname)
log.misc.debug("Setting {} -> {} to {!r}".format(sectname, optname,
value))
_set_setting(*mapping, value=value)
log.misc.vdebug("Setting {} -> {} to {!r}".format(
sectname, optname, value))
mapping.set(value)
objreg.get('config').changed.connect(update_settings)
@ -220,4 +396,4 @@ def update_settings(section, option):
except KeyError:
return
value = config.get(section, option)
_set_setting(*mapping, value=value)
mapping.set(value)