Merge pull request #2846 from rcorre/completion-fixes

Completion fixes
This commit is contained in:
Florian Bruhin 2017-07-24 07:27:11 +02:00 committed by GitHub
commit 837ee5c626
8 changed files with 40 additions and 60 deletions

View File

@ -109,8 +109,6 @@ class CompletionView(QTreeView):
super().__init__(parent) super().__init__(parent)
self.pattern = '' self.pattern = ''
self._win_id = win_id self._win_id = win_id
# FIXME handle new aliases.
# objreg.get('config').changed.connect(self.init_command_completion)
objreg.get('config').changed.connect(self._on_config_changed) objreg.get('config').changed.connect(self._on_config_changed)
self._active = False self._active = False
@ -297,6 +295,7 @@ class CompletionView(QTreeView):
self.pattern = pattern self.pattern = pattern
with debug.log_time(log.completion, 'Set pattern {}'.format(pattern)): with debug.log_time(log.completion, 'Set pattern {}'.format(pattern)):
self.model().set_pattern(pattern) self.model().set_pattern(pattern)
self.selectionModel().clear()
self._maybe_update_geometry() self._maybe_update_geometry()
self._maybe_show() self._maybe_show()

View File

@ -22,6 +22,7 @@
from PyQt5.QtCore import Qt, QModelIndex, QAbstractItemModel from PyQt5.QtCore import Qt, QModelIndex, QAbstractItemModel
from qutebrowser.utils import log, qtutils from qutebrowser.utils import log, qtutils
from qutebrowser.commands import cmdexc
class CompletionModel(QAbstractItemModel): class CompletionModel(QAbstractItemModel):
@ -219,6 +220,13 @@ class CompletionModel(QAbstractItemModel):
parent = index.parent() parent = index.parent()
cat = self._cat_from_idx(parent) cat = self._cat_from_idx(parent)
assert cat, "CompletionView sent invalid index for deletion" assert cat, "CompletionView sent invalid index for deletion"
if not cat.delete_func:
raise cmdexc.CommandError("Cannot delete this item.")
data = [cat.data(cat.index(index.row(), i))
for i in range(cat.columnCount())]
cat.delete_func(data)
self.beginRemoveRows(parent, index.row(), index.row()) self.beginRemoveRows(parent, index.row(), index.row())
cat.delete_cur_item(cat.index(index.row(), 0)) cat.removeRow(index.row(), QModelIndex())
self.endRemoveRows() self.endRemoveRows()

View File

@ -25,7 +25,6 @@ from PyQt5.QtSql import QSqlQueryModel
from qutebrowser.misc import sql from qutebrowser.misc import sql
from qutebrowser.utils import debug from qutebrowser.utils import debug
from qutebrowser.commands import cmdexc
from qutebrowser.config import config from qutebrowser.config import config
@ -90,14 +89,10 @@ class HistoryCategory(QSqlQueryModel):
self._query.run(pat=pattern) self._query.run(pat=pattern)
self.setQuery(self._query) self.setQuery(self._query)
def delete_cur_item(self, index): def removeRows(self, _row, _count, _parent=None):
"""Delete the row at the given index.""" """Override QAbstractItemModel::removeRows to re-run sql query."""
if not self.delete_func:
raise cmdexc.CommandError("Cannot delete this item.")
data = [self.data(index.sibling(index.row(), i))
for i in range(self.columnCount())]
self.delete_func(data)
# re-run query to reload updated table # re-run query to reload updated table
with debug.log_time('sql', 'Re-running completion query post-delete'): with debug.log_time('sql', 'Re-running completion query post-delete'):
self._query.run() self._query.run()
self.setQuery(self._query) self.setQuery(self._query)
return True

View File

@ -21,11 +21,10 @@
import re import re
from PyQt5.QtCore import Qt, QSortFilterProxyModel, QModelIndex, QRegExp from PyQt5.QtCore import Qt, QSortFilterProxyModel, QRegExp
from PyQt5.QtGui import QStandardItem, QStandardItemModel from PyQt5.QtGui import QStandardItem, QStandardItemModel
from qutebrowser.utils import qtutils from qutebrowser.utils import qtutils
from qutebrowser.commands import cmdexc
class ListCategory(QSortFilterProxyModel): class ListCategory(QSortFilterProxyModel):
@ -91,12 +90,3 @@ class ListCategory(QSortFilterProxyModel):
return False return False
else: else:
return left < right return left < right
def delete_cur_item(self, index):
"""Delete the row at the given index."""
if not self.delete_func:
raise cmdexc.CommandError("Cannot delete this item.")
data = [self.data(index.sibling(index.row(), i))
for i in range(self.columnCount())]
self.delete_func(data)
self.removeRow(index.row(), QModelIndex())

View File

