Re-implement searching for QtWebKit

This commit is contained in:
Florian Bruhin 2016-07-04 11:23:46 +02:00
parent 515d16f137
commit 0b88c5d413
6 changed files with 126 additions and 64 deletions

View File

@ -1400,17 +1400,6 @@ class CommandDispatcher:
this.dispatchEvent(event);
""".format(webelem.javascript_escape(sel)))
def _clear_search(self, view, text):
"""Clear search string/highlights for the given view.
This does nothing if the view's search text is the same as the given
text.
"""
if view.search_text is not None and view.search_text != text:
# We first clear the marked text, then the highlights
view.search('', 0)
view.search('', QWebPage.HighlightAllOccurrences)
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0)
def search(self, text="", reverse=False):
@ -1421,27 +1410,18 @@ class CommandDispatcher:
reverse: Reverse search direction.
"""
self.set_mark("'")
view = self._current_widget()
self._clear_search(view, text)
flags = 0
ignore_case = config.get('general', 'ignore-case')
if ignore_case == 'smart':
if not text.islower():
flags |= QWebPage.FindCaseSensitively
elif not ignore_case:
flags |= QWebPage.FindCaseSensitively
if config.get('general', 'wrap-search'):
flags |= QWebPage.FindWrapsAroundDocument
if reverse:
flags |= QWebPage.FindBackward
# We actually search *twice* - once to highlight everything, then again
# to get a mark so we can navigate.
view.search(text, flags)
view.search(text, flags | QWebPage.HighlightAllOccurrences)
view.search_text = text
view.search_flags = flags
tab = self._current_widget()
tab.search.clear()
options = {
'ignore_case': config.get('general', 'ignore-case'),
'wrap': config.get('general', 'wrap-search'),
'reverse': reverse,
}
tab.search.search(text, **options)
self._tabbed_browser.search_text = text
self._tabbed_browser.search_flags = flags
self._tabbed_browser.search_options = options
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@ -1452,18 +1432,19 @@ class CommandDispatcher:
Args:
count: How many elements to ignore.
"""
tab = self._current_widget()
window_text = self._tabbed_browser.search_text
window_options = self._tabbed_browser.search_options
self.set_mark("'")
view = self._current_widget()
self._clear_search(view, self._tabbed_browser.search_text)
if window_text is not None and window_text != tab.search.text:
tab.search.clear()
tab.search.search(window_text, **window_options)
count -= 1
if self._tabbed_browser.search_text is not None:
view.search_text = self._tabbed_browser.search_text
view.search_flags = self._tabbed_browser.search_flags
view.search(view.search_text,
view.search_flags | QWebPage.HighlightAllOccurrences)
for _ in range(count):
view.search(view.search_text, view.search_flags)
for _ in range(count):
tab.search.next_result()
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@ -1474,25 +1455,19 @@ class CommandDispatcher:
Args:
count: How many elements to ignore.
"""
self.set_mark("'")
view = self._current_widget()
self._clear_search(view, self._tabbed_browser.search_text)
tab = self._current_widget()
window_text = self._tabbed_browser.search_text
window_options = self._tabbed_browser.search_options
self.set_mark("'")
if window_text is not None and window_text != tab.search.text:
tab.search.clear()
tab.search.search(window_text, **window_options)
count -= 1
if self._tabbed_browser.search_text is not None:
view.search_text = self._tabbed_browser.search_text
view.search_flags = self._tabbed_browser.search_flags
view.search(view.search_text,
view.search_flags | QWebPage.HighlightAllOccurrences)
# The int() here serves as a QFlags constructor to create a copy of the
# QFlags instance rather as a reference. I don't know why it works this
# way, but it does.
flags = int(view.search_flags)
if flags & QWebPage.FindBackward:
flags &= ~QWebPage.FindBackward
else:
flags |= QWebPage.FindBackward
for _ in range(count):
view.search(view.search_text, flags)
tab.search.prev_result()
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')

View File

