Implement completion models as functions.
First step of Completion Model/View revamping (#74). Rewrite the completion models as functions that each return an instance of a CompletionModel class. Caching is removed from all models except the UrlModel. Models other than the UrlModel can be generated very quickly so caching just adds needless complexity and can lead to incorrect results if one forgets to wire up a signal.
This commit is contained in:
parent
bef372e5f5
commit
08bb3f4f19
@ -72,20 +72,7 @@ class Completer(QObject):
|
||||
Return:
|
||||
A completion model or None.
|
||||
"""
|
||||
if completion == usertypes.Completion.option:
|
||||
section = pos_args[0]
|
||||
model = instances.get(completion).get(section)
|
||||
elif completion == usertypes.Completion.value:
|
||||
section = pos_args[0]
|
||||
option = pos_args[1]
|
||||
try:
|
||||
model = instances.get(completion)[section][option]
|
||||
except KeyError:
|
||||
# No completion model for this section/option.
|
||||
model = None
|
||||
else:
|
||||
model = instances.get(completion)
|
||||
|
||||
model = instances.get(completion)(*pos_args)
|
||||
if model is None:
|
||||
return None
|
||||
else:
|
||||
@ -109,7 +96,7 @@ class Completer(QObject):
|
||||
log.completion.debug("After removing flags: {}".format(before_cursor))
|
||||
if not before_cursor:
|
||||
# '|' or 'set|'
|
||||
model = instances.get(usertypes.Completion.command)
|
||||
model = instances.get(usertypes.Completion.command)()
|
||||
return sortfilter.CompletionFilterModel(source=model, parent=self)
|
||||
try:
|
||||
cmd = cmdutils.cmd_dict[before_cursor[0]]
|
||||
|
@ -28,7 +28,6 @@ from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel, QSize
|
||||
|
||||
from qutebrowser.config import config, style
|
||||
from qutebrowser.completion import completiondelegate
|
||||
from qutebrowser.completion.models import base
|
||||
from qutebrowser.utils import utils, usertypes, objreg
|
||||
from qutebrowser.commands import cmdexc, cmdutils
|
||||
|
||||
@ -112,7 +111,7 @@ class CompletionView(QTreeView):
|
||||
# objreg.get('config').changed.connect(self.init_command_completion)
|
||||
objreg.get('config').changed.connect(self._on_config_changed)
|
||||
|
||||
self._column_widths = base.BaseCompletionModel.COLUMN_WIDTHS
|
||||
self._column_widths = (30, 70, 0)
|
||||
self._active = False
|
||||
|
||||
self._delegate = completiondelegate.CompletionItemDelegate(self)
|
||||
@ -300,7 +299,7 @@ class CompletionView(QTreeView):
|
||||
if pattern is not None:
|
||||
model.set_pattern(pattern)
|
||||
|
||||
self._column_widths = model.srcmodel.COLUMN_WIDTHS
|
||||
self._column_widths = model.srcmodel.column_widths
|
||||
self._resize_columns()
|
||||
self._maybe_update_geometry()
|
||||
|
||||
|
@ -33,26 +33,27 @@ Role = usertypes.enum('Role', ['sort', 'userdata'], start=Qt.UserRole,
|
||||
is_int=True)
|
||||
|
||||
|
||||
class BaseCompletionModel(QStandardItemModel):
|
||||
class CompletionModel(QStandardItemModel):
|
||||
|
||||
"""A simple QStandardItemModel adopted for completions.
|
||||
|
||||
Used for showing completions later in the CompletionView. Supports setting
|
||||
marks and adding new categories/items easily.
|
||||
|
||||
Class Attributes:
|
||||
COLUMN_WIDTHS: The width percentages of the columns used in the
|
||||
completion view.
|
||||
DUMB_SORT: the dumb sorting used by the model
|
||||
Attributes:
|
||||
column_widths: The width percentages of the columns used in the
|
||||
completion view.
|
||||
dumb_sort: the dumb sorting used by the model
|
||||
"""
|
||||
|
||||
COLUMN_WIDTHS = (30, 70, 0)
|
||||
DUMB_SORT = None
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, dumb_sort=None, column_widths=(30, 70, 0),
|
||||
columns_to_filter=None, delete_cur_item=None, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setColumnCount(3)
|
||||
self.columns_to_filter = [0]
|
||||
self.columns_to_filter = columns_to_filter or [0]
|
||||
self.dumb_sort = dumb_sort
|
||||
self.column_widths = column_widths
|
||||
self.delete_cur_item = delete_cur_item
|
||||
|
||||
def new_category(self, name, sort=None):
|
||||
"""Add a new category to the model.
|
||||
@ -103,10 +104,6 @@ class BaseCompletionModel(QStandardItemModel):
|
||||
nameitem.setData(userdata, Role.userdata)
|
||||
return nameitem, descitem, miscitem
|
||||
|
||||
def delete_cur_item(self, completion):
|
||||
"""Delete the selected item."""
|
||||
raise NotImplementedError
|
||||
|
||||
def flags(self, index):
|
||||
"""Return the item flags for index.
|
||||
|
||||
|
@ -17,142 +17,75 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""CompletionModels for the config."""
|
||||
"""Functions that return config-related completion models."""
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot, Qt
|
||||
|
||||
from qutebrowser.config import config, configdata
|
||||
from qutebrowser.utils import log, qtutils, objreg
|
||||
from qutebrowser.config import config, configdata, configexc
|
||||
from qutebrowser.completion.models import base
|
||||
|
||||
|
||||
class SettingSectionCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def section():
|
||||
"""A CompletionModel filled with settings sections."""
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
COLUMN_WIDTHS = (20, 70, 10)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
cat = self.new_category("Sections")
|
||||
for name in configdata.DATA:
|
||||
desc = configdata.SECTION_DESC[name].splitlines()[0].strip()
|
||||
self.new_item(cat, name, desc)
|
||||
model = base.CompletionModel(column_widths=(20, 70, 10))
|
||||
cat = model.new_category("Sections")
|
||||
for name in configdata.DATA:
|
||||
desc = configdata.SECTION_DESC[name].splitlines()[0].strip()
|
||||
model.new_item(cat, name, desc)
|
||||
return model
|
||||
|
||||
|
||||
class SettingOptionCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def option(sectname):
|
||||
"""A CompletionModel filled with settings and their descriptions.
|
||||
|
||||
Attributes:
|
||||
_misc_items: A dict of the misc. column items which will be set later.
|
||||
_section: The config section this model shows.
|
||||
Args:
|
||||
sectname: The name of the config section this model shows.
|
||||
"""
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
COLUMN_WIDTHS = (20, 70, 10)
|
||||
|
||||
def __init__(self, section, parent=None):
|
||||
super().__init__(parent)
|
||||
cat = self.new_category(section)
|
||||
sectdata = configdata.DATA[section]
|
||||
self._misc_items = {}
|
||||
self._section = section
|
||||
objreg.get('config').changed.connect(self.update_misc_column)
|
||||
for name in sectdata:
|
||||
try:
|
||||
desc = sectdata.descriptions[name]
|
||||
except (KeyError, AttributeError):
|
||||
# Some stuff (especially ValueList items) don't have a
|
||||
# description.
|
||||
desc = ""
|
||||
else:
|
||||
desc = desc.splitlines()[0]
|
||||
value = config.get(section, name, raw=True)
|
||||
_valitem, _descitem, miscitem = self.new_item(cat, name, desc,
|
||||
value)
|
||||
self._misc_items[name] = miscitem
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def update_misc_column(self, section, option):
|
||||
"""Update misc column when config changed."""
|
||||
if section != self._section:
|
||||
return
|
||||
model = base.CompletionModel(column_widths=(20, 70, 10))
|
||||
cat = model.new_category(sectname)
|
||||
try:
|
||||
sectdata = configdata.DATA[sectname]
|
||||
except KeyError:
|
||||
return None
|
||||
for name in sectdata:
|
||||
try:
|
||||
item = self._misc_items[option]
|
||||
except KeyError:
|
||||
log.completion.debug("Couldn't get item {}.{} from model!".format(
|
||||
section, option))
|
||||
# changed before init
|
||||
return
|
||||
val = config.get(section, option, raw=True)
|
||||
idx = item.index()
|
||||
qtutils.ensure_valid(idx)
|
||||
ok = self.setData(idx, val, Qt.DisplayRole)
|
||||
if not ok:
|
||||
raise ValueError("Setting data failed! (section: {}, option: {}, "
|
||||
"value: {})".format(section, option, val))
|
||||
desc = sectdata.descriptions[name]
|
||||
except (KeyError, AttributeError):
|
||||
# Some stuff (especially ValueList items) don't have a
|
||||
# description.
|
||||
desc = ""
|
||||
else:
|
||||
desc = desc.splitlines()[0]
|
||||
val = config.get(sectname, name, raw=True)
|
||||
model.new_item(cat, name, desc, val)
|
||||
return model
|
||||
|
||||
|
||||
class SettingValueCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def value(sectname, optname):
|
||||
"""A CompletionModel filled with setting values.
|
||||
|
||||
Attributes:
|
||||
_section: The config section this model shows.
|
||||
_option: The config option this model shows.
|
||||
Args:
|
||||
sectname: The name of the config section this model shows.
|
||||
optname: The name of the config option this model shows.
|
||||
"""
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
COLUMN_WIDTHS = (20, 70, 10)
|
||||
|
||||
def __init__(self, section, option, parent=None):
|
||||
super().__init__(parent)
|
||||
self._section = section
|
||||
self._option = option
|
||||
objreg.get('config').changed.connect(self.update_current_value)
|
||||
cur_cat = self.new_category("Current/Default", sort=0)
|
||||
value = config.get(section, option, raw=True)
|
||||
if not value:
|
||||
value = '""'
|
||||
self.cur_item, _descitem, _miscitem = self.new_item(cur_cat, value,
|
||||
"Current value")
|
||||
default_value = configdata.DATA[section][option].default()
|
||||
if not default_value:
|
||||
default_value = '""'
|
||||
self.new_item(cur_cat, default_value, "Default value")
|
||||
if hasattr(configdata.DATA[section], 'valtype'):
|
||||
# Same type for all values (ValueList)
|
||||
vals = configdata.DATA[section].valtype.complete()
|
||||
else:
|
||||
if option is None:
|
||||
raise ValueError("option may only be None for ValueList "
|
||||
"sections, but {} is not!".format(section))
|
||||
# Different type for each value (KeyValue)
|
||||
vals = configdata.DATA[section][option].typ.complete()
|
||||
if vals is not None:
|
||||
cat = self.new_category("Completions", sort=1)
|
||||
for (val, desc) in vals:
|
||||
self.new_item(cat, val, desc)
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def update_current_value(self, section, option):
|
||||
"""Update current value when config changed."""
|
||||
if (section, option) != (self._section, self._option):
|
||||
return
|
||||
value = config.get(section, option, raw=True)
|
||||
if not value:
|
||||
value = '""'
|
||||
idx = self.cur_item.index()
|
||||
qtutils.ensure_valid(idx)
|
||||
ok = self.setData(idx, value, Qt.DisplayRole)
|
||||
if not ok:
|
||||
raise ValueError("Setting data failed! (section: {}, option: {}, "
|
||||
"value: {})".format(section, option, value))
|
||||
model = base.CompletionModel(column_widths=(20, 70, 10))
|
||||
cur_cat = model.new_category("Current/Default", sort=0)
|
||||
try:
|
||||
val = config.get(sectname, optname, raw=True) or '""'
|
||||
except (configexc.NoSectionError, configexc.NoOptionError):
|
||||
return None
|
||||
model.new_item(cur_cat, val, "Current value")
|
||||
default_value = configdata.DATA[sectname][optname].default() or '""'
|
||||
model.new_item(cur_cat, default_value, "Default value")
|
||||
if hasattr(configdata.DATA[sectname], 'valtype'):
|
||||
# Same type for all values (ValueList)
|
||||
vals = configdata.DATA[sectname].valtype.complete()
|
||||
else:
|
||||
if optname is None:
|
||||
raise ValueError("optname may only be None for ValueList "
|
||||
"sections, but {} is not!".format(sectname))
|
||||
# Different type for each value (KeyValue)
|
||||
vals = configdata.DATA[sectname][optname].typ.complete()
|
||||
if vals is not None:
|
||||
cat = model.new_category("Completions", sort=1)
|
||||
for (val, desc) in vals:
|
||||
model.new_item(cat, val, desc)
|
||||
return model
|
||||
|
@ -17,180 +17,37 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Global instances of the completion models.
|
||||
|
||||
Module attributes:
|
||||
_instances: A dict of available completions.
|
||||
INITIALIZERS: A {usertypes.Completion: callable} dict of functions to
|
||||
initialize completions.
|
||||
"""
|
||||
|
||||
import functools
|
||||
"""Global instances of the completion models."""
|
||||
|
||||
from qutebrowser.utils import usertypes
|
||||
from qutebrowser.completion.models import miscmodels, urlmodel, configmodel
|
||||
from qutebrowser.utils import objreg, usertypes, log, debug
|
||||
from qutebrowser.config import configdata, config
|
||||
|
||||
|
||||
_instances = {}
|
||||
|
||||
|
||||
def _init_command_completion():
|
||||
"""Initialize the command completion model."""
|
||||
log.completion.debug("Initializing command completion.")
|
||||
model = miscmodels.CommandCompletionModel()
|
||||
_instances[usertypes.Completion.command] = model
|
||||
|
||||
|
||||
def _init_helptopic_completion():
|
||||
"""Initialize the helptopic completion model."""
|
||||
log.completion.debug("Initializing helptopic completion.")
|
||||
model = miscmodels.HelpCompletionModel()
|
||||
_instances[usertypes.Completion.helptopic] = model
|
||||
|
||||
|
||||
def _init_url_completion():
|
||||
"""Initialize the URL completion model."""
|
||||
log.completion.debug("Initializing URL completion.")
|
||||
with debug.log_time(log.completion, 'URL completion init'):
|
||||
model = urlmodel.UrlCompletionModel()
|
||||
_instances[usertypes.Completion.url] = model
|
||||
|
||||
|
||||
def _init_tab_completion():
|
||||
"""Initialize the tab completion model."""
|
||||
log.completion.debug("Initializing tab completion.")
|
||||
with debug.log_time(log.completion, 'tab completion init'):
|
||||
model = miscmodels.TabCompletionModel()
|
||||
_instances[usertypes.Completion.tab] = model
|
||||
|
||||
|
||||
def _init_setting_completions():
|
||||
"""Initialize setting completion models."""
|
||||
log.completion.debug("Initializing setting completion.")
|
||||
_instances[usertypes.Completion.section] = (
|
||||
configmodel.SettingSectionCompletionModel())
|
||||
_instances[usertypes.Completion.option] = {}
|
||||
_instances[usertypes.Completion.value] = {}
|
||||
for sectname in configdata.DATA:
|
||||
opt_model = configmodel.SettingOptionCompletionModel(sectname)
|
||||
_instances[usertypes.Completion.option][sectname] = opt_model
|
||||
_instances[usertypes.Completion.value][sectname] = {}
|
||||
for opt in configdata.DATA[sectname]:
|
||||
val_model = configmodel.SettingValueCompletionModel(sectname, opt)
|
||||
_instances[usertypes.Completion.value][sectname][opt] = val_model
|
||||
|
||||
|
||||
def init_quickmark_completions():
|
||||
"""Initialize quickmark completion models."""
|
||||
log.completion.debug("Initializing quickmark completion.")
|
||||
try:
|
||||
_instances[usertypes.Completion.quickmark_by_name].deleteLater()
|
||||
except KeyError:
|
||||
pass
|
||||
model = miscmodels.QuickmarkCompletionModel()
|
||||
_instances[usertypes.Completion.quickmark_by_name] = model
|
||||
|
||||
|
||||
def init_bookmark_completions():
|
||||
"""Initialize bookmark completion models."""
|
||||
log.completion.debug("Initializing bookmark completion.")
|
||||
try:
|
||||
_instances[usertypes.Completion.bookmark_by_url].deleteLater()
|
||||
except KeyError:
|
||||
pass
|
||||
model = miscmodels.BookmarkCompletionModel()
|
||||
_instances[usertypes.Completion.bookmark_by_url] = model
|
||||
|
||||
|
||||
def init_session_completion():
|
||||
"""Initialize session completion model."""
|
||||
log.completion.debug("Initializing session completion.")
|
||||
try:
|
||||
_instances[usertypes.Completion.sessions].deleteLater()
|
||||
except KeyError:
|
||||
pass
|
||||
model = miscmodels.SessionCompletionModel()
|
||||
_instances[usertypes.Completion.sessions] = model
|
||||
|
||||
|
||||
def _init_bind_completion():
|
||||
"""Initialize the command completion model."""
|
||||
log.completion.debug("Initializing bind completion.")
|
||||
model = miscmodels.BindCompletionModel()
|
||||
_instances[usertypes.Completion.bind] = model
|
||||
|
||||
|
||||
INITIALIZERS = {
|
||||
usertypes.Completion.command: _init_command_completion,
|
||||
usertypes.Completion.helptopic: _init_helptopic_completion,
|
||||
usertypes.Completion.url: _init_url_completion,
|
||||
usertypes.Completion.tab: _init_tab_completion,
|
||||
usertypes.Completion.section: _init_setting_completions,
|
||||
usertypes.Completion.option: _init_setting_completions,
|
||||
usertypes.Completion.value: _init_setting_completions,
|
||||
usertypes.Completion.quickmark_by_name: init_quickmark_completions,
|
||||
usertypes.Completion.bookmark_by_url: init_bookmark_completions,
|
||||
usertypes.Completion.sessions: init_session_completion,
|
||||
usertypes.Completion.bind: _init_bind_completion,
|
||||
}
|
||||
|
||||
|
||||
def get(completion):
|
||||
"""Get a certain completion. Initializes the completion if needed."""
|
||||
try:
|
||||
return _instances[completion]
|
||||
except KeyError:
|
||||
if completion in INITIALIZERS:
|
||||
INITIALIZERS[completion]()
|
||||
return _instances[completion]
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def update(completions):
|
||||
"""Update an already existing completion.
|
||||
|
||||
Args:
|
||||
completions: An iterable of usertypes.Completions.
|
||||
"""
|
||||
did_run = []
|
||||
for completion in completions:
|
||||
if completion in _instances:
|
||||
func = INITIALIZERS[completion]
|
||||
if func not in did_run:
|
||||
func()
|
||||
did_run.append(func)
|
||||
|
||||
|
||||
@config.change_filter('aliases', function=True)
|
||||
def _update_aliases():
|
||||
"""Update completions that include command aliases."""
|
||||
update([usertypes.Completion.command])
|
||||
if completion == usertypes.Completion.command:
|
||||
return miscmodels.command
|
||||
if completion == usertypes.Completion.helptopic:
|
||||
return miscmodels.helptopic
|
||||
if completion == usertypes.Completion.tab:
|
||||
return miscmodels.buffer
|
||||
if completion == usertypes.Completion.quickmark_by_name:
|
||||
return miscmodels.quickmark
|
||||
if completion == usertypes.Completion.bookmark_by_url:
|
||||
return miscmodels.bookmark
|
||||
if completion == usertypes.Completion.sessions:
|
||||
return miscmodels.session
|
||||
if completion == usertypes.Completion.bind:
|
||||
return miscmodels.bind
|
||||
if completion == usertypes.Completion.section:
|
||||
return configmodel.section
|
||||
if completion == usertypes.Completion.option:
|
||||
return configmodel.option
|
||||
if completion == usertypes.Completion.value:
|
||||
return configmodel.value
|
||||
if completion == usertypes.Completion.url:
|
||||
return urlmodel.url
|
||||
|
||||
|
||||
def init():
|
||||
"""Initialize completions. Note this only connects signals."""
|
||||
quickmark_manager = objreg.get('quickmark-manager')
|
||||
quickmark_manager.changed.connect(
|
||||
functools.partial(update, [usertypes.Completion.quickmark_by_name]))
|
||||
|
||||
bookmark_manager = objreg.get('bookmark-manager')
|
||||
bookmark_manager.changed.connect(
|
||||
functools.partial(update, [usertypes.Completion.bookmark_by_url]))
|
||||
|
||||
session_manager = objreg.get('session-manager')
|
||||
session_manager.update_completion.connect(
|
||||
functools.partial(update, [usertypes.Completion.sessions]))
|
||||
|
||||
history = objreg.get('web-history')
|
||||
history.async_read_done.connect(
|
||||
functools.partial(update, [usertypes.Completion.url]))
|
||||
|
||||
keyconf = objreg.get('key-config')
|
||||
keyconf.changed.connect(
|
||||
functools.partial(update, [usertypes.Completion.command]))
|
||||
keyconf.changed.connect(
|
||||
functools.partial(update, [usertypes.Completion.bind]))
|
||||
|
||||
objreg.get('config').changed.connect(_update_aliases)
|
||||
pass
|
||||
|
@ -17,252 +17,139 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Misc. CompletionModels."""
|
||||
"""Functions that return miscellaneous completion models."""
|
||||
|
||||
from PyQt5.QtCore import Qt, QTimer, pyqtSlot
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
from qutebrowser.browser import browsertab
|
||||
from qutebrowser.config import config, configdata
|
||||
from qutebrowser.utils import objreg, log, qtutils
|
||||
from qutebrowser.commands import cmdutils
|
||||
from qutebrowser.completion.models import base
|
||||
|
||||
|
||||
class CommandCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def command():
|
||||
"""A CompletionModel filled with non-hidden commands and descriptions."""
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
COLUMN_WIDTHS = (20, 60, 20)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
cmdlist = _get_cmd_completions(include_aliases=True,
|
||||
include_hidden=False)
|
||||
cat = self.new_category("Commands")
|
||||
for (name, desc, misc) in cmdlist:
|
||||
self.new_item(cat, name, desc, misc)
|
||||
model = base.CompletionModel(column_widths=(20, 60, 20))
|
||||
cmdlist = _get_cmd_completions(include_aliases=True, include_hidden=False)
|
||||
cat = model.new_category("Commands")
|
||||
for (name, desc, misc) in cmdlist:
|
||||
model.new_item(cat, name, desc, misc)
|
||||
return model
|
||||
|
||||
|
||||
class HelpCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def helptopic():
|
||||
"""A CompletionModel filled with help topics."""
|
||||
model = base.CompletionModel()
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
cmdlist = _get_cmd_completions(include_aliases=False, include_hidden=True,
|
||||
prefix=':')
|
||||
cat = model.new_category("Commands")
|
||||
for (name, desc, misc) in cmdlist:
|
||||
model.new_item(cat, name, desc, misc)
|
||||
|
||||
COLUMN_WIDTHS = (20, 60, 20)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._init_commands()
|
||||
self._init_settings()
|
||||
|
||||
def _init_commands(self):
|
||||
"""Fill completion with :command entries."""
|
||||
cmdlist = _get_cmd_completions(include_aliases=False,
|
||||
include_hidden=True, prefix=':')
|
||||
cat = self.new_category("Commands")
|
||||
for (name, desc, misc) in cmdlist:
|
||||
self.new_item(cat, name, desc, misc)
|
||||
|
||||
def _init_settings(self):
|
||||
"""Fill completion with section->option entries."""
|
||||
cat = self.new_category("Settings")
|
||||
for sectname, sectdata in configdata.DATA.items():
|
||||
for optname in sectdata:
|
||||
try:
|
||||
desc = sectdata.descriptions[optname]
|
||||
except (KeyError, AttributeError):
|
||||
# Some stuff (especially ValueList items) don't have a
|
||||
# description.
|
||||
desc = ""
|
||||
else:
|
||||
desc = desc.splitlines()[0]
|
||||
name = '{}->{}'.format(sectname, optname)
|
||||
self.new_item(cat, name, desc)
|
||||
cat = model.new_category("Settings")
|
||||
for sectname, sectdata in configdata.DATA.items():
|
||||
for optname in sectdata:
|
||||
try:
|
||||
desc = sectdata.descriptions[optname]
|
||||
except (KeyError, AttributeError):
|
||||
# Some stuff (especially ValueList items) don't have a
|
||||
# description.
|
||||
desc = ""
|
||||
else:
|
||||
desc = desc.splitlines()[0]
|
||||
name = '{}->{}'.format(sectname, optname)
|
||||
model.new_item(cat, name, desc)
|
||||
return model
|
||||
|
||||
|
||||
class QuickmarkCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def quickmark():
|
||||
"""A CompletionModel filled with all quickmarks."""
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
cat = self.new_category("Quickmarks")
|
||||
quickmarks = objreg.get('quickmark-manager').marks.items()
|
||||
for qm_name, qm_url in quickmarks:
|
||||
self.new_item(cat, qm_name, qm_url)
|
||||
model = base.CompletionModel()
|
||||
cat = model.new_category("Quickmarks")
|
||||
quickmarks = objreg.get('quickmark-manager').marks.items()
|
||||
for qm_name, qm_url in quickmarks:
|
||||
model.new_item(cat, qm_name, qm_url)
|
||||
return model
|
||||
|
||||
|
||||
class BookmarkCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def bookmark():
|
||||
"""A CompletionModel filled with all bookmarks."""
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
cat = self.new_category("Bookmarks")
|
||||
bookmarks = objreg.get('bookmark-manager').marks.items()
|
||||
for bm_url, bm_title in bookmarks:
|
||||
self.new_item(cat, bm_url, bm_title)
|
||||
model = base.CompletionModel()
|
||||
cat = model.new_category("Bookmarks")
|
||||
bookmarks = objreg.get('bookmark-manager').marks.items()
|
||||
for bm_url, bm_title in bookmarks:
|
||||
model.new_item(cat, bm_url, bm_title)
|
||||
return model
|
||||
|
||||
|
||||
class SessionCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def session():
|
||||
"""A CompletionModel filled with session names."""
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
cat = self.new_category("Sessions")
|
||||
try:
|
||||
for name in objreg.get('session-manager').list_sessions():
|
||||
if not name.startswith('_'):
|
||||
self.new_item(cat, name)
|
||||
except OSError:
|
||||
log.completion.exception("Failed to list sessions!")
|
||||
model = base.CompletionModel()
|
||||
cat = model.new_category("Sessions")
|
||||
try:
|
||||
for name in objreg.get('session-manager').list_sessions():
|
||||
if not name.startswith('_'):
|
||||
model.new_item(cat, name)
|
||||
except OSError:
|
||||
log.completion.exception("Failed to list sessions!")
|
||||
return model
|
||||
|
||||
|
||||
class TabCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
def buffer():
|
||||
"""A model to complete on open tabs across all windows.
|
||||
|
||||
Used for switching the buffer command.
|
||||
"""
|
||||
idx_column = 0
|
||||
url_column = 1
|
||||
text_column = 2
|
||||
|
||||
IDX_COLUMN = 0
|
||||
URL_COLUMN = 1
|
||||
TEXT_COLUMN = 2
|
||||
|
||||
COLUMN_WIDTHS = (6, 40, 54)
|
||||
DUMB_SORT = Qt.DescendingOrder
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.columns_to_filter = [self.IDX_COLUMN, self.URL_COLUMN,
|
||||
self.TEXT_COLUMN]
|
||||
|
||||
for win_id in objreg.window_registry:
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
for i in range(tabbed_browser.count()):
|
||||
tab = tabbed_browser.widget(i)
|
||||
tab.url_changed.connect(self.rebuild)
|
||||
tab.title_changed.connect(self.rebuild)
|
||||
tab.shutting_down.connect(self.delayed_rebuild)
|
||||
tabbed_browser.new_tab.connect(self.on_new_tab)
|
||||
tabbed_browser.tabBar().tabMoved.connect(self.rebuild)
|
||||
objreg.get("app").new_window.connect(self.on_new_window)
|
||||
self.rebuild()
|
||||
|
||||
def on_new_window(self, window):
|
||||
"""Add hooks to new windows."""
|
||||
window.tabbed_browser.new_tab.connect(self.on_new_tab)
|
||||
|
||||
@pyqtSlot(browsertab.AbstractTab)
|
||||
def on_new_tab(self, tab):
|
||||
"""Add hooks to new tabs."""
|
||||
tab.url_changed.connect(self.rebuild)
|
||||
tab.title_changed.connect(self.rebuild)
|
||||
tab.shutting_down.connect(self.delayed_rebuild)
|
||||
self.rebuild()
|
||||
|
||||
@pyqtSlot()
|
||||
def delayed_rebuild(self):
|
||||
"""Fire a rebuild indirectly so widgets get a chance to update."""
|
||||
QTimer.singleShot(0, self.rebuild)
|
||||
|
||||
@pyqtSlot()
|
||||
def rebuild(self):
|
||||
"""Rebuild completion model from current tabs.
|
||||
|
||||
Very lazy method of keeping the model up to date. We could connect to
|
||||
signals for new tab, tab url/title changed, tab close, tab moved and
|
||||
make sure we handled background loads too ... but iterating over a
|
||||
few/few dozen/few hundred tabs doesn't take very long at all.
|
||||
"""
|
||||
window_count = 0
|
||||
for win_id in objreg.window_registry:
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
if not tabbed_browser.shutting_down:
|
||||
window_count += 1
|
||||
|
||||
if window_count < self.rowCount():
|
||||
self.removeRows(window_count, self.rowCount() - window_count)
|
||||
|
||||
for i, win_id in enumerate(objreg.window_registry):
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
if tabbed_browser.shutting_down:
|
||||
continue
|
||||
if i >= self.rowCount():
|
||||
c = self.new_category("{}".format(win_id))
|
||||
else:
|
||||
c = self.item(i, 0)
|
||||
c.setData("{}".format(win_id), Qt.DisplayRole)
|
||||
if tabbed_browser.count() < c.rowCount():
|
||||
c.removeRows(tabbed_browser.count(),
|
||||
c.rowCount() - tabbed_browser.count())
|
||||
for idx in range(tabbed_browser.count()):
|
||||
tab = tabbed_browser.widget(idx)
|
||||
if idx >= c.rowCount():
|
||||
self.new_item(c, "{}/{}".format(win_id, idx + 1),
|
||||
tab.url().toDisplayString(),
|
||||
tabbed_browser.page_title(idx))
|
||||
else:
|
||||
c.child(idx, 0).setData("{}/{}".format(win_id, idx + 1),
|
||||
Qt.DisplayRole)
|
||||
c.child(idx, 1).setData(tab.url().toDisplayString(),
|
||||
Qt.DisplayRole)
|
||||
c.child(idx, 2).setData(tabbed_browser.page_title(idx),
|
||||
Qt.DisplayRole)
|
||||
|
||||
def delete_cur_item(self, completion):
|
||||
"""Delete the selected item.
|
||||
|
||||
Args:
|
||||
completion: The Completion object to use.
|
||||
"""
|
||||
def delete_buffer(completion):
|
||||
"""Close the selected tab."""
|
||||
index = completion.currentIndex()
|
||||
qtutils.ensure_valid(index)
|
||||
category = index.parent()
|
||||
qtutils.ensure_valid(category)
|
||||
index = category.child(index.row(), self.IDX_COLUMN)
|
||||
index = category.child(index.row(), idx_column)
|
||||
win_id, tab_index = index.data().split('/')
|
||||
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=int(win_id))
|
||||
tabbed_browser.on_tab_close_requested(int(tab_index) - 1)
|
||||
|
||||
model = base.CompletionModel(
|
||||
column_widths=(6, 40, 54),
|
||||
dumb_sort=Qt.DescendingOrder,
|
||||
delete_cur_item=delete_buffer,
|
||||
columns_to_filter=[idx_column, url_column, text_column])
|
||||
|
||||
class BindCompletionModel(base.BaseCompletionModel):
|
||||
for win_id in objreg.window_registry:
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
if tabbed_browser.shutting_down:
|
||||
continue
|
||||
c = model.new_category("{}".format(win_id))
|
||||
for idx in range(tabbed_browser.count()):
|
||||
tab = tabbed_browser.widget(idx)
|
||||
model.new_item(c, "{}/{}".format(win_id, idx + 1),
|
||||
tab.url().toDisplayString(),
|
||||
tabbed_browser.page_title(idx))
|
||||
return model
|
||||
|
||||
"""A CompletionModel filled with all bindable commands and descriptions."""
|
||||
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/545
|
||||
# pylint: disable=abstract-method
|
||||
def bind(_):
|
||||
"""A CompletionModel filled with all bindable commands and descriptions.
|
||||
|
||||
COLUMN_WIDTHS = (20, 60, 20)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
cmdlist = _get_cmd_completions(include_hidden=True,
|
||||
include_aliases=True)
|
||||
cat = self.new_category("Commands")
|
||||
for (name, desc, misc) in cmdlist:
|
||||
self.new_item(cat, name, desc, misc)
|
||||
Args:
|
||||
_: the key being bound.
|
||||
"""
|
||||
# TODO: offer a 'Current binding' completion based on the key.
|
||||
model = base.CompletionModel(column_widths=(20, 60, 20))
|
||||
cmdlist = _get_cmd_completions(include_hidden=True, include_aliases=True)
|
||||
cat = model.new_category("Commands")
|
||||
for (name, desc, misc) in cmdlist:
|
||||
model.new_item(cat, name, desc, misc)
|
||||
return model
|
||||
|
||||
|
||||
def _get_cmd_completions(include_hidden, include_aliases, prefix=''):
|
||||
|
@ -50,7 +50,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
||||
self.pattern = ''
|
||||
self.pattern_re = None
|
||||
|
||||
dumb_sort = self.srcmodel.DUMB_SORT
|
||||
dumb_sort = self.srcmodel.dumb_sort
|
||||
if dumb_sort is None:
|
||||
# pylint: disable=invalid-name
|
||||
self.lessThan = self.intelligentLessThan
|
||||
|
@ -17,7 +17,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""CompletionModels for URLs."""
|
||||
"""Function to return the url completion model for the `open` command."""
|
||||
|
||||
import datetime
|
||||
|
||||
@ -27,166 +27,172 @@ from qutebrowser.utils import objreg, utils, qtutils, log
|
||||
from qutebrowser.completion.models import base
|
||||
from qutebrowser.config import config
|
||||
|
||||
_URL_COLUMN = 0
|
||||
_TEXT_COLUMN = 1
|
||||
_TIME_COLUMN = 2
|
||||
_model = None
|
||||
_history_cat = None
|
||||
_quickmark_cat = None
|
||||
_bookmark_cat = None
|
||||
|
||||
class UrlCompletionModel(base.BaseCompletionModel):
|
||||
|
||||
"""A model which combines bookmarks, quickmarks and web history URLs.
|
||||
def _delete_url(completion):
|
||||
index = completion.currentIndex()
|
||||
qtutils.ensure_valid(index)
|
||||
category = index.parent()
|
||||
index = category.child(index.row(), _URL_COLUMN)
|
||||
qtutils.ensure_valid(category)
|
||||
if category.data() == 'Bookmarks':
|
||||
bookmark_manager = objreg.get('bookmark-manager')
|
||||
bookmark_manager.delete(index.data())
|
||||
elif category.data() == 'Quickmarks':
|
||||
quickmark_manager = objreg.get('quickmark-manager')
|
||||
sibling = index.sibling(index.row(), _TEXT_COLUMN)
|
||||
qtutils.ensure_valid(sibling)
|
||||
name = sibling.data()
|
||||
quickmark_manager.delete(name)
|
||||
|
||||
|
||||
def _remove_oldest_history():
|
||||
"""Remove the oldest history entry."""
|
||||
_history_cat.removeRow(0)
|
||||
|
||||
|
||||
def _add_history_entry(entry):
|
||||
"""Add a new history entry to the completion."""
|
||||
_model.new_item(_history_cat, entry.url.toDisplayString(),
|
||||
entry.title, _fmt_atime(entry.atime),
|
||||
sort=int(entry.atime), userdata=entry.url)
|
||||
|
||||
max_history = config.get('completion', 'web-history-max-items')
|
||||
if max_history != -1 and _history_cat.rowCount() > max_history:
|
||||
_remove_oldest_history()
|
||||
|
||||
|
||||
@config.change_filter('completion', 'timestamp-format')
|
||||
def _reformat_timestamps():
|
||||
"""Reformat the timestamps if the config option was changed."""
|
||||
for i in range(_history_cat.rowCount()):
|
||||
url_item = _history_cat.child(i, _URL_COLUMN)
|
||||
atime_item = _history_cat.child(i, _TIME_COLUMN)
|
||||
atime = url_item.data(base.Role.sort)
|
||||
atime_item.setText(_fmt_atime(atime))
|
||||
|
||||
|
||||
@pyqtSlot(object)
|
||||
def _on_history_item_added(entry):
|
||||
"""Slot called when a new history item was added."""
|
||||
for i in range(_history_cat.rowCount()):
|
||||
url_item = _history_cat.child(i, _URL_COLUMN)
|
||||
atime_item = _history_cat.child(i, _TIME_COLUMN)
|
||||
title_item = _history_cat.child(i, _TEXT_COLUMN)
|
||||
if url_item.data(base.Role.userdata) == entry.url:
|
||||
atime_item.setText(_fmt_atime(entry.atime))
|
||||
title_item.setText(entry.title)
|
||||
url_item.setData(int(entry.atime), base.Role.sort)
|
||||
break
|
||||
else:
|
||||
_add_history_entry(entry)
|
||||
|
||||
|
||||
@pyqtSlot()
|
||||
def _on_history_cleared():
|
||||
_history_cat.removeRows(0, _history_cat.rowCount())
|
||||
|
||||
|
||||
def _remove_item(data, category, column):
|
||||
"""Helper function for on_quickmark_removed and on_bookmark_removed.
|
||||
|
||||
Args:
|
||||
data: The item to search for.
|
||||
category: The category to search in.
|
||||
column: The column to use for matching.
|
||||
"""
|
||||
for i in range(category.rowCount()):
|
||||
item = category.child(i, column)
|
||||
if item.data(Qt.DisplayRole) == data:
|
||||
category.removeRow(i)
|
||||
break
|
||||
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _on_quickmark_removed(name):
|
||||
"""Called when a quickmark has been removed by the user.
|
||||
|
||||
Args:
|
||||
name: The name of the quickmark which has been removed.
|
||||
"""
|
||||
_remove_item(name, _quickmark_cat, _TEXT_COLUMN)
|
||||
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _on_bookmark_removed(urltext):
|
||||
"""Called when a bookmark has been removed by the user.
|
||||
|
||||
Args:
|
||||
urltext: The url of the bookmark which has been removed.
|
||||
"""
|
||||
_remove_item(urltext, _bookmark_cat, _URL_COLUMN)
|
||||
|
||||
|
||||
def _fmt_atime(atime):
|
||||
"""Format an atime to a human-readable string."""
|
||||
fmt = config.get('completion', 'timestamp-format')
|
||||
if fmt is None:
|
||||
return ''
|
||||
try:
|
||||
dt = datetime.datetime.fromtimestamp(atime)
|
||||
except (ValueError, OSError, OverflowError):
|
||||
# Different errors which can occur for too large values...
|
||||
log.misc.error("Got invalid timestamp {}!".format(atime))
|
||||
return '(invalid)'
|
||||
else:
|
||||
return dt.strftime(fmt)
|
||||
|
||||
|
||||
def _init():
|
||||
global _model, _quickmark_cat, _bookmark_cat, _history_cat
|
||||
_model = base.CompletionModel(column_widths=(40, 50, 10),
|
||||
dumb_sort=Qt.DescendingOrder,
|
||||
delete_cur_item=_delete_url,
|
||||
columns_to_filter=[_URL_COLUMN,
|
||||
_TEXT_COLUMN])
|
||||
_quickmark_cat = _model.new_category("Quickmarks")
|
||||
_bookmark_cat = _model.new_category("Bookmarks")
|
||||
_history_cat = _model.new_category("History")
|
||||
|
||||
quickmark_manager = objreg.get('quickmark-manager')
|
||||
quickmarks = quickmark_manager.marks.items()
|
||||
for qm_name, qm_url in quickmarks:
|
||||
_model.new_item(_quickmark_cat, qm_url, qm_name)
|
||||
quickmark_manager.added.connect(
|
||||
lambda name, url: _model.new_item(_quickmark_cat, url, name))
|
||||
quickmark_manager.removed.connect(_on_quickmark_removed)
|
||||
|
||||
bookmark_manager = objreg.get('bookmark-manager')
|
||||
bookmarks = bookmark_manager.marks.items()
|
||||
for bm_url, bm_title in bookmarks:
|
||||
_model.new_item(_bookmark_cat, bm_url, bm_title)
|
||||
bookmark_manager.added.connect(
|
||||
lambda name, url: _model.new_item(_bookmark_cat, url, name))
|
||||
bookmark_manager.removed.connect(_on_bookmark_removed)
|
||||
|
||||
history = objreg.get('web-history')
|
||||
max_history = config.get('completion', 'web-history-max-items')
|
||||
for entry in utils.newest_slice(history, max_history):
|
||||
if not entry.redirect:
|
||||
_add_history_entry(entry)
|
||||
history.add_completion_item.connect(_on_history_item_added)
|
||||
history.cleared.connect(_on_history_cleared)
|
||||
|
||||
objreg.get('config').changed.connect(_reformat_timestamps)
|
||||
|
||||
|
||||
def url():
|
||||
"""A _model which combines bookmarks, quickmarks and web history URLs.
|
||||
|
||||
Used for the `open` command.
|
||||
"""
|
||||
|
||||
URL_COLUMN = 0
|
||||
TEXT_COLUMN = 1
|
||||
TIME_COLUMN = 2
|
||||
|
||||
COLUMN_WIDTHS = (40, 50, 10)
|
||||
DUMB_SORT = Qt.DescendingOrder
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.columns_to_filter = [self.URL_COLUMN, self.TEXT_COLUMN]
|
||||
|
||||
self._quickmark_cat = self.new_category("Quickmarks")
|
||||
self._bookmark_cat = self.new_category("Bookmarks")
|
||||
self._history_cat = self.new_category("History")
|
||||
|
||||
quickmark_manager = objreg.get('quickmark-manager')
|
||||
quickmarks = quickmark_manager.marks.items()
|
||||
for qm_name, qm_url in quickmarks:
|
||||
self.new_item(self._quickmark_cat, qm_url, qm_name)
|
||||
quickmark_manager.added.connect(
|
||||
lambda name, url: self.new_item(self._quickmark_cat, url, name))
|
||||
quickmark_manager.removed.connect(self.on_quickmark_removed)
|
||||
|
||||
bookmark_manager = objreg.get('bookmark-manager')
|
||||
bookmarks = bookmark_manager.marks.items()
|
||||
for bm_url, bm_title in bookmarks:
|
||||
self.new_item(self._bookmark_cat, bm_url, bm_title)
|
||||
bookmark_manager.added.connect(
|
||||
lambda name, url: self.new_item(self._bookmark_cat, url, name))
|
||||
bookmark_manager.removed.connect(self.on_bookmark_removed)
|
||||
|
||||
self._history = objreg.get('web-history')
|
||||
self._max_history = config.get('completion', 'web-history-max-items')
|
||||
history = utils.newest_slice(self._history, self._max_history)
|
||||
for entry in history:
|
||||
if not entry.redirect:
|
||||
self._add_history_entry(entry)
|
||||
self._history.add_completion_item.connect(self.on_history_item_added)
|
||||
self._history.cleared.connect(self.on_history_cleared)
|
||||
|
||||
objreg.get('config').changed.connect(self.reformat_timestamps)
|
||||
|
||||
def _fmt_atime(self, atime):
|
||||
"""Format an atime to a human-readable string."""
|
||||
fmt = config.get('completion', 'timestamp-format')
|
||||
if fmt is None:
|
||||
return ''
|
||||
try:
|
||||
dt = datetime.datetime.fromtimestamp(atime)
|
||||
except (ValueError, OSError, OverflowError):
|
||||
# Different errors which can occur for too large values...
|
||||
log.misc.error("Got invalid timestamp {}!".format(atime))
|
||||
return '(invalid)'
|
||||
else:
|
||||
return dt.strftime(fmt)
|
||||
|
||||
def _remove_oldest_history(self):
|
||||
"""Remove the oldest history entry."""
|
||||
self._history_cat.removeRow(0)
|
||||
|
||||
def _add_history_entry(self, entry):
|
||||
"""Add a new history entry to the completion."""
|
||||
self.new_item(self._history_cat, entry.url.toDisplayString(),
|
||||
entry.title,
|
||||
self._fmt_atime(entry.atime), sort=int(entry.atime),
|
||||
userdata=entry.url)
|
||||
|
||||
if (self._max_history != -1 and
|
||||
self._history_cat.rowCount() > self._max_history):
|
||||
self._remove_oldest_history()
|
||||
|
||||
@config.change_filter('completion', 'timestamp-format')
|
||||
def reformat_timestamps(self):
|
||||
"""Reformat the timestamps if the config option was changed."""
|
||||
for i in range(self._history_cat.rowCount()):
|
||||
url_item = self._history_cat.child(i, self.URL_COLUMN)
|
||||
atime_item = self._history_cat.child(i, self.TIME_COLUMN)
|
||||
atime = url_item.data(base.Role.sort)
|
||||
atime_item.setText(self._fmt_atime(atime))
|
||||
|
||||
@pyqtSlot(object)
|
||||
def on_history_item_added(self, entry):
|
||||
"""Slot called when a new history item was added."""
|
||||
for i in range(self._history_cat.rowCount()):
|
||||
url_item = self._history_cat.child(i, self.URL_COLUMN)
|
||||
atime_item = self._history_cat.child(i, self.TIME_COLUMN)
|
||||
title_item = self._history_cat.child(i, self.TEXT_COLUMN)
|
||||
url = url_item.data(base.Role.userdata)
|
||||
if url == entry.url:
|
||||
atime_item.setText(self._fmt_atime(entry.atime))
|
||||
title_item.setText(entry.title)
|
||||
url_item.setData(int(entry.atime), base.Role.sort)
|
||||
break
|
||||
else:
|
||||
self._add_history_entry(entry)
|
||||
|
||||
@pyqtSlot()
|
||||
def on_history_cleared(self):
|
||||
self._history_cat.removeRows(0, self._history_cat.rowCount())
|
||||
|
||||
def _remove_item(self, data, category, column):
|
||||
"""Helper function for on_quickmark_removed and on_bookmark_removed.
|
||||
|
||||
Args:
|
||||
data: The item to search for.
|
||||
category: The category to search in.
|
||||
column: The column to use for matching.
|
||||
"""
|
||||
for i in range(category.rowCount()):
|
||||
item = category.child(i, column)
|
||||
if item.data(Qt.DisplayRole) == data:
|
||||
category.removeRow(i)
|
||||
break
|
||||
|
||||
@pyqtSlot(str)
|
||||
def on_quickmark_removed(self, name):
|
||||
"""Called when a quickmark has been removed by the user.
|
||||
|
||||
Args:
|
||||
name: The name of the quickmark which has been removed.
|
||||
"""
|
||||
self._remove_item(name, self._quickmark_cat, self.TEXT_COLUMN)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def on_bookmark_removed(self, url):
|
||||
"""Called when a bookmark has been removed by the user.
|
||||
|
||||
Args:
|
||||
url: The url of the bookmark which has been removed.
|
||||
"""
|
||||
self._remove_item(url, self._bookmark_cat, self.URL_COLUMN)
|
||||
|
||||
def delete_cur_item(self, completion):
|
||||
"""Delete the selected item.
|
||||
|
||||
Args:
|
||||
completion: The Completion object to use.
|
||||
"""
|
||||
index = completion.currentIndex()
|
||||
qtutils.ensure_valid(index)
|
||||
category = index.parent()
|
||||
index = category.child(index.row(), self.URL_COLUMN)
|
||||
url = index.data()
|
||||
qtutils.ensure_valid(category)
|
||||
|
||||
if category.data() == 'Bookmarks':
|
||||
bookmark_manager = objreg.get('bookmark-manager')
|
||||
bookmark_manager.delete(url)
|
||||
elif category.data() == 'Quickmarks':
|
||||
quickmark_manager = objreg.get('quickmark-manager')
|
||||
sibling = index.sibling(index.row(), self.TEXT_COLUMN)
|
||||
qtutils.ensure_valid(sibling)
|
||||
name = sibling.data()
|
||||
quickmark_manager.delete(name)
|
||||
if not _model:
|
||||
_init()
|
||||
return _model
|
||||
|
@ -1,50 +0,0 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2015-2017 Alexander Cogneau <alexander.cogneau@gmail.com>
|
||||
#
|
||||
# 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.completion.models column widths."""
|
||||
|
||||
import pytest
|
||||
|
||||
from qutebrowser.completion.models.base import BaseCompletionModel
|
||||
from qutebrowser.completion.models.configmodel import (
|
||||
SettingOptionCompletionModel, SettingSectionCompletionModel,
|
||||
SettingValueCompletionModel)
|
||||
from qutebrowser.completion.models.miscmodels import (
|
||||
CommandCompletionModel, HelpCompletionModel, QuickmarkCompletionModel,
|
||||
BookmarkCompletionModel, SessionCompletionModel)
|
||||
from qutebrowser.completion.models.urlmodel import UrlCompletionModel
|
||||
|
||||
|
||||
CLASSES = [BaseCompletionModel, SettingOptionCompletionModel,
|
||||
SettingOptionCompletionModel, SettingSectionCompletionModel,
|
||||
SettingValueCompletionModel, CommandCompletionModel,
|
||||
HelpCompletionModel, QuickmarkCompletionModel,
|
||||
BookmarkCompletionModel, SessionCompletionModel, UrlCompletionModel]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model", CLASSES)
|
||||
def test_list_size(model):
|
||||
"""Test if there are 3 items in the COLUMN_WIDTHS property."""
|
||||
assert len(model.COLUMN_WIDTHS) == 3
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model", CLASSES)
|
||||
def test_column_width_sum(model):
|
||||
"""Test if the sum of the widths asserts to 100."""
|
||||
assert sum(model.COLUMN_WIDTHS) == 100
|
@ -34,11 +34,11 @@ class FakeCompletionModel(QStandardItemModel):
|
||||
|
||||
"""Stub for a completion model."""
|
||||
|
||||
DUMB_SORT = None
|
||||
|
||||
def __init__(self, kind, parent=None):
|
||||
def __init__(self, kind, *pos_args, parent=None):
|
||||
super().__init__(parent)
|
||||
self.kind = kind
|
||||
self.pos_args = [*pos_args]
|
||||
self.dumb_sort = None
|
||||
|
||||
|
||||
class CompletionWidgetStub(QObject):
|
||||
@ -74,17 +74,8 @@ def instances(monkeypatch):
|
||||
"""Mock the instances module so get returns a fake completion model."""
|
||||
# populate a model for each completion type, with a nested structure for
|
||||
# option and value completion
|
||||
instances = {kind: FakeCompletionModel(kind)
|
||||
for kind in usertypes.Completion}
|
||||
instances[usertypes.Completion.option] = {
|
||||
'general': FakeCompletionModel(usertypes.Completion.option),
|
||||
}
|
||||
instances[usertypes.Completion.value] = {
|
||||
'general': {
|
||||
'editor': FakeCompletionModel(usertypes.Completion.value),
|
||||
}
|
||||
}
|
||||
monkeypatch.setattr(completer, 'instances', instances)
|
||||
get = lambda kind: lambda *args: FakeCompletionModel(kind, *args)
|
||||
monkeypatch.setattr(completer, 'instances', get)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@ -140,47 +131,52 @@ def _set_cmd_prompt(cmd, txt):
|
||||
cmd.setCursorPosition(txt.index('|'))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('txt, kind, pattern', [
|
||||
(':nope|', usertypes.Completion.command, 'nope'),
|
||||
(':nope |', None, ''),
|
||||
(':set |', usertypes.Completion.section, ''),
|
||||
(':set gen|', usertypes.Completion.section, 'gen'),
|
||||
(':set general |', usertypes.Completion.option, ''),
|
||||
(':set what |', None, ''),
|
||||
(':set general editor |', usertypes.Completion.value, ''),
|
||||
(':set general editor gv|', usertypes.Completion.value, 'gv'),
|
||||
(':set general editor "gvim -f"|', usertypes.Completion.value, 'gvim -f'),
|
||||
(':set general editor "gvim |', usertypes.Completion.value, 'gvim'),
|
||||
(':set general huh |', None, ''),
|
||||
(':help |', usertypes.Completion.helptopic, ''),
|
||||
(':help |', usertypes.Completion.helptopic, ''),
|
||||
(':open |', usertypes.Completion.url, ''),
|
||||
(':bind |', None, ''),
|
||||
(':bind <c-x> |', usertypes.Completion.command, ''),
|
||||
(':bind <c-x> foo|', usertypes.Completion.command, 'foo'),
|
||||
(':bind <c-x>| foo', None, '<c-x>'),
|
||||
(':set| general ', usertypes.Completion.command, 'set'),
|
||||
(':|set general ', usertypes.Completion.command, 'set'),
|
||||
(':set gene|ral ignore-case', usertypes.Completion.section, 'general'),
|
||||
(':|', usertypes.Completion.command, ''),
|
||||
(': |', usertypes.Completion.command, ''),
|
||||
('/|', None, ''),
|
||||
(':open -t|', None, ''),
|
||||
(':open --tab|', None, ''),
|
||||
(':open -t |', usertypes.Completion.url, ''),
|
||||
(':open --tab |', usertypes.Completion.url, ''),
|
||||
(':open | -t', usertypes.Completion.url, ''),
|
||||
(':tab-detach |', None, ''),
|
||||
(':bind --mode=caret <c-x> |', usertypes.Completion.command, ''),
|
||||
@pytest.mark.parametrize('txt, kind, pattern, pos_args', [
|
||||
(':nope|', usertypes.Completion.command, 'nope', []),
|
||||
(':nope |', None, '', []),
|
||||
(':set |', usertypes.Completion.section, '', []),
|
||||
(':set gen|', usertypes.Completion.section, 'gen', []),
|
||||
(':set general |', usertypes.Completion.option, '', ['general']),
|
||||
(':set what |', usertypes.Completion.option, '', ['what']),
|
||||
(':set general editor |', usertypes.Completion.value, '',
|
||||
['general', 'editor']),
|
||||
(':set general editor gv|', usertypes.Completion.value, 'gv',
|
||||
['general', 'editor']),
|
||||
(':set general editor "gvim -f"|', usertypes.Completion.value, 'gvim -f',
|
||||
['general', 'editor']),
|
||||
(':set general editor "gvim |', usertypes.Completion.value, 'gvim',
|
||||
['general', 'editor']),
|
||||
(':set general huh |', usertypes.Completion.value, '', ['general', 'huh']),
|
||||
(':help |', usertypes.Completion.helptopic, '', []),
|
||||
(':help |', usertypes.Completion.helptopic, '', []),
|
||||
(':open |', usertypes.Completion.url, '', []),
|
||||
(':bind |', None, '', []),
|
||||
(':bind <c-x> |', usertypes.Completion.command, '', ['<c-x>']),
|
||||
(':bind <c-x> foo|', usertypes.Completion.command, 'foo', ['<c-x>']),
|
||||
(':bind <c-x>| foo', None, '<c-x>', []),
|
||||
(':set| general ', usertypes.Completion.command, 'set', []),
|
||||
(':|set general ', usertypes.Completion.command, 'set', []),
|
||||
(':set gene|ral ignore-case', usertypes.Completion.section, 'general', []),
|
||||
(':|', usertypes.Completion.command, '', []),
|
||||
(': |', usertypes.Completion.command, '', []),
|
||||
('/|', None, '', []),
|
||||
(':open -t|', None, '', []),
|
||||
(':open --tab|', None, '', []),
|
||||
(':open -t |', usertypes.Completion.url, '', []),
|
||||
(':open --tab |', usertypes.Completion.url, '', []),
|
||||
(':open | -t', usertypes.Completion.url, '', []),
|
||||
(':tab-detach |', None, '', []),
|
||||
(':bind --mode=caret <c-x> |', usertypes.Completion.command, '',
|
||||
['<c-x>']),
|
||||
pytest.param(':bind --mode caret <c-x> |', usertypes.Completion.command,
|
||||
'', marks=pytest.mark.xfail(reason='issue #74')),
|
||||
(':set -t -p |', usertypes.Completion.section, ''),
|
||||
(':open -- |', None, ''),
|
||||
(':gibberish nonesense |', None, ''),
|
||||
('/:help|', None, ''),
|
||||
'', [], marks=pytest.mark.xfail(reason='issue #74')),
|
||||
(':set -t -p |', usertypes.Completion.section, '', []),
|
||||
(':open -- |', None, '', []),
|
||||
(':gibberish nonesense |', None, '', []),
|
||||
('/:help|', None, '', []),
|
||||
('::bind|', usertypes.Completion.command, ':bind'),
|
||||
])
|
||||
def test_update_completion(txt, kind, pattern, status_command_stub,
|
||||
def test_update_completion(txt, kind, pattern, pos_args, status_command_stub,
|
||||
completer_obj, completion_widget_stub):
|
||||
"""Test setting the completion widget's model based on command text."""
|
||||
# this test uses | as a placeholder for the current cursor position
|
||||
@ -192,7 +188,9 @@ def test_update_completion(txt, kind, pattern, status_command_stub,
|
||||
if kind is None:
|
||||
assert args[0] is None
|
||||
else:
|
||||
assert args[0].srcmodel.kind == kind
|
||||
model = args[0].srcmodel
|
||||
assert model.kind == kind
|
||||
assert model.pos_args == pos_args
|
||||
assert args[1] == pattern
|
||||
|
||||
|
||||
|
@ -71,7 +71,7 @@ def completionview(qtbot, status_command_stub, config_stub, win_registry,
|
||||
|
||||
def test_set_model(completionview):
|
||||
"""Ensure set_model actually sets the model and expands all categories."""
|
||||
model = base.BaseCompletionModel()
|
||||
model = base.CompletionModel()
|
||||
filtermodel = sortfilter.CompletionFilterModel(model)
|
||||
for i in range(3):
|
||||
model.appendRow(QStandardItem(str(i)))
|
||||
@ -82,7 +82,7 @@ def test_set_model(completionview):
|
||||
|
||||
|
||||
def test_set_pattern(completionview):
|
||||
model = sortfilter.CompletionFilterModel(base.BaseCompletionModel())
|
||||
model = sortfilter.CompletionFilterModel(base.CompletionModel())
|
||||
model.set_pattern = unittest.mock.Mock()
|
||||
completionview.set_model(model, 'foo')
|
||||
model.set_pattern.assert_called_with('foo')
|
||||
@ -148,7 +148,7 @@ def test_completion_item_focus(which, tree, expected, completionview, qtbot):
|
||||
successive movement. None implies no signal should be
|
||||
emitted.
|
||||
"""
|
||||
model = base.BaseCompletionModel()
|
||||
model = base.CompletionModel()
|
||||
for catdata in tree:
|
||||
cat = QStandardItem()
|
||||
model.appendRow(cat)
|
||||
@ -176,7 +176,7 @@ def test_completion_item_focus_no_model(which, completionview, qtbot):
|
||||
"""
|
||||
with qtbot.assertNotEmitted(completionview.selection_changed):
|
||||
completionview.completion_item_focus(which)
|
||||
model = base.BaseCompletionModel()
|
||||
model = base.CompletionModel()
|
||||
filtermodel = sortfilter.CompletionFilterModel(model,
|
||||
parent=completionview)
|
||||
completionview.set_model(filtermodel)
|
||||
@ -200,7 +200,7 @@ def test_completion_show(show, rows, quick_complete, completionview,
|
||||
config_stub.data['completion']['show'] = show
|
||||
config_stub.data['completion']['quick-complete'] = quick_complete
|
||||
|
||||
model = base.BaseCompletionModel()
|
||||
model = base.CompletionModel()
|
||||
for name in rows:
|
||||
cat = QStandardItem()
|
||||
model.appendRow(cat)
|
||||
|
@ -56,6 +56,9 @@ def _check_completions(model, expected):
|
||||
misc = actual_cat.child(j, 2)
|
||||
actual_item = (name.text(), desc.text(), misc.text())
|
||||
assert actual_item in expected_cat
|
||||
# sanity-check the column_widths
|
||||
assert len(model.column_widths) == 3
|
||||
assert sum(model.column_widths) == 100
|
||||
|
||||
|
||||
def _patch_cmdutils(monkeypatch, stubs, symbol):
|
||||
@ -184,7 +187,7 @@ def test_command_completion(qtmodeltester, monkeypatch, stubs, config_stub,
|
||||
key_config_stub.set_bindings_for('normal', {'s': 'stop',
|
||||
'rr': 'roll',
|
||||
'ro': 'rock'})
|
||||
model = miscmodels.CommandCompletionModel()
|
||||
model = miscmodels.command()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -212,7 +215,7 @@ def test_help_completion(qtmodeltester, monkeypatch, stubs, key_config_stub):
|
||||
key_config_stub.set_bindings_for('normal', {'s': 'stop', 'rr': 'roll'})
|
||||
_patch_cmdutils(monkeypatch, stubs, module + '.cmdutils')
|
||||
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
|
||||
model = miscmodels.HelpCompletionModel()
|
||||
model = miscmodels.helptopic()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -236,7 +239,7 @@ def test_help_completion(qtmodeltester, monkeypatch, stubs, key_config_stub):
|
||||
|
||||
def test_quickmark_completion(qtmodeltester, quickmarks):
|
||||
"""Test the results of quickmark completion."""
|
||||
model = miscmodels.QuickmarkCompletionModel()
|
||||
model = miscmodels.quickmark()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -251,7 +254,7 @@ def test_quickmark_completion(qtmodeltester, quickmarks):
|
||||
|
||||
def test_bookmark_completion(qtmodeltester, bookmarks):
|
||||
"""Test the results of bookmark completion."""
|
||||
model = miscmodels.BookmarkCompletionModel()
|
||||
model = miscmodels.bookmark()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -275,7 +278,7 @@ def test_url_completion(qtmodeltester, config_stub, web_history, quickmarks,
|
||||
"""
|
||||
config_stub.data['completion'] = {'timestamp-format': '%Y-%m-%d',
|
||||
'web-history-max-items': 2}
|
||||
model = urlmodel.UrlCompletionModel()
|
||||
model = urlmodel.url()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -303,7 +306,7 @@ def test_url_completion_delete_bookmark(qtmodeltester, config_stub,
|
||||
"""Test deleting a bookmark from the url completion model."""
|
||||
config_stub.data['completion'] = {'timestamp-format': '%Y-%m-%d',
|
||||
'web-history-max-items': 2}
|
||||
model = urlmodel.UrlCompletionModel()
|
||||
model = urlmodel.url()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -321,7 +324,7 @@ def test_url_completion_delete_quickmark(qtmodeltester, config_stub,
|
||||
"""Test deleting a bookmark from the url completion model."""
|
||||
config_stub.data['completion'] = {'timestamp-format': '%Y-%m-%d',
|
||||
'web-history-max-items': 2}
|
||||
model = urlmodel.UrlCompletionModel()
|
||||
model = urlmodel.url()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -335,7 +338,7 @@ def test_url_completion_delete_quickmark(qtmodeltester, config_stub,
|
||||
|
||||
def test_session_completion(qtmodeltester, session_manager_stub):
|
||||
session_manager_stub.sessions = ['default', '1', '2']
|
||||
model = miscmodels.SessionCompletionModel()
|
||||
model = miscmodels.session()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -354,7 +357,7 @@ def test_tab_completion(qtmodeltester, fake_web_tab, app_stub, win_registry,
|
||||
tabbed_browser_stubs[1].tabs = [
|
||||
fake_web_tab(QUrl('https://wiki.archlinux.org'), 'ArchWiki', 0),
|
||||
]
|
||||
model = miscmodels.TabCompletionModel()
|
||||
model = miscmodels.buffer()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -381,7 +384,7 @@ def test_tab_completion_delete(qtmodeltester, fake_web_tab, qtbot, app_stub,
|
||||
tabbed_browser_stubs[1].tabs = [
|
||||
fake_web_tab(QUrl('https://wiki.archlinux.org'), 'ArchWiki', 0),
|
||||
]
|
||||
model = miscmodels.TabCompletionModel()
|
||||
model = miscmodels.buffer()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -398,7 +401,7 @@ def test_setting_section_completion(qtmodeltester, monkeypatch, stubs):
|
||||
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
|
||||
_patch_config_section_desc(monkeypatch, stubs,
|
||||
module + '.configdata.SECTION_DESC')
|
||||
model = configmodel.SettingSectionCompletionModel()
|
||||
model = configmodel.section()
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -418,7 +421,7 @@ def test_setting_option_completion(qtmodeltester, monkeypatch, stubs,
|
||||
config_stub.data = {'ui': {'gesture': 'off',
|
||||
'mind': 'on',
|
||||
'voice': 'sometimes'}}
|
||||
model = configmodel.SettingOptionCompletionModel('ui')
|
||||
model = configmodel.option('ui')
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -440,7 +443,7 @@ def test_setting_option_completion_valuelist(qtmodeltester, monkeypatch, stubs,
|
||||
'DEFAULT': 'https://duckduckgo.com/?q={}'
|
||||
}
|
||||
}
|
||||
model = configmodel.SettingOptionCompletionModel('searchengines')
|
||||
model = configmodel.option('searchengines')
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -454,7 +457,7 @@ def test_setting_value_completion(qtmodeltester, monkeypatch, stubs,
|
||||
module = 'qutebrowser.completion.models.configmodel'
|
||||
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
|
||||
config_stub.data = {'general': {'volume': '0'}}
|
||||
model = configmodel.SettingValueCompletionModel('general', 'volume')
|
||||
model = configmodel.value('general', 'volume')
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
@ -486,7 +489,7 @@ def test_bind_completion(qtmodeltester, monkeypatch, stubs, config_stub,
|
||||
key_config_stub.set_bindings_for('normal', {'s': 'stop',
|
||||
'rr': 'roll',
|
||||
'ro': 'rock'})
|
||||
model = miscmodels.BindCompletionModel()
|
||||
model = miscmodels.bind('s')
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
|
@ -33,7 +33,7 @@ def _create_model(data):
|
||||
tuple in the sub-list represents an item, and each value in the
|
||||
tuple represents the item data for that column
|
||||
"""
|
||||
model = base.BaseCompletionModel()
|
||||
model = base.CompletionModel()
|
||||
for catdata in data:
|
||||
cat = model.new_category('')
|
||||
for itemdata in catdata:
|
||||
@ -74,7 +74,7 @@ def _extract_model_data(model):
|
||||
('4', 'blah', False),
|
||||
])
|
||||
def test_filter_accepts_row(pattern, data, expected):
|
||||
source_model = base.BaseCompletionModel()
|
||||
source_model = base.CompletionModel()
|
||||
cat = source_model.new_category('test')
|
||||
source_model.new_item(cat, data)
|
||||
|
||||
@ -119,8 +119,8 @@ def test_first_last_item(tree, first, last):
|
||||
|
||||
def test_set_source_model():
|
||||
"""Ensure setSourceModel sets source_model and clears the pattern."""
|
||||
model1 = base.BaseCompletionModel()
|
||||
model2 = base.BaseCompletionModel()
|
||||
model1 = base.CompletionModel()
|
||||
model2 = base.CompletionModel()
|
||||
filter_model = sortfilter.CompletionFilterModel(model1)
|
||||
filter_model.set_pattern('foo')
|
||||
# sourceModel() is cached as srcmodel, so make sure both match
|
||||
@ -202,7 +202,7 @@ def test_count(tree, expected):
|
||||
def test_set_pattern(pattern, dumb_sort, filter_cols, before, after):
|
||||
"""Validate the filtering and sorting results of set_pattern."""
|
||||
model = _create_model(before)
|
||||
model.DUMB_SORT = dumb_sort
|
||||
model.dumb_sort = dumb_sort
|
||||
model.columns_to_filter = filter_cols
|
||||
filter_model = sortfilter.CompletionFilterModel(model)
|
||||
filter_model.set_pattern(pattern)
|
||||
|
Loading…
Reference in New Issue
Block a user