@ -28,6 +28,7 @@ from PyQt5.QtCore import QModelIndex
from qutebrowser.completion.models import completionmodel, listcategory from qutebrowser.completion.models import completionmodel, listcategory
from qutebrowser.utils import qtutils from qutebrowser.utils import qtutils
from qutebrowser.commands import cmdexc
@hypothesis.given(strategies.lists(min_size=0, max_size=3, @hypothesis.given(strategies.lists(min_size=0, max_size=3,
@ -92,8 +93,25 @@ def test_delete_cur_item():
func.assert_called_once_with(['foo', 'bar']) func.assert_called_once_with(['foo', 'bar'])
def test_delete_cur_item_no_func():
callback = mock.Mock(spec=[])
model = completionmodel.CompletionModel()
cat = listcategory.ListCategory('', [('foo', 'bar')], delete_func=None)
model.rowsAboutToBeRemoved.connect(callback)
model.rowsRemoved.connect(callback)
model.add_category(cat)
parent = model.index(0, 0)
with pytest.raises(cmdexc.CommandError):
model.delete_cur_item(model.index(0, 0, parent))
assert not callback.called
def test_delete_cur_item_no_cat(): def test_delete_cur_item_no_cat():
"""Test completion_item_del with no selected category.""" """Test completion_item_del with no selected category."""
callback = mock.Mock(spec=[])
model = completionmodel.CompletionModel() model = completionmodel.CompletionModel()
model.rowsAboutToBeRemoved.connect(callback)
model.rowsRemoved.connect(callback)
with pytest.raises(qtutils.QtValueError): with pytest.raises(qtutils.QtValueError):
model.delete_cur_item(QModelIndex()) model.delete_cur_item(QModelIndex())
assert not callback.called

View File

@ -87,6 +87,7 @@ def test_set_pattern(completionview):
completionview.set_model(model) completionview.set_model(model)
completionview.set_pattern('foo') completionview.set_pattern('foo')
model.set_pattern.assert_called_with('foo') model.set_pattern.assert_called_with('foo')
assert not completionview.selectionModel().currentIndex().isValid()
def test_set_pattern_no_model(completionview): def test_set_pattern_no_model(completionview):

View File

@ -19,14 +19,13 @@
"""Test the web history completion category.""" """Test the web history completion category."""
import unittest.mock
import datetime import datetime
import pytest import pytest
from PyQt5.QtCore import QModelIndex
from qutebrowser.misc import sql from qutebrowser.misc import sql
from qutebrowser.completion.models import histcategory from qutebrowser.completion.models import histcategory
from qutebrowser.commands import cmdexc
@pytest.fixture @pytest.fixture
@ -140,20 +139,13 @@ def test_sorting(max_items, before, after, model_validator, hist, config_stub):
model_validator.validate(after) model_validator.validate(after)
def test_delete_cur_item(hist): def test_remove_rows(hist, model_validator):
hist.insert({'url': 'foo', 'title': 'Foo'}) hist.insert({'url': 'foo', 'title': 'Foo'})
hist.insert({'url': 'bar', 'title': 'Bar'}) hist.insert({'url': 'bar', 'title': 'Bar'})
func = unittest.mock.Mock(spec=[])
cat = histcategory.HistoryCategory(delete_func=func)
cat.set_pattern('')
cat.delete_cur_item(cat.index(0, 0))
func.assert_called_with(['foo', 'Foo', ''])
def test_delete_cur_item_no_func(hist):
hist.insert({'url': 'foo', 'title': 1})
hist.insert({'url': 'bar', 'title': 2})
cat = histcategory.HistoryCategory() cat = histcategory.HistoryCategory()
model_validator.set_model(cat)
cat.set_pattern('') cat.set_pattern('')
with pytest.raises(cmdexc.CommandError, match='Cannot delete this item'): hist.delete('url', 'foo')
cat.delete_cur_item(cat.index(0, 0)) # histcategory does not care which index was removed, it just regenerates
cat.removeRows(QModelIndex(), 1)
model_validator.validate([('bar', 'Bar', '')])

View File

@ -19,12 +19,9 @@
"""Tests for CompletionFilterModel.""" """Tests for CompletionFilterModel."""
from unittest import mock
import pytest import pytest
from qutebrowser.completion.models import listcategory from qutebrowser.completion.models import listcategory
from qutebrowser.commands import cmdexc
@pytest.mark.parametrize('pattern, before, after', [ @pytest.mark.parametrize('pattern, before, after', [
@ -51,23 +48,3 @@ def test_set_pattern(pattern, before, after, model_validator):
model_validator.set_model(cat) model_validator.set_model(cat)
cat.set_pattern(pattern) cat.set_pattern(pattern)
model_validator.validate(after) model_validator.validate(after)
def test_delete_cur_item(model_validator):
func = mock.Mock(spec=[])
cat = listcategory.ListCategory('Foo', [('a', 'b'), ('c', 'd')],
delete_func=func)
model_validator.set_model(cat)
idx = cat.index(0, 0)
cat.delete_cur_item(idx)
func.assert_called_once_with(['a', 'b'])
model_validator.validate([('c', 'd')])
def test_delete_cur_item_no_func(model_validator):
cat = listcategory.ListCategory('Foo', [('a', 'b'), ('c', 'd')])
model_validator.set_model(cat)
idx = cat.index(0, 0)
with pytest.raises(cmdexc.CommandError, match="Cannot delete this item."):
cat.delete_cur_item(idx)
model_validator.validate([('a', 'b'), ('c', 'd')])