@ -56,6 +56,46 @@ class WrapperLayout(QLayout):
self._widget.setGeometry(r)
class AbstractSearch(QObject):
"""Attribute of AbstractTab for doing searches.
Attributes:
widget: The underlying WebView widget.
text: The last thing this view was searched for.
_flags: The flags of the last search.
"""
def __init__(self, parent=None):
super().__init__(parent)
self.widget = None
self.text = None
self._flags = 0
def search(self, text, *, ignore_case=False, wrap=False):
"""Find the given text on the page.
Args:
text: The text to search for.
ignore_case: Search case-insensitively. (True/False/'smart')
wrap: Wrap around to the top when arriving at the bottom.
reverse: Reverse search direction.
"""
raise NotImplementedError
def clear(self):
"""Clear the current search."""
raise NotImplementedError
def prev_result(self):
"""Go to the previous result of the current search."""
raise NotImplementedError
def next_result(self):
"""Go to the next result of the current search."""
raise NotImplementedError
class AbstractZoom(QObject):
"""Attribute of AbstractTab for controlling zoom.
@ -357,6 +397,7 @@ class AbstractTab(QWidget):
# self.scroll = AbstractScroller(parent=self)
# self.caret = AbstractCaret(win_id=win_id, parent=self)
# self.zoom = AbstractZoom(win_id=win_id)
# self.search = AbstractSearch(parent=self)
self._layout = None
self._widget = None
self.keep_icon = False # FIXME:refactor get rid of this?
@ -368,6 +409,7 @@ class AbstractTab(QWidget):
self.scroll.widget = widget
self.caret.widget = widget
self.zoom.widget = widget
self.search.widget = widget
widget.mouse_wheel_zoom.connect(self.zoom.on_mouse_wheel_zoom)
widget.setParent(self)

View File

@ -31,6 +31,13 @@ from qutebrowser.browser import tab
from qutebrowser.utils import usertypes, qtutils
class WebEngineSearch(tab.AbstractSearch):
## TODO
pass
class WebEngineCaret(tab.AbstractCaret):
## TODO
@ -100,6 +107,7 @@ class WebEngineViewTab(tab.AbstractTab):
self.scroll = WebEngineScroller()
self.caret = WebEngineCaret(win_id=win_id, parent=self)
self.zoom = WebEngineZoom(win_id=win_id, parent=self)
self.search = WebEngineSearch(parent=self)
self._set_widget(widget)
self._connect_signals()

View File

@ -31,6 +31,46 @@ from qutebrowser.browser.webkit import webview
from qutebrowser.utils import qtutils, objreg, usertypes, utils
class WebViewSearch(tab.AbstractSearch):
def clear(self):
# We first clear the marked text, then the highlights
self.widget.search('', 0)
self.widget.search('', QWebPage.HighlightAllOccurrences)
def search(self, text, *, ignore_case=False, wrap=False, reverse=False):
flags = 0
if ignore_case == 'smart':
if not text.islower():
flags |= QWebPage.FindCaseSensitively
elif not ignore_case:
flags |= QWebPage.FindCaseSensitively
if wrap:
flags |= QWebPage.FindWrapsAroundDocument
if reverse:
flags |= QWebPage.FindBackward
# We actually search *twice* - once to highlight everything, then again
# to get a mark so we can navigate.
self.widget.search(text, flags)
self.widget.search(text, flags | QWebPage.HighlightAllOccurrences)
self.text = text
self._flags = flags
def next_result(self):
self.widget.search(self.text, self._flags)
def prev_result(self):
# The int() here serves as a QFlags constructor to create a copy of the
# QFlags instance rather as a reference. I don't know why it works this
# way, but it does.
flags = int(self._flags)
if flags & QWebPage.FindBackward:
flags &= ~QWebPage.FindBackward
else:
flags |= QWebPage.FindBackward
self.widget.search(self.text, flags)
class WebViewCaret(tab.AbstractCaret):
@pyqtSlot(usertypes.KeyMode)
@ -376,6 +416,7 @@ class WebViewTab(tab.AbstractTab):
self.scroll = WebViewScroller(parent=self)
self.caret = WebViewCaret(win_id=win_id, parent=self)
self.zoom = WebViewZoom(win_id=win_id, parent=self)
self.search = WebViewSearch(parent=self)
self._set_widget(widget)
self._connect_signals()
self.zoom._set_default_zoom()

View File

@ -54,8 +54,6 @@ class WebView(QWebView):
code.
registry: The ObjectRegistry associated with this tab.
win_id: The window ID of the view.
search_text: The text of the last search.
search_flags: The search flags of the last search.
_tab_id: The tab ID of the view.
_has_ssl_errors: Whether SSL errors occurred during loading.
_old_scroll_pos: The old scroll position.
@ -101,8 +99,6 @@ class WebView(QWebView):
self._has_ssl_errors = False
self._ignore_wheel_event = False
self.keep_icon = False
self.search_text = None
self.search_flags = 0
self._set_bg_color()
self.cur_url = QUrl()
self.progress = 0

View File

@ -57,8 +57,8 @@ class TabbedBrowser(tabwidget.TabWidget):
emitted if the signal occurred in the current tab.
Attributes:
search_text/search_flags: Search parameters which are shared between
all tabs.
search_text/search_options: Search parameters which are shared between
all tabs.
_win_id: The window ID this tabbedbrowser is associated with.
_filter: A SignalFilter instance.
_now_focused: The tab which is focused now.
@ -118,7 +118,7 @@ class TabbedBrowser(tabwidget.TabWidget):
self._filter = signalfilter.SignalFilter(win_id, self)
self._now_focused = None
self.search_text = None
self.search_flags = 0
self.search_options = {}
self._local_marks = {}
self._global_marks = {}
self.default_window_icon = self.window().windowIcon()