Get rid of most @property's.
They were problematic because they're executing hidden code, and also PyQt hides exceptions happening inside them.
This commit is contained in:
parent
a2e457ccc3
commit
ccfc0b3c19
@ -471,7 +471,7 @@ class Application(QApplication):
|
||||
return pages
|
||||
if self.mainwindow.tabs is None:
|
||||
return pages
|
||||
for tab in self.mainwindow.tabs.widgets:
|
||||
for tab in self.mainwindow.tabs.widgets():
|
||||
try:
|
||||
url = tab.cur_url.toString(
|
||||
QUrl.RemovePassword | QUrl.FullyEncoded)
|
||||
@ -586,7 +586,7 @@ class Application(QApplication):
|
||||
# exceptions occur.
|
||||
if pages is None:
|
||||
pages = []
|
||||
for tab in self.mainwindow.tabs.widgets:
|
||||
for tab in self.mainwindow.tabs.widgets():
|
||||
urlstr = tab.cur_url.toString(
|
||||
QUrl.RemovePassword | QUrl.FullyEncoded)
|
||||
if urlstr:
|
||||
|
@ -491,7 +491,7 @@ class CommandDispatcher:
|
||||
@cmdutils.register(instance='mainwindow.tabs.cmd')
|
||||
def tab_only(self):
|
||||
"""Close all tabs except for the current one."""
|
||||
for tab in self._tabs.widgets:
|
||||
for tab in self._tabs.widgets():
|
||||
if tab is self._tabs.currentWidget():
|
||||
continue
|
||||
self._tabs.close_tab(tab)
|
||||
|
@ -43,14 +43,10 @@ class DownloadItem(QObject):
|
||||
|
||||
Attributes:
|
||||
reply: The QNetworkReply associated with this download.
|
||||
percentage: How many percent were downloaded successfully.
|
||||
None if unknown.
|
||||
bytes_done: How many bytes there are already downloaded.
|
||||
bytes_total: The total count of bytes.
|
||||
None if the total is unknown.
|
||||
speed: The current download speed, in bytes per second.
|
||||
remaining_time: The time remaining for the download.
|
||||
None if not enough data is available yet.
|
||||
fileobj: The file object to download the file to.
|
||||
filename: The filename of the download.
|
||||
is_cancelled: Whether the download was cancelled.
|
||||
@ -120,13 +116,19 @@ class DownloadItem(QObject):
|
||||
"""
|
||||
speed = utils.format_size(self.speed, suffix='B/s')
|
||||
down = utils.format_size(self.bytes_done, suffix='B')
|
||||
if all(e is None for e in (self.percentage, self.remaining_time,
|
||||
self.bytes_total)):
|
||||
perc = self._percentage()
|
||||
remaining = self._remaining_time()
|
||||
if all(e is None for e in (perc, remaining, self.bytes_total)):
|
||||
return ('{name} [{speed:>10}|{down}]'.format(
|
||||
name=self.basename, speed=speed, down=down))
|
||||
perc = '??' if self.percentage is None else round(self.percentage)
|
||||
remaining = (utils.format_seconds(self.remaining_time)
|
||||
if self.remaining_time is not None else '?')
|
||||
if perc is None:
|
||||
perc = '??'
|
||||
else:
|
||||
perc = round(perc)
|
||||
if remaining is None:
|
||||
remaining = '?'
|
||||
else:
|
||||
remaining = utils.format_seconds(remaining)
|
||||
total = utils.format_size(self.bytes_total, suffix='B')
|
||||
return ('{name} [{speed:>10}|{remaining:>5}|{perc:>2}%|'
|
||||
'{down}/{total}]'.format(name=self.basename, speed=speed,
|
||||
@ -145,17 +147,15 @@ class DownloadItem(QObject):
|
||||
self.error.emit(e.strerror)
|
||||
self.finished.emit()
|
||||
|
||||
@property
|
||||
def percentage(self):
|
||||
"""Property to get the current download percentage."""
|
||||
def _percentage(self):
|
||||
"""The current download percentage, or None if unknown."""
|
||||
if self.bytes_total == 0 or self.bytes_total is None:
|
||||
return None
|
||||
else:
|
||||
return 100 * self.bytes_done / self.bytes_total
|
||||
|
||||
@property
|
||||
def remaining_time(self):
|
||||
"""Property to get the remaining download time in seconds."""
|
||||
def _remaining_time(self):
|
||||
"""The remaining download time in seconds, or None."""
|
||||
if self.bytes_total is None or not self.speed_avg:
|
||||
# No average yet or we don't know the total size.
|
||||
return None
|
||||
@ -172,10 +172,10 @@ class DownloadItem(QObject):
|
||||
start = config.get('colors', 'downloads.bg.start')
|
||||
stop = config.get('colors', 'downloads.bg.stop')
|
||||
system = config.get('colors', 'downloads.bg.system')
|
||||
if self.percentage is None:
|
||||
if self._percentage() is None:
|
||||
return start
|
||||
else:
|
||||
return utils.interpolate_color(start, stop, self.percentage,
|
||||
return utils.interpolate_color(start, stop, self._percentage(),
|
||||
system)
|
||||
|
||||
def cancel(self):
|
||||
|
@ -65,25 +65,13 @@ class HintContext:
|
||||
|
||||
def __init__(self):
|
||||
self.elems = {}
|
||||
self._target = None
|
||||
self.target = None
|
||||
self.baseurl = None
|
||||
self.to_follow = None
|
||||
self.frames = []
|
||||
self.connected_frames = []
|
||||
self.args = []
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
"""Getter for target so we can define a setter."""
|
||||
return self._target
|
||||
|
||||
@target.setter
|
||||
def target(self, val):
|
||||
"""Setter for target to do type checking."""
|
||||
if not isinstance(val, Target):
|
||||
raise TypeError("Target {} is no Target member!".format(val))
|
||||
self._target = val
|
||||
|
||||
def get_args(self, urlstr):
|
||||
"""Get the arguments, with {hint-url} replaced by the given URL."""
|
||||
args = []
|
||||
|
@ -79,7 +79,7 @@ class Command:
|
||||
"""
|
||||
# We don't use modeman.instance() here to avoid a circular import
|
||||
# of qutebrowser.keyinput.modeman.
|
||||
curmode = QCoreApplication.instance().modeman.mode
|
||||
curmode = QCoreApplication.instance().modeman.mode()
|
||||
if self.modes is not None and curmode not in self.modes:
|
||||
mode_names = '/'.join(mode.name for mode in self.modes)
|
||||
raise cmdexc.PrerequisitesError(
|
||||
|
@ -198,7 +198,7 @@ class ConfigManager(QObject):
|
||||
"""Get the option items as string for sect."""
|
||||
lines = []
|
||||
for optname, option in sect.items():
|
||||
value = option.get_first_value(startlayer='conf')
|
||||
value = option.value(startlayer='conf')
|
||||
for c in self.KEY_ESCAPE:
|
||||
if optname.startswith(c):
|
||||
optname = optname.replace(c, self.ESCAPE_CHAR + c, 1)
|
||||
@ -243,7 +243,7 @@ class ConfigManager(QObject):
|
||||
if not raw:
|
||||
raise ValueError("items() with raw=True is not implemented!")
|
||||
for optname, option in self.sections[sectname].items():
|
||||
items.append((optname, option.value))
|
||||
items.append((optname, option.value()))
|
||||
return items
|
||||
|
||||
def has_option(self, sectname, optname):
|
||||
@ -325,10 +325,10 @@ class ConfigManager(QObject):
|
||||
except KeyError:
|
||||
raise NoOptionError(optname, sectname)
|
||||
if raw:
|
||||
return val.value
|
||||
mapping = {key: val.value for key, val in sect.values.items()}
|
||||
return val.value()
|
||||
mapping = {key: val.value() for key, val in sect.values.items()}
|
||||
newval = self._interpolation.before_get(self, sectname, optname,
|
||||
val.value, mapping)
|
||||
val.value(), mapping)
|
||||
if transformed:
|
||||
newval = val.typ.transform(newval)
|
||||
return newval
|
||||
@ -403,7 +403,7 @@ class ConfigManager(QObject):
|
||||
sect = self.sections[sectname]
|
||||
except KeyError:
|
||||
raise NoSectionError(sectname)
|
||||
mapping = {key: val.value for key, val in sect.values.items()}
|
||||
mapping = {key: val.value() for key, val in sect.values.items()}
|
||||
interpolated = self._interpolation.before_get(self, sectname, optname,
|
||||
value, mapping)
|
||||
try:
|
||||
@ -462,27 +462,27 @@ class SectionProxy(collections.abc.MutableMapping):
|
||||
conf: The Config object.
|
||||
name: The section name.
|
||||
"""
|
||||
self._conf = conf
|
||||
self._name = name
|
||||
self.conf = conf
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return '<{} {}>'.format(self.__class__.__name__, self._name)
|
||||
return '<{} {}>'.format(self.__class__.__name__, self.name)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if not self._conf.has_option(self._name, key):
|
||||
if not self.conf.has_option(self.name, key):
|
||||
raise KeyError(key)
|
||||
return self._conf.get(self._name, key)
|
||||
return self.conf.get(self.name, key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
return self._conf.set('conf', self._name, key, value)
|
||||
return self.conf.set('conf', self.name, key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
if not (self._conf.has_option(self._name, key) and
|
||||
self._conf.remove_option(self._name, key)):
|
||||
if not (self.conf.has_option(self.name, key) and
|
||||
self.conf.remove_option(self.name, key)):
|
||||
raise KeyError(key)
|
||||
|
||||
def __contains__(self, key):
|
||||
return self._conf.has_option(self._name, key)
|
||||
return self.conf.has_option(self.name, key)
|
||||
|
||||
def __len__(self):
|
||||
return len(self._options())
|
||||
@ -492,7 +492,7 @@ class SectionProxy(collections.abc.MutableMapping):
|
||||
|
||||
def _options(self):
|
||||
"""Get the option keys from this section."""
|
||||
return self._conf.sections[self._name].keys()
|
||||
return self.conf.sections[self.name].keys()
|
||||
|
||||
def get(self, optname, *, raw=False): # pylint: disable=arguments-differ
|
||||
"""Get a value from this section.
|
||||
@ -504,14 +504,4 @@ class SectionProxy(collections.abc.MutableMapping):
|
||||
optname: The option name to get.
|
||||
raw: Whether to get a raw value or not.
|
||||
"""
|
||||
return self._conf.get(self._name, optname, raw=raw)
|
||||
|
||||
@property
|
||||
def conf(self):
|
||||
"""The conf object of the proxy is read-only."""
|
||||
return self._conf
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""The name of the section on a proxy is read-only."""
|
||||
return self._name
|
||||
return self.conf.get(self.name, optname, raw=raw)
|
||||
|
@ -120,12 +120,11 @@ class KeyValue(Section):
|
||||
def dump_userconfig(self):
|
||||
changed = []
|
||||
for k, v in self.items():
|
||||
if (v.values['temp'] is not None and
|
||||
v.values['temp'] != v.values['default']):
|
||||
changed.append((k, v.values['temp']))
|
||||
elif (v.values['conf'] is not None and
|
||||
v.values['conf'] != v.values['default']):
|
||||
changed.append((k, v.values['conf']))
|
||||
vals = v.values
|
||||
if vals['temp'] is not None and vals['temp'] != vals['default']:
|
||||
changed.append((k, vals['temp']))
|
||||
elif vals['conf'] is not None and vals['conf'] != vals['default']:
|
||||
changed.append((k, vals['conf']))
|
||||
return changed
|
||||
|
||||
|
||||
@ -172,8 +171,7 @@ class ValueList(Section):
|
||||
self.values = collections.ChainMap(
|
||||
self.layers['temp'], self.layers['conf'], self.layers['default'])
|
||||
|
||||
@property
|
||||
def ordered_values(self):
|
||||
def _ordered_values(self):
|
||||
"""Get ordered values in layers.
|
||||
|
||||
This is more expensive than the ChainMap, but we need this for
|
||||
@ -201,20 +199,20 @@ class ValueList(Section):
|
||||
self.layers['temp'], self.layers['conf'])
|
||||
for k, v in mapping.items():
|
||||
try:
|
||||
if v.value != self.layers['default'][k].value:
|
||||
changed.append((k, v.value))
|
||||
if v.value() != self.layers['default'][k].value():
|
||||
changed.append((k, v.value()))
|
||||
except KeyError:
|
||||
changed.append((k, v.value))
|
||||
changed.append((k, v.value()))
|
||||
return changed
|
||||
|
||||
def __iter__(self):
|
||||
"""Iterate over all set values."""
|
||||
return self.ordered_values.__iter__()
|
||||
return self._ordered_values().__iter__()
|
||||
|
||||
def items(self):
|
||||
"""Get dict items."""
|
||||
return self.ordered_values.items()
|
||||
return self._ordered_values().items()
|
||||
|
||||
def keys(self):
|
||||
"""Get value keys."""
|
||||
return self.ordered_values.keys()
|
||||
return self._ordered_values().keys()
|
||||
|
@ -31,8 +31,8 @@ class SettingValue:
|
||||
Attributes:
|
||||
typ: A BaseType subclass instance.
|
||||
value: (readonly property) The currently valid, most important value.
|
||||
_values: An OrderedDict with the values on different layers, with the
|
||||
most significant layer first.
|
||||
values: An OrderedDict with the values on different layers, with the
|
||||
most significant layer first.
|
||||
"""
|
||||
|
||||
def __init__(self, typ, default=None):
|
||||
@ -43,28 +43,17 @@ class SettingValue:
|
||||
default: Raw value to set.
|
||||
"""
|
||||
self.typ = typ
|
||||
self._values = collections.OrderedDict.fromkeys(
|
||||
self.values = collections.OrderedDict.fromkeys(
|
||||
['temp', 'conf', 'default'])
|
||||
self._values['default'] = default
|
||||
self.values['default'] = default
|
||||
|
||||
def __str__(self):
|
||||
"""Get raw string value."""
|
||||
return self.value
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""Get the currently valid value."""
|
||||
return self.get_first_value()
|
||||
|
||||
@property
|
||||
def default(self):
|
||||
"""Get the default value."""
|
||||
return self._values['default']
|
||||
|
||||
@property
|
||||
def values(self):
|
||||
"""Readonly property for _values."""
|
||||
return self._values
|
||||
return self.values['default']
|
||||
|
||||
def getlayers(self, startlayer):
|
||||
"""Get a dict of values starting with startlayer.
|
||||
@ -72,18 +61,18 @@ class SettingValue:
|
||||
Args:
|
||||
startlayer: The first layer to include.
|
||||
"""
|
||||
idx = list(self._values.keys()).index(startlayer)
|
||||
d = collections.OrderedDict(list(self._values.items())[idx:])
|
||||
idx = list(self.values.keys()).index(startlayer)
|
||||
d = collections.OrderedDict(list(self.values.items())[idx:])
|
||||
return d
|
||||
|
||||
def get_first_value(self, startlayer=None):
|
||||
def value(self, startlayer=None):
|
||||
"""Get the first valid value starting from startlayer.
|
||||
|
||||
Args:
|
||||
startlayer: The first layer to include.
|
||||
"""
|
||||
if startlayer is None:
|
||||
d = self._values
|
||||
d = self.values
|
||||
else:
|
||||
d = self.getlayers(startlayer)
|
||||
for val in d.values():
|
||||
@ -94,8 +83,7 @@ class SettingValue:
|
||||
|
||||
def transformed(self):
|
||||
"""Get the transformed value."""
|
||||
v = self.value
|
||||
return self.typ.transform(v)
|
||||
return self.typ.transform(self.value())
|
||||
|
||||
def setv(self, layer, value, interpolated):
|
||||
"""Set the value on a layer.
|
||||
@ -107,4 +95,4 @@ class SettingValue:
|
||||
interpolated: The interpolated value, for typechecking.
|
||||
"""
|
||||
self.typ.validate(interpolated)
|
||||
self._values[layer] = value
|
||||
self.values[layer] = value
|
||||
|
@ -73,7 +73,6 @@ class ModeManager(QObject):
|
||||
"""Manager for keyboard modes.
|
||||
|
||||
Attributes:
|
||||
mode: The current mode (readonly property).
|
||||
passthrough: A list of modes in which to pass through events.
|
||||
mainwindow: The mainwindow object
|
||||
locked: Whether current mode is locked. This means the current mode can
|
||||
@ -109,11 +108,10 @@ class ModeManager(QObject):
|
||||
'forward-unbound-keys')
|
||||
|
||||
def __repr__(self):
|
||||
return '<{} mode={}>'.format(self.__class__.__name__, self.mode)
|
||||
return '<{} mode={}>'.format(self.__class__.__name__, self.mode())
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
"""Read-only property for the current mode."""
|
||||
"""Get the current mode.."""
|
||||
if not self._mode_stack:
|
||||
return None
|
||||
return self._mode_stack[-1]
|
||||
@ -127,17 +125,18 @@ class ModeManager(QObject):
|
||||
Return:
|
||||
True if event should be filtered, False otherwise.
|
||||
"""
|
||||
handler = self._handlers[self.mode]
|
||||
if self.mode != usertypes.KeyMode.insert:
|
||||
curmode = self.mode()
|
||||
handler = self._handlers[curmode]
|
||||
if curmode != usertypes.KeyMode.insert:
|
||||
log.modes.debug("got keypress in mode {} - calling handler "
|
||||
"{}".format(self.mode, handler.__qualname__))
|
||||
"{}".format(curmode, handler.__qualname__))
|
||||
handled = handler(event) if handler is not None else False
|
||||
|
||||
is_non_alnum = bool(event.modifiers()) or not event.text().strip()
|
||||
|
||||
if handled:
|
||||
filter_this = True
|
||||
elif (self.mode in self.passthrough or
|
||||
elif (curmode in self.passthrough or
|
||||
self._forward_unbound_keys == 'all' or
|
||||
(self._forward_unbound_keys == 'auto' and is_non_alnum)):
|
||||
filter_this = False
|
||||
@ -147,11 +146,11 @@ class ModeManager(QObject):
|
||||
if not filter_this:
|
||||
self._releaseevents_to_pass.append(event)
|
||||
|
||||
if self.mode != usertypes.KeyMode.insert:
|
||||
if curmode != usertypes.KeyMode.insert:
|
||||
log.modes.debug("handled: {}, forward-unbound-keys: {}, "
|
||||
"passthrough: {}, is_non_alnum: {} --> filter: "
|
||||
"{}".format(handled, self._forward_unbound_keys,
|
||||
self.mode in self.passthrough,
|
||||
curmode in self.passthrough,
|
||||
is_non_alnum, filter_this))
|
||||
return filter_this
|
||||
|
||||
@ -172,7 +171,7 @@ class ModeManager(QObject):
|
||||
filter_this = False
|
||||
else:
|
||||
filter_this = True
|
||||
if self.mode != usertypes.KeyMode.insert:
|
||||
if self.mode() != usertypes.KeyMode.insert:
|
||||
log.modes.debug("filter: {}".format(filter_this))
|
||||
return filter_this
|
||||
|
||||
@ -205,9 +204,9 @@ class ModeManager(QObject):
|
||||
raise TypeError("Mode {} is no KeyMode member!".format(mode))
|
||||
if self.locked:
|
||||
log.modes.debug("Not entering mode {} because mode is locked to "
|
||||
"{}.".format(mode, self.mode))
|
||||
"{}.".format(mode, self.mode()))
|
||||
raise ModeLockedError("Mode is currently locked to {}".format(
|
||||
self.mode))
|
||||
self.mode()))
|
||||
log.modes.debug("Entering mode {}{}".format(
|
||||
mode, '' if reason is None else ' (reason: {})'.format(reason)))
|
||||
if mode not in self._handlers:
|
||||
@ -256,9 +255,9 @@ class ModeManager(QObject):
|
||||
not_modes=[usertypes.KeyMode.normal], hide=True)
|
||||
def leave_current_mode(self):
|
||||
"""Leave the mode we're currently in."""
|
||||
if self.mode == usertypes.KeyMode.normal:
|
||||
if self.mode() == usertypes.KeyMode.normal:
|
||||
raise ValueError("Can't leave normal mode!")
|
||||
self.leave(self.mode, 'leave current')
|
||||
self.leave(self.mode(), 'leave current')
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def on_config_changed(self, section, option):
|
||||
@ -278,7 +277,7 @@ class ModeManager(QObject):
|
||||
Return:
|
||||
True if event should be filtered, False otherwise.
|
||||
"""
|
||||
if self.mode is None:
|
||||
if self.mode() is None:
|
||||
# We got events before mode is set, so just pass them through.
|
||||
return False
|
||||
typ = event.type()
|
||||
|
@ -88,7 +88,7 @@ class HintKeyParser(keyparser.CommandKeyParser):
|
||||
|
||||
Attributes:
|
||||
_filtertext: The text to filter with.
|
||||
last_press: The nature of the last keypress, a LastPress member.
|
||||
_last_press: The nature of the last keypress, a LastPress member.
|
||||
"""
|
||||
|
||||
fire_hint = pyqtSignal(str)
|
||||
@ -97,22 +97,9 @@ class HintKeyParser(keyparser.CommandKeyParser):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent, supports_count=False, supports_chains=True)
|
||||
self._filtertext = ''
|
||||
self._last_press = None
|
||||
self.last_press = LastPress.none
|
||||
self._last_press = LastPress.none
|
||||
self.read_config('keybind.hint')
|
||||
|
||||
@property
|
||||
def last_press(self):
|
||||
"""Getter for last_press so we can define a setter."""
|
||||
return self._last_press
|
||||
|
||||
@last_press.setter
|
||||
def last_press(self, val):
|
||||
"""Setter for last_press to do typechecking."""
|
||||
if not isinstance(val, LastPress):
|
||||
raise TypeError("Value {} is no LastPress member!".format(val))
|
||||
self._last_press = val
|
||||
|
||||
def _handle_special_key(self, e):
|
||||
"""Override _handle_special_key to handle string filtering.
|
||||
|
||||
@ -132,14 +119,14 @@ class HintKeyParser(keyparser.CommandKeyParser):
|
||||
e.key(), e.text()))
|
||||
if e.key() == Qt.Key_Backspace:
|
||||
log.keyboard.debug("Got backspace, mode {}, filtertext '{}', "
|
||||
"keystring '{}'".format(self.last_press,
|
||||
"keystring '{}'".format(self._last_press,
|
||||
self._filtertext,
|
||||
self._keystring))
|
||||
if self.last_press == LastPress.filtertext and self._filtertext:
|
||||
if self._last_press == LastPress.filtertext and self._filtertext:
|
||||
self._filtertext = self._filtertext[:-1]
|
||||
self.filter_hints.emit(self._filtertext)
|
||||
return True
|
||||
elif self.last_press == LastPress.keystring and self._keystring:
|
||||
elif self._last_press == LastPress.keystring and self._keystring:
|
||||
self._keystring = self._keystring[:-1]
|
||||
self.keystring_updated.emit(self._keystring)
|
||||
return True
|
||||
@ -152,7 +139,7 @@ class HintKeyParser(keyparser.CommandKeyParser):
|
||||
else:
|
||||
self._filtertext += e.text()
|
||||
self.filter_hints.emit(self._filtertext)
|
||||
self.last_press = LastPress.filtertext
|
||||
self._last_press = LastPress.filtertext
|
||||
return True
|
||||
|
||||
def handle(self, e):
|
||||
@ -168,12 +155,12 @@ class HintKeyParser(keyparser.CommandKeyParser):
|
||||
if handled and self._keystring:
|
||||
# A key has been added to the keystring (Match.partial)
|
||||
self.keystring_updated.emit(self._keystring)
|
||||
self.last_press = LastPress.keystring
|
||||
self._last_press = LastPress.keystring
|
||||
return handled
|
||||
elif handled:
|
||||
# We handled the key but the keystring is empty. This happens when
|
||||
# match is Match.definitive, so a keychain has been completed.
|
||||
self.last_press = LastPress.none
|
||||
self._last_press = LastPress.none
|
||||
return handled
|
||||
else:
|
||||
# We couldn't find a keychain so we check if it's a special key.
|
||||
|
@ -43,7 +43,6 @@ class History:
|
||||
"""Command history.
|
||||
|
||||
Attributes:
|
||||
browsing: If we're currently browsing the history (property).
|
||||
history: A list of executed commands, with newer commands at the end.
|
||||
_tmphist: Temporary history for history browsing (as NeighborList)
|
||||
"""
|
||||
@ -63,8 +62,7 @@ class History:
|
||||
def __getitem__(self, idx):
|
||||
return self.history[idx]
|
||||
|
||||
@property
|
||||
def browsing(self):
|
||||
def is_browsing(self):
|
||||
"""Check _tmphist to see if we're browsing."""
|
||||
return self._tmphist is not None
|
||||
|
||||
@ -101,7 +99,7 @@ class History:
|
||||
ValueError if start() wasn't called.
|
||||
HistoryEndReachedError if the first item was reached.
|
||||
"""
|
||||
if not self.browsing:
|
||||
if not self.is_browsing():
|
||||
raise ValueError("Currently not browsing history")
|
||||
try:
|
||||
return self._tmphist.previtem()
|
||||
@ -117,7 +115,7 @@ class History:
|
||||
ValueError if start() wasn't called.
|
||||
HistoryEndReachedError if the last item was reached.
|
||||
"""
|
||||
if not self.browsing:
|
||||
if not self.is_browsing():
|
||||
raise ValueError("Currently not browsing history")
|
||||
try:
|
||||
return self._tmphist.nextitem()
|
||||
|
@ -35,7 +35,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
||||
|
||||
Attributes:
|
||||
srcmodel: The source model of this QSFPM.
|
||||
_pattern: The pattern to filter with, used in pattern property.
|
||||
_pattern: The pattern to filter with.
|
||||
"""
|
||||
|
||||
def __init__(self, source, parent=None):
|
||||
@ -44,13 +44,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
||||
self.srcmodel = source
|
||||
self._pattern = ''
|
||||
|
||||
@property
|
||||
def pattern(self):
|
||||
"""Getter for pattern."""
|
||||
return self._pattern
|
||||
|
||||
@pattern.setter
|
||||
def pattern(self, val):
|
||||
def set_pattern(self, val):
|
||||
"""Setter for pattern.
|
||||
|
||||
Invalidates the filter and re-sorts the model.
|
||||
@ -70,8 +64,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
||||
self.sort(sortcol)
|
||||
self.invalidate()
|
||||
|
||||
@property
|
||||
def item_count(self):
|
||||
def count(self):
|
||||
"""Get the count of non-toplevel items currently visible.
|
||||
|
||||
Note this only iterates one level deep, as we only need root items
|
||||
@ -121,7 +114,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
||||
def setSourceModel(self, model):
|
||||
"""Override QSortFilterProxyModel's setSourceModel to clear pattern."""
|
||||
log.completion.debug("Setting source model: {}".format(model))
|
||||
self.pattern = ''
|
||||
self.set_pattern('')
|
||||
self.srcmodel = model
|
||||
super().setSourceModel(model)
|
||||
|
||||
@ -135,7 +128,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
||||
parent: The parent item QModelIndex.
|
||||
|
||||
Return:
|
||||
True if self.pattern is contained in item, or if it's a root item
|
||||
True if self._pattern is contained in item, or if it's a root item
|
||||
(category). False in all other cases
|
||||
"""
|
||||
if parent == QModelIndex():
|
||||
@ -144,14 +137,14 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
||||
qtutils.ensure_valid(idx)
|
||||
data = self.srcmodel.data(idx)
|
||||
# TODO more sophisticated filtering
|
||||
if not self.pattern:
|
||||
if not self._pattern:
|
||||
return True
|
||||
return self.pattern in data
|
||||
return self._pattern in data
|
||||
|
||||
def lessThan(self, lindex, rindex):
|
||||
"""Custom sorting implementation.
|
||||
|
||||
Prefers all items which start with self.pattern. Other than that, uses
|
||||
Prefers all items which start with self._pattern. Other than that, uses
|
||||
normal Python string sorting.
|
||||
|
||||
Args:
|
||||
@ -173,8 +166,8 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
||||
left = self.srcmodel.data(lindex)
|
||||
right = self.srcmodel.data(rindex)
|
||||
|
||||
leftstart = left.startswith(self.pattern)
|
||||
rightstart = right.startswith(self.pattern)
|
||||
leftstart = left.startswith(self._pattern)
|
||||
rightstart = right.startswith(self._pattern)
|
||||
|
||||
if leftstart and rightstart:
|
||||
return left < right
|
||||
|
@ -148,8 +148,7 @@ class Completer(QObject):
|
||||
data = model.data(indexes[0])
|
||||
if data is None:
|
||||
return
|
||||
if model.item_count == 1 and config.get('completion',
|
||||
'quick-complete'):
|
||||
if model.count() == 1 and config.get('completion', 'quick-complete'):
|
||||
# If we only have one item, we want to apply it immediately
|
||||
# and go on to the next part.
|
||||
self.change_completed_part.emit(data, True)
|
||||
@ -192,13 +191,13 @@ class Completer(QObject):
|
||||
return
|
||||
|
||||
pattern = parts[cursor_part] if parts else ''
|
||||
self.view.model().pattern = pattern
|
||||
self.view.model().set_pattern(pattern)
|
||||
|
||||
log.completion.debug(
|
||||
"New completion for {}: {}, with pattern '{}'".format(
|
||||
parts, model.srcmodel.__class__.__name__, pattern))
|
||||
|
||||
if self.view.model().item_count == 0:
|
||||
if self.view.model().count() == 0:
|
||||
self.view.hide()
|
||||
return
|
||||
|
||||
|
@ -46,13 +46,13 @@ def parse_content_disposition(reply):
|
||||
try:
|
||||
content_disposition = rfc6266.parse_headers(
|
||||
bytes(reply.rawHeader('Content-Disposition')))
|
||||
filename = content_disposition.filename_unsafe
|
||||
filename = content_disposition.filename()
|
||||
except UnicodeDecodeError as e:
|
||||
log.misc.warning("Error while getting filename: {}: {}".format(
|
||||
e.__class__.__name__, e))
|
||||
filename = None
|
||||
else:
|
||||
is_inline = content_disposition.is_inline
|
||||
is_inline = content_disposition.is_inline()
|
||||
# Then try to get filename from url
|
||||
if not filename:
|
||||
filename = reply.url().path()
|
||||
|
@ -36,8 +36,7 @@ class ReadlineBridge:
|
||||
def __init__(self):
|
||||
self.deleted = {}
|
||||
|
||||
@property
|
||||
def widget(self):
|
||||
def _widget(self):
|
||||
"""Get the currently active QLineEdit."""
|
||||
w = QApplication.instance().focusWidget()
|
||||
if isinstance(w, QLineEdit):
|
||||
@ -52,9 +51,10 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's backward-char.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.cursorBackward(False)
|
||||
widget.cursorBackward(False)
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -63,9 +63,10 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's forward-char.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.cursorForward(False)
|
||||
widget.cursorForward(False)
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -74,9 +75,10 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's backward-word.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.cursorWordBackward(False)
|
||||
widget.cursorWordBackward(False)
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -85,9 +87,10 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's forward-word.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.cursorWordForward(False)
|
||||
widget.cursorWordForward(False)
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -96,9 +99,10 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's beginning-of-line.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.home(False)
|
||||
widget.home(False)
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -107,9 +111,10 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's end-of-line.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.end(False)
|
||||
widget.end(False)
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -118,11 +123,12 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's unix-line-discard.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.home(True)
|
||||
self.deleted[self.widget] = self.widget.selectedText()
|
||||
self.widget.del_()
|
||||
widget.home(True)
|
||||
self.deleted[widget] = widget.selectedText()
|
||||
widget.del_()
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -131,11 +137,12 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's kill-line.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.end(True)
|
||||
self.deleted[self.widget] = self.widget.selectedText()
|
||||
self.widget.del_()
|
||||
widget.end(True)
|
||||
self.deleted[widget] = widget.selectedText()
|
||||
widget.del_()
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -144,11 +151,12 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's unix-word-rubout.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.cursorWordBackward(True)
|
||||
self.deleted[self.widget] = self.widget.selectedText()
|
||||
self.widget.del_()
|
||||
widget.cursorWordBackward(True)
|
||||
self.deleted[widget] = widget.selectedText()
|
||||
widget.del_()
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -157,11 +165,12 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's kill-word.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.cursorWordForward(True)
|
||||
self.deleted[self.widget] = self.widget.selectedText()
|
||||
self.widget.del_()
|
||||
widget.cursorWordForward(True)
|
||||
self.deleted[widget] = widget.selectedText()
|
||||
widget.del_()
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -170,9 +179,10 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's yank.
|
||||
"""
|
||||
if self.widget is None or self.widget not in self.deleted:
|
||||
widget = self._widget()
|
||||
if widget is None or widget not in self.deleted:
|
||||
return
|
||||
self.widget.insert(self.deleted[self.widget])
|
||||
widget.insert(self.deleted[widget])
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -181,9 +191,10 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's delete-char.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.del_()
|
||||
widget.del_()
|
||||
|
||||
@cmdutils.register(instance='rl_bridge', hide=True,
|
||||
modes=[typ.KeyMode.command, typ.KeyMode.prompt])
|
||||
@ -192,6 +203,7 @@ class ReadlineBridge:
|
||||
|
||||
This acts like readline's backward-delete-char.
|
||||
"""
|
||||
if self.widget is None:
|
||||
widget = self._widget()
|
||||
if widget is None:
|
||||
return
|
||||
self.widget.backspace()
|
||||
widget.backspace()
|
||||
|
@ -250,18 +250,17 @@ class ContentDisposition:
|
||||
assert isinstance(param, ExtDispositionParm)
|
||||
self.assocs['filename*'] = parse_ext_value(param.value).string
|
||||
|
||||
@property
|
||||
def filename_unsafe(self):
|
||||
def filename(self):
|
||||
"""The filename from the Content-Disposition header or None.
|
||||
|
||||
On safety:
|
||||
This property records the intent of the sender.
|
||||
|
||||
You shouldn't use this sender-controlled value as a filesystem
|
||||
path, it can be insecure. Serving files with this filename can be
|
||||
dangerous as well, due to a certain browser using the part after the
|
||||
dot for mime-sniffing.
|
||||
Saving it to a database is fine by itself though.
|
||||
This property records the intent of the sender.
|
||||
|
||||
You shouldn't use this sender-controlled value as a filesystem path, it
|
||||
can be insecure. Serving files with this filename can be dangerous as
|
||||
well, due to a certain browser using the part after the dot for
|
||||
mime-sniffing. Saving it to a database is fine by itself though.
|
||||
"""
|
||||
|
||||
if 'filename*' in self.assocs:
|
||||
@ -270,11 +269,10 @@ class ContentDisposition:
|
||||
# XXX Reject non-ascii (parsed via qdtext) here?
|
||||
return self.assocs['filename']
|
||||
|
||||
@property
|
||||
def is_inline(self):
|
||||
"""If this property is true, the file should be handled inline.
|
||||
"""Return if the file should be handled inline.
|
||||
|
||||
Otherwise, and unless your application supports other dispositions
|
||||
If not, and unless your application supports other dispositions
|
||||
than the standard inline and attachment, it should be handled
|
||||
as an attachment.
|
||||
"""
|
||||
|
@ -60,8 +60,7 @@ class ConsoleLineEdit(misc.CommandLineEdit):
|
||||
self.returnPressed.connect(self.execute)
|
||||
self.setText('')
|
||||
|
||||
@property
|
||||
def curprompt(self):
|
||||
def _curprompt(self):
|
||||
"""Get the prompt which is visible currently."""
|
||||
return sys.ps2 if self._more else sys.ps1
|
||||
|
||||
@ -79,7 +78,7 @@ class ConsoleLineEdit(misc.CommandLineEdit):
|
||||
"""Push a line to the interpreter."""
|
||||
self._buffer.append(line)
|
||||
source = '\n'.join(self._buffer)
|
||||
self.write.emit(self.curprompt + line)
|
||||
self.write.emit(self._curprompt() + line)
|
||||
# We do two special things with the contextmanagers here:
|
||||
# - We replace stdout/stderr to capture output. Even if we could
|
||||
# override InteractiveInterpreter's write method, most things are
|
||||
@ -89,14 +88,14 @@ class ConsoleLineEdit(misc.CommandLineEdit):
|
||||
# printed and don't ooen a crashdialog.
|
||||
with utils.fake_io(self.write.emit), utils.disabled_excepthook():
|
||||
self._more = self._interpreter.runsource(source, '<console>')
|
||||
self.set_prompt(self.curprompt)
|
||||
self.set_prompt(self._curprompt())
|
||||
if not self._more:
|
||||
self._buffer = []
|
||||
|
||||
def history_prev(self):
|
||||
"""Go back in the history."""
|
||||
try:
|
||||
if not self.history.browsing:
|
||||
if not self.history.is_browsing():
|
||||
item = self.history.start(self.text().strip())
|
||||
else:
|
||||
item = self.history.previtem()
|
||||
@ -107,7 +106,7 @@ class ConsoleLineEdit(misc.CommandLineEdit):
|
||||
|
||||
def history_next(self):
|
||||
"""Go forward in the history."""
|
||||
if not self.history.browsing:
|
||||
if not self.history.is_browsing():
|
||||
return
|
||||
try:
|
||||
item = self.history.nextitem()
|
||||
@ -117,12 +116,12 @@ class ConsoleLineEdit(misc.CommandLineEdit):
|
||||
|
||||
def setText(self, text):
|
||||
"""Override setText to always prepend the prompt."""
|
||||
super().setText(self.curprompt + text)
|
||||
super().setText(self._curprompt() + text)
|
||||
|
||||
def text(self):
|
||||
"""Override text to strip the prompt."""
|
||||
text = super().text()
|
||||
return text[len(self.curprompt):]
|
||||
return text[len(self._curprompt()):]
|
||||
|
||||
def keyPressEvent(self, e):
|
||||
"""Override keyPressEvent to handle up/down keypresses."""
|
||||
|
@ -65,14 +65,12 @@ class StatusBar(QWidget):
|
||||
For some reason we need to have this as class attribute so
|
||||
pyqtProperty works correctly.
|
||||
|
||||
_prompt_active: If we're currently in prompt-mode, accessed through the
|
||||
prompt_active property.
|
||||
_prompt_active: If we're currently in prompt-mode.
|
||||
|
||||
For some reason we need to have this as class attribute
|
||||
so pyqtProperty works correctly.
|
||||
|
||||
_insert_active: If we're currently in insert mode, accessed through the
|
||||
insert_active property.
|
||||
_insert_active: If we're currently in insert mode.
|
||||
|
||||
For some reason we need to have this as class attribute
|
||||
so pyqtProperty works correctly.
|
||||
@ -180,8 +178,7 @@ class StatusBar(QWidget):
|
||||
# pylint: disable=method-hidden
|
||||
return self._error
|
||||
|
||||
@error.setter
|
||||
def error(self, val):
|
||||
def _set_error(self, val):
|
||||
"""Setter for self.error, so it can be used as Qt property.
|
||||
|
||||
Re-set the stylesheet after setting the value, so everything gets
|
||||
@ -206,9 +203,8 @@ class StatusBar(QWidget):
|
||||
# pylint: disable=method-hidden
|
||||
return self._prompt_active
|
||||
|
||||
@prompt_active.setter
|
||||
def prompt_active(self, val):
|
||||
"""Setter for self.prompt_active, so it can be used as Qt property.
|
||||
def _set_prompt_active(self, val):
|
||||
"""Setter for self.prompt_active.
|
||||
|
||||
Re-set the stylesheet after setting the value, so everything gets
|
||||
updated by Qt properly.
|
||||
@ -223,9 +219,8 @@ class StatusBar(QWidget):
|
||||
# pylint: disable=method-hidden
|
||||
return self._insert_active
|
||||
|
||||
@insert_active.setter
|
||||
def insert_active(self, val):
|
||||
"""Setter for self.insert_active, so it can be used as Qt property.
|
||||
def _set_insert_active(self, val):
|
||||
"""Setter for self.insert_active.
|
||||
|
||||
Re-set the stylesheet after setting the value, so everything gets
|
||||
updated by Qt properly.
|
||||
@ -239,8 +234,8 @@ class StatusBar(QWidget):
|
||||
try:
|
||||
error, text = self._text_queue.popleft()
|
||||
except IndexError:
|
||||
self.error = False
|
||||
self.txt.temptext = ''
|
||||
self._set_error(False)
|
||||
self.txt.set_text(self.txt.Text.temp, '')
|
||||
self._text_pop_timer.stop()
|
||||
# If a previous widget was interrupted by an error, restore it.
|
||||
if self._previous_widget == PreviousWidget.prompt:
|
||||
@ -255,12 +250,12 @@ class StatusBar(QWidget):
|
||||
log.statusbar.debug("Displaying {} message: {}".format(
|
||||
'error' if error else 'text', text))
|
||||
log.statusbar.debug("Remaining: {}".format(self._text_queue))
|
||||
self.error = error
|
||||
self.txt.temptext = text
|
||||
self._set_error(error)
|
||||
self.txt.set_text(self.txt.Text.temp, text)
|
||||
|
||||
def _show_cmd_widget(self):
|
||||
"""Show command widget instead of temporary text."""
|
||||
self.error = False
|
||||
self._set_error(False)
|
||||
self._previous_widget = PreviousWidget.prompt
|
||||
if self._text_pop_timer.isActive():
|
||||
self._timer_was_active = True
|
||||
@ -281,8 +276,8 @@ class StatusBar(QWidget):
|
||||
|
||||
def _show_prompt_widget(self):
|
||||
"""Show prompt widget instead of temporary text."""
|
||||
self.error = False
|
||||
self.prompt_active = True
|
||||
self._set_error(False)
|
||||
self._set_prompt_active(True)
|
||||
self._previous_widget = PreviousWidget.prompt
|
||||
if self._text_pop_timer.isActive():
|
||||
self._timer_was_active = True
|
||||
@ -291,7 +286,7 @@ class StatusBar(QWidget):
|
||||
|
||||
def _hide_prompt_widget(self):
|
||||
"""Show temporary text instead of prompt widget."""
|
||||
self.prompt_active = False
|
||||
self._set_prompt_active(False)
|
||||
self._previous_widget = PreviousWidget.none
|
||||
log.statusbar.debug("Hiding prompt widget, queue: {}".format(
|
||||
self._text_queue))
|
||||
@ -328,8 +323,8 @@ class StatusBar(QWidget):
|
||||
# immediately. We then start the pop_timer only to restore the
|
||||
# normal state in 2 seconds.
|
||||
log.statusbar.debug("Displaying immediately")
|
||||
self.error = error
|
||||
self.txt.temptext = text
|
||||
self._set_error(error)
|
||||
self.txt.set_text(self.txt.Text.temp, text)
|
||||
self._text_pop_timer.start()
|
||||
elif self._text_queue and self._text_queue[-1] == (error, text):
|
||||
# If we get the same message multiple times in a row and we're
|
||||
@ -341,8 +336,8 @@ class StatusBar(QWidget):
|
||||
# We display this immediately and restart the timer.to clear it and
|
||||
# display the rest of the queue later.
|
||||
log.statusbar.debug("Moving to beginning of queue")
|
||||
self.error = error
|
||||
self.txt.temptext = text
|
||||
self._set_error(error)
|
||||
self.txt.set_text(self.txt.Text.temp, text)
|
||||
self._text_pop_timer.start()
|
||||
else:
|
||||
# There are still some messages to be displayed, so we queue this
|
||||
@ -376,23 +371,24 @@ class StatusBar(QWidget):
|
||||
@pyqtSlot(str)
|
||||
def set_text(self, val):
|
||||
"""Set a normal (persistent) text in the status bar."""
|
||||
self.txt.normaltext = val
|
||||
self.txt.set_text(self.txt.Text.normal, val)
|
||||
|
||||
@pyqtSlot(usertypes.KeyMode)
|
||||
def on_mode_entered(self, mode):
|
||||
"""Mark certain modes in the commandline."""
|
||||
if mode in modeman.instance().passthrough:
|
||||
self.txt.normaltext = "-- {} MODE --".format(mode.name.upper())
|
||||
text = "-- {} MODE --".format(mode.name.upper())
|
||||
self.txt.set_text(self.txt.Text.normal, text)
|
||||
if mode == usertypes.KeyMode.insert:
|
||||
self.insert_active = True
|
||||
self._set_insert_active(True)
|
||||
|
||||
@pyqtSlot(usertypes.KeyMode)
|
||||
def on_mode_left(self, mode):
|
||||
"""Clear marked mode."""
|
||||
if mode in modeman.instance().passthrough:
|
||||
self.txt.normaltext = ""
|
||||
self.txt.set_text(self.txt.Text.normal, '')
|
||||
if mode == usertypes.KeyMode.insert:
|
||||
self.insert_active = False
|
||||
self._set_insert_active(False)
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def on_config_changed(self, section, option):
|
||||
|
@ -81,9 +81,8 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
self.cursorPositionChanged.connect(self.on_cursor_position_changed)
|
||||
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)
|
||||
|
||||
@property
|
||||
def prefix(self):
|
||||
"""Property to get the current command prefix entered."""
|
||||
"""Get the currently entered command prefix."""
|
||||
text = self.text()
|
||||
if not text:
|
||||
return ''
|
||||
@ -92,10 +91,9 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
else:
|
||||
return ''
|
||||
|
||||
@property
|
||||
def parts(self):
|
||||
"""Property to get the text split up in parts."""
|
||||
text = self.text()[len(self.prefix):]
|
||||
def split(self):
|
||||
"""Get the text split up in parts."""
|
||||
text = self.text()[len(self.prefix()):]
|
||||
if not text:
|
||||
# When only ":" is entered, we already have one imaginary part,
|
||||
# which just is empty at the moment.
|
||||
@ -122,8 +120,8 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
spaces = True
|
||||
else:
|
||||
spaces = False
|
||||
cursor_pos -= len(self.prefix)
|
||||
for i, part in enumerate(self.parts):
|
||||
cursor_pos -= len(self.prefix())
|
||||
for i, part in enumerate(self.split()):
|
||||
if cursor_pos <= len(part):
|
||||
# foo| bar
|
||||
self.cursor_part = i
|
||||
@ -140,7 +138,8 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
@pyqtSlot()
|
||||
def on_cursor_position_changed(self):
|
||||
"""Update completion when the cursor position changed."""
|
||||
self.update_completion.emit(self.prefix, self.parts, self.cursor_part)
|
||||
self.update_completion.emit(self.prefix(), self.split(),
|
||||
self.cursor_part)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def set_cmd_text(self, text):
|
||||
@ -156,7 +155,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
self.setText(text)
|
||||
if old_text != text:
|
||||
# We want the completion to pop out here.
|
||||
self.update_completion.emit(self.prefix, self.parts,
|
||||
self.update_completion.emit(self.prefix(), self.split(),
|
||||
self.cursor_part)
|
||||
self.setFocus()
|
||||
self.show_cmd.emit()
|
||||
@ -189,17 +188,17 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
including a trailing space and we shouldn't continue
|
||||
completing the current item.
|
||||
"""
|
||||
parts = self.parts[:]
|
||||
parts = self.split()
|
||||
log.completion.debug("changing part {} to '{}'".format(
|
||||
self.cursor_part, newtext))
|
||||
parts[self.cursor_part] = newtext
|
||||
# We want to place the cursor directly after the part we just changed.
|
||||
cursor_str = self.prefix + ' '.join(parts[:self.cursor_part + 1])
|
||||
cursor_str = self.prefix() + ' '.join(parts[:self.cursor_part + 1])
|
||||
if immediate:
|
||||
# If we should complete immediately, we want to move the cursor by
|
||||
# one more char, to get to the next field.
|
||||
cursor_str += ' '
|
||||
text = self.prefix + ' '.join(parts)
|
||||
text = self.prefix() + ' '.join(parts)
|
||||
if immediate and self.cursor_part == len(parts) - 1:
|
||||
# If we should complete immediately and we're completing the last
|
||||
# part in the commandline, we automatically add a space.
|
||||
@ -215,7 +214,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
def command_history_prev(self):
|
||||
"""Go back in the commandline history."""
|
||||
try:
|
||||
if not self.history.browsing:
|
||||
if not self.history.is_browsing():
|
||||
item = self.history.start(self.text().strip())
|
||||
else:
|
||||
item = self.history.previtem()
|
||||
@ -229,7 +228,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
modes=[usertypes.KeyMode.command])
|
||||
def command_history_next(self):
|
||||
"""Go forward in the commandline history."""
|
||||
if not self.history.browsing:
|
||||
if not self.history.is_browsing():
|
||||
return
|
||||
try:
|
||||
item = self.history.nextitem()
|
||||
|
@ -283,7 +283,7 @@ class Prompter:
|
||||
try:
|
||||
modeman.enter(mode, 'question asked')
|
||||
except modeman.ModeLockedError:
|
||||
if modeman.instance().mode != usertypes.KeyMode.prompt:
|
||||
if modeman.instance().mode() != usertypes.KeyMode.prompt:
|
||||
question.abort()
|
||||
return None
|
||||
modeman.instance().locked = True
|
||||
|
@ -23,6 +23,7 @@ from PyQt5.QtCore import pyqtSlot
|
||||
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.widgets.statusbar import textbase
|
||||
from qutebrowser.utils import usertypes
|
||||
|
||||
|
||||
class Text(textbase.TextBase):
|
||||
@ -31,80 +32,63 @@ class Text(textbase.TextBase):
|
||||
|
||||
Attributes:
|
||||
_normaltext: The "permanent" text. Never automatically cleared.
|
||||
Accessed via normaltext property.
|
||||
_temptext: The temporary text to display.
|
||||
Accessed via temptext property.
|
||||
_jstext: The text javascript wants to display.
|
||||
Accessed via jstext property.
|
||||
|
||||
The temptext is shown from StatusBar when a temporary text or error is
|
||||
available. If not, the permanent text is shown.
|
||||
"""
|
||||
|
||||
Text = usertypes.enum('Text', 'normal', 'temp', 'js')
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._normaltext = ''
|
||||
self._temptext = ''
|
||||
self._jstext = ''
|
||||
|
||||
@property
|
||||
def normaltext(self):
|
||||
"""Getter for normaltext so we can define a setter."""
|
||||
return self._normaltext
|
||||
def set_text(self, which, text):
|
||||
"""Set a text.
|
||||
|
||||
@normaltext.setter
|
||||
def normaltext(self, val):
|
||||
"""Setter for normaltext to update text display after setting."""
|
||||
self._normaltext = val
|
||||
self._update_text()
|
||||
|
||||
@property
|
||||
def temptext(self):
|
||||
"""Getter for temptext so we can define a setter."""
|
||||
return self._temptext
|
||||
|
||||
@temptext.setter
|
||||
def temptext(self, val):
|
||||
"""Setter for temptext to update text display after setting."""
|
||||
self._temptext = val
|
||||
self._update_text()
|
||||
|
||||
@property
|
||||
def jstext(self):
|
||||
"""Getter for jstext so we can define a setter."""
|
||||
return self._jstext
|
||||
|
||||
@jstext.setter
|
||||
def jstext(self, val):
|
||||
"""Setter for jstext to update text display after setting."""
|
||||
self._jstext = val
|
||||
Args:
|
||||
which: Which text to set, a self.Text instance.
|
||||
text: The text to set.
|
||||
"""
|
||||
if which is self.Text.normal:
|
||||
self._normaltext = text
|
||||
elif which is self.Text.temp:
|
||||
self._temptext = text
|
||||
elif which is self.Text.js:
|
||||
self._jstext = text
|
||||
else:
|
||||
raise ValueError("Invalid value {} for which!".format(which))
|
||||
self._update_text()
|
||||
|
||||
def _update_text(self):
|
||||
"""Update QLabel text when needed."""
|
||||
if self.temptext:
|
||||
self.setText(self.temptext)
|
||||
elif self.jstext and config.get('ui', 'display-statusbar-messages'):
|
||||
self.setText(self.jstext)
|
||||
elif self.normaltext:
|
||||
self.setText(self.normaltext)
|
||||
if self._temptext:
|
||||
self.setText(self._temptext)
|
||||
elif self._jstext and config.get('ui', 'display-statusbar-messages'):
|
||||
self.setText(self._jstext)
|
||||
elif self._normaltext:
|
||||
self.setText(self._normaltext)
|
||||
else:
|
||||
self.setText('')
|
||||
|
||||
@pyqtSlot(str)
|
||||
def on_statusbar_message(self, val):
|
||||
"""Called when javascript tries to set a statusbar message."""
|
||||
self.jstext = val
|
||||
self._jstext = val
|
||||
|
||||
@pyqtSlot()
|
||||
def on_load_started(self):
|
||||
"""Clear jstext when page loading started."""
|
||||
self.jstext = ''
|
||||
self._jstext = ''
|
||||
|
||||
@pyqtSlot(int)
|
||||
def on_tab_changed(self, tab):
|
||||
"""Set the correct jstext when the current tab changed."""
|
||||
self.jstext = tab.statusbar_message
|
||||
self._jstext = tab.statusbar_message
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def on_config_changed(self, section, option):
|
||||
|
@ -37,9 +37,9 @@ class UrlText(textbase.TextBase):
|
||||
"""URL displayed in the statusbar.
|
||||
|
||||
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.
|
||||
hover_url: The URL we're currently hovering over.
|
||||
_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.
|
||||
_hover_url: The URL we're currently hovering over.
|
||||
_ssl_errors: Whether SSL errors occured while loading.
|
||||
|
||||
Class attributes:
|
||||
@ -96,64 +96,18 @@ class UrlText(textbase.TextBase):
|
||||
else:
|
||||
return self._urltype.name
|
||||
|
||||
@urltype.setter
|
||||
def urltype(self, val):
|
||||
"""Setter for self.urltype to update stylesheets after it is set."""
|
||||
if not isinstance(val, UrlType):
|
||||
raise TypeError("Type {} is no UrlType member!".format(val))
|
||||
self._urltype = val
|
||||
self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
|
||||
|
||||
@property
|
||||
def hover_url(self):
|
||||
"""Getter so we can define a setter."""
|
||||
return self._hover_url
|
||||
|
||||
@hover_url.setter
|
||||
def hover_url(self, val):
|
||||
"""Setter to update displayed URL when hover_url was set."""
|
||||
self._hover_url = val
|
||||
self._update_url()
|
||||
|
||||
@property
|
||||
def normal_url(self):
|
||||
"""Getter so we can define a setter."""
|
||||
return self._normal_url
|
||||
|
||||
@normal_url.setter
|
||||
def normal_url(self, val):
|
||||
"""Setter to update displayed URL when normal_url was set."""
|
||||
self._normal_url = val
|
||||
self._update_url()
|
||||
|
||||
@property
|
||||
def normal_url_type(self):
|
||||
"""Getter so we can define a setter."""
|
||||
return self._normal_url_type
|
||||
|
||||
@normal_url_type.setter
|
||||
def normal_url_type(self, val):
|
||||
"""Setter to update displayed URL when normal_url_type was set.
|
||||
|
||||
Args:
|
||||
val: The value as an UrlType instance.
|
||||
"""
|
||||
if not isinstance(val, UrlType):
|
||||
raise TypeError("Type {} is no UrlType member!".format(val))
|
||||
self._normal_url_type = val
|
||||
self._update_url()
|
||||
|
||||
def _update_url(self):
|
||||
"""Update the displayed URL if the url or the hover url changed."""
|
||||
if self.hover_url is not None:
|
||||
self.setText(self.hover_url)
|
||||
self.urltype = UrlType.hover
|
||||
elif self.normal_url is not None:
|
||||
self.setText(self.normal_url)
|
||||
self.urltype = self.normal_url_type
|
||||
if self._hover_url is not None:
|
||||
self.setText(self._hover_url)
|
||||
self._urltype = UrlType.hover
|
||||
elif self._normal_url is not None:
|
||||
self.setText(self._normal_url)
|
||||
self._urltype = self._normal_url_type
|
||||
else:
|
||||
self.setText('')
|
||||
self.urltype = UrlType.normal
|
||||
self._urltype = UrlType.normal
|
||||
self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
|
||||
|
||||
@pyqtSlot(str)
|
||||
def on_load_status_changed(self, status_str):
|
||||
@ -165,9 +119,10 @@ class UrlText(textbase.TextBase):
|
||||
status = webview.LoadStatus[status_str]
|
||||
if status in (webview.LoadStatus.success, webview.LoadStatus.error,
|
||||
webview.LoadStatus.warn):
|
||||
self.normal_url_type = UrlType[status_str]
|
||||
self._normal_url_type = UrlType[status_str]
|
||||
else:
|
||||
self.normal_url_type = UrlType.normal
|
||||
self._normal_url_type = UrlType.normal
|
||||
self._update_url()
|
||||
|
||||
@pyqtSlot(str)
|
||||
def set_url(self, s):
|
||||
@ -176,8 +131,9 @@ class UrlText(textbase.TextBase):
|
||||
Args:
|
||||
s: The URL to set as string.
|
||||
"""
|
||||
self.normal_url = s
|
||||
self.normal_url_type = UrlType.normal
|
||||
self._normal_url = s
|
||||
self._normal_url_type = UrlType.normal
|
||||
self._update_url()
|
||||
|
||||
@pyqtSlot(str, str, str)
|
||||
def set_hover_url(self, link, _title, _text):
|
||||
@ -192,13 +148,15 @@ class UrlText(textbase.TextBase):
|
||||
_text: The text of the hovered link (string)
|
||||
"""
|
||||
if link:
|
||||
self.hover_url = link
|
||||
self._hover_url = link
|
||||
else:
|
||||
self.hover_url = None
|
||||
self._hover_url = None
|
||||
self._update_url()
|
||||
|
||||
@pyqtSlot(int)
|
||||
def on_tab_changed(self, tab):
|
||||
"""Update URL if the tab changed."""
|
||||
self.hover_url = None
|
||||
self.normal_url = tab.cur_url.toDisplayString()
|
||||
self._hover_url = None
|
||||
self._normal_url = tab.cur_url.toDisplayString()
|
||||
self.on_load_status_changed(tab.load_status.name)
|
||||
self._update_url()
|
||||
|
@ -120,12 +120,12 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
return '<{} with {} tabs>'.format(self.__class__.__name__,
|
||||
self.count())
|
||||
|
||||
@property
|
||||
def widgets(self):
|
||||
"""Get a list of open tab widgets.
|
||||
|
||||
We don't implement this as generator so we can delete tabs while
|
||||
iterating over the list."""
|
||||
iterating over the list.
|
||||
"""
|
||||
w = []
|
||||
for i in range(self.count()):
|
||||
w.append(self.widget(i))
|
||||
@ -227,7 +227,7 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
except TypeError as e:
|
||||
log.destroy.debug("Error while shutting down tabs: {}: {}".format(
|
||||
e.__class__.__name__, e))
|
||||
for tab in self.widgets:
|
||||
for tab in self.widgets():
|
||||
self._remove_tab(tab)
|
||||
|
||||
def close_tab(self, tab):
|
||||
@ -413,7 +413,7 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
tab.on_config_changed(section, option)
|
||||
if (section, option) == ('tabbar', 'show-favicons'):
|
||||
show = config.get('tabs', 'show-favicons')
|
||||
for i, tab in enumerate(self.widgets):
|
||||
for i, tab in enumerate(self.widgets()):
|
||||
if show:
|
||||
self.setTabIcon(i, tab.icon())
|
||||
else:
|
||||
|
@ -50,15 +50,14 @@ class WebView(QWebView):
|
||||
scroll_pos: The current scroll position as (x%, y%) tuple.
|
||||
statusbar_message: The current javscript statusbar message.
|
||||
inspector: The QWebInspector used for this webview.
|
||||
load_status: loading status of this page (index into LoadStatus)
|
||||
open_target: Where to open the next tab ("normal", "tab", "tab_bg")
|
||||
_page: The QWebPage behind the view
|
||||
_cur_url: The current URL (accessed via cur_url property).
|
||||
_load_status: loading status of this page (index into LoadStatus)
|
||||
Accessed via load_status property.
|
||||
_has_ssl_errors: Whether SSL errors occured during loading.
|
||||
_zoom: A NeighborList with the zoom levels.
|
||||
_old_scroll_pos: The old scroll position.
|
||||
_force_open_target: Override for _open_target.
|
||||
_force_open_target: Override for open_target.
|
||||
_check_insertmode: If True, in mouseReleaseEvent we should check if we
|
||||
need to enter/leave insert mode.
|
||||
|
||||
@ -78,7 +77,6 @@ class WebView(QWebView):
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._load_status = None
|
||||
self.load_status = LoadStatus.none
|
||||
self._check_insertmode = False
|
||||
self.tabbedbrowser = parent
|
||||
@ -86,7 +84,6 @@ class WebView(QWebView):
|
||||
self.scroll_pos = (-1, -1)
|
||||
self.statusbar_message = ''
|
||||
self._old_scroll_pos = (-1, -1)
|
||||
self._open_target = None
|
||||
self.open_target = usertypes.ClickTarget.normal
|
||||
self._force_open_target = None
|
||||
self._zoom = None
|
||||
@ -116,25 +113,7 @@ class WebView(QWebView):
|
||||
url = self.url().toDisplayString()
|
||||
return "WebView(url='{}')".format(utils.elide(url, 50))
|
||||
|
||||
@property
|
||||
def open_target(self):
|
||||
"""Getter for open_target so we can define a setter."""
|
||||
return self._open_target
|
||||
|
||||
@open_target.setter
|
||||
def open_target(self, val):
|
||||
"""Setter for open_target to do type checking."""
|
||||
if not isinstance(val, usertypes.ClickTarget):
|
||||
raise TypeError("Target {} is no ClickTarget member!".format(val))
|
||||
self._open_target = val
|
||||
|
||||
@property
|
||||
def load_status(self):
|
||||
"""Getter for load_status."""
|
||||
return self._load_status
|
||||
|
||||
@load_status.setter
|
||||
def load_status(self, val):
|
||||
def _set_load_status(self, val):
|
||||
"""Setter for load_status.
|
||||
|
||||
Emit:
|
||||
@ -143,27 +122,9 @@ class WebView(QWebView):
|
||||
if not isinstance(val, LoadStatus):
|
||||
raise TypeError("Type {} is no LoadStatus member!".format(val))
|
||||
log.webview.debug("load status for {}: {}".format(repr(self), val))
|
||||
self._load_status = val
|
||||
self.load_status = val
|
||||
self.load_status_changed.emit(val.name)
|
||||
|
||||
@property
|
||||
def cur_url(self):
|
||||
"""Getter for cur_url so we can define a setter."""
|
||||
return self._cur_url
|
||||
|
||||
@cur_url.setter
|
||||
def cur_url(self, url):
|
||||
"""Setter for cur_url to emit a signal..
|
||||
|
||||
Arg:
|
||||
url: The new URL as a QUrl.
|
||||
|
||||
Emit:
|
||||
url_text_changed: Always emitted.
|
||||
"""
|
||||
self._cur_url = url
|
||||
self.url_text_changed.emit(url.toDisplayString())
|
||||
|
||||
def _init_neighborlist(self):
|
||||
"""Initialize the _zoom neighborlist."""
|
||||
levels = config.get('ui', 'zoom-levels')
|
||||
@ -302,6 +263,7 @@ class WebView(QWebView):
|
||||
log.webview.debug("New title: {}".format(urlstr))
|
||||
self.titleChanged.emit(urlstr)
|
||||
self.cur_url = url
|
||||
self.url_text_changed.emit(url.toDisplayString())
|
||||
return self.load(url)
|
||||
|
||||
def zoom_perc(self, perc, fuzzyval=True):
|
||||
@ -356,6 +318,7 @@ class WebView(QWebView):
|
||||
"""Update cur_url when URL has changed."""
|
||||
qtutils.ensure_valid(url)
|
||||
self.cur_url = url
|
||||
self.url_text_changed.emit(url.toDisplayString())
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def on_config_changed(self, section, option):
|
||||
@ -374,20 +337,20 @@ class WebView(QWebView):
|
||||
"""Leave insert/hint mode and set vars when a new page is loading."""
|
||||
self.progress = 0
|
||||
self._has_ssl_errors = False
|
||||
self.load_status = LoadStatus.loading
|
||||
self._set_load_status(LoadStatus.loading)
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def on_load_finished(self, ok):
|
||||
"""Handle auto-insert-mode after loading finished."""
|
||||
if ok and not self._has_ssl_errors:
|
||||
self.load_status = LoadStatus.success
|
||||
self._set_load_status(LoadStatus.success)
|
||||
elif ok:
|
||||
self.load_status = LoadStatus.warn
|
||||
self._set_load_status(LoadStatus.warn)
|
||||
else:
|
||||
self.load_status = LoadStatus.error
|
||||
self._set_load_status(LoadStatus.error)
|
||||
if not config.get('input', 'auto-insert-mode'):
|
||||
return
|
||||
if modeman.instance().mode == usertypes.KeyMode.insert or not ok:
|
||||
if modeman.instance().mode() == usertypes.KeyMode.insert or not ok:
|
||||
return
|
||||
frame = self.page().currentFrame()
|
||||
elem = frame.findFirstElement(':focus')
|
||||
@ -467,7 +430,7 @@ class WebView(QWebView):
|
||||
|
||||
This does the following things:
|
||||
- Check if a link was clicked with the middle button or Ctrl and
|
||||
set the _open_target attribute accordingly.
|
||||
set the open_target attribute accordingly.
|
||||
- Emit the editable_elem_selected signal if an editable element was
|
||||
clicked.
|
||||
|
||||
|
@ -376,9 +376,9 @@ def generate_settings(f):
|
||||
except KeyError:
|
||||
f.write(" * +{}+".format(val) + "\n")
|
||||
f.write("\n")
|
||||
if option.default:
|
||||
if option.default():
|
||||
f.write("Default: +pass:[{}]+\n".format(html.escape(
|
||||
option.default)))
|
||||
option.default())))
|
||||
else:
|
||||
f.write("Default: empty\n")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user