summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <git@the-compiler.org>2015-04-17 07:49:08 +0200
committerFlorian Bruhin <git@the-compiler.org>2015-04-17 07:51:21 +0200
commitffd1e673b311efb126edb23d22c46578407e1d03 (patch)
treefcaef5718df427920e42253cbdfa55f39d041b83
parent71ffe8f656a7d506739e5810538e4dbedc3524c7 (diff)
downloadqutebrowser-ffd1e673b311efb126edb23d22c46578407e1d03.tar.gz
qutebrowser-ffd1e673b311efb126edb23d22c46578407e1d03.zip
Get rid of SearchRunner.
A SearchRunner was per-mainwindow, which caused bugs when searching in a tab and in another before clearing the search. Instead we now split it between WebView/CommandDispatcher. Fixes #638.
-rw-r--r--qutebrowser/browser/commands.py68
-rw-r--r--qutebrowser/browser/webview.py35
-rw-r--r--qutebrowser/commands/runners.py99
-rw-r--r--qutebrowser/mainwindow/mainwindow.py9
-rw-r--r--qutebrowser/mainwindow/statusbar/command.py17
-rw-r--r--qutebrowser/mainwindow/tabbedbrowser.py30
6 files changed, 108 insertions, 150 deletions
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
index 93bed2b49..7349e9a03 100644
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -1076,3 +1076,71 @@ class CommandDispatcher:
elem.evaluateJavaScript("this.value='{}'".format(text))
except webelem.IsNullError:
raise cmdexc.CommandError("Element vanished while editing!")
+
+ @cmdutils.register(instance='command-dispatcher', scope='window',
+ maxsplit=0)
+ def search(self, text="", reverse=False):
+ """Search for a text on the current page. With no text, clear results.
+
+ Args:
+ text: The text to search for.
+ reverse: Reverse search direction.
+ """
+ view = self._current_widget()
+ 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)
+
+ 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
+
+ @cmdutils.register(instance='command-dispatcher', hide=True,
+ scope='window')
+ def search_next(self, count: {'special': 'count'}=1):
+ """Continue the search to the ([count]th) next term.
+
+ Args:
+ count: How many elements to ignore.
+ """
+ view = self._current_widget()
+ if view.search_text is not None:
+ for _ in range(count):
+ view.search(view.search_text, view.search_flags)
+
+ @cmdutils.register(instance='command-dispatcher', hide=True,
+ scope='window')
+ def search_prev(self, count: {'special': 'count'}=1):
+ """Continue the search to the ([count]th) previous term.
+
+ Args:
+ count: How many elements to ignore.
+ """
+ view = self._current_widget()
+ if view.search_text is None:
+ return
+ # 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)
diff --git a/qutebrowser/browser/webview.py b/qutebrowser/browser/webview.py
index ee88e4089..20733c33e 100644
--- a/qutebrowser/browser/webview.py
+++ b/qutebrowser/browser/webview.py
@@ -23,7 +23,7 @@ import sys
import itertools
import functools
-from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QTimer, QUrl
+from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QTimer, QUrl, QObject
from PyQt5.QtWidgets import QApplication, QStyleFactory
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWebKitWidgets import QWebView, QWebPage
@@ -62,6 +62,8 @@ class WebView(QWebView):
registry: The ObjectRegistry associated with this tab.
tab_id: The tab ID of the view.
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.
_cur_url: The current URL (accessed via cur_url property).
_has_ssl_errors: Whether SSL errors occurred during loading.
_zoom: A NeighborList with the zoom levels.
@@ -102,6 +104,8 @@ class WebView(QWebView):
self._zoom = None
self._has_ssl_errors = False
self.keep_icon = False
+ self.search_text = None
+ self.search_flags = 0
self.init_neighborlist()
cfg = objreg.get('config')
cfg.changed.connect(self.init_neighborlist)
@@ -436,6 +440,35 @@ class WebView(QWebView):
"left.".format(mode))
self.setFocusPolicy(Qt.WheelFocus)
+ def search(self, text, flags):
+ """Search for text in the current page.
+
+ Args:
+ text: The text to search for.
+ flags: The QWebPage::FindFlags.
+ """
+ log.webview.debug("Searching with text '{}' and flags "
+ "0x{:04x}.".format(text, int(flags)))
+ old_scroll_pos = self.scroll_pos
+ flags = QWebPage.FindFlags(flags)
+ found = self.findText(text, flags)
+ if not found and not flags & QWebPage.HighlightAllOccurrences and text:
+ message.error(self.win_id, "Text '{}' not found on "
+ "page!".format(text), immediately=True)
+ else:
+ backward = int(flags) & QWebPage.FindBackward
+
+ def check_scroll_pos():
+ """Check if the scroll position got smaller and show info."""
+ if not backward and self.scroll_pos < old_scroll_pos:
+ message.info(self.win_id, "Search hit BOTTOM, continuing "
+ "at TOP", immediately=True)
+ elif backward and self.scroll_pos > old_scroll_pos:
+ message.info(self.win_id, "Search hit TOP, continuing at "
+ "BOTTOM", immediately=True)
+ # We first want QWebPage to refresh.
+ QTimer.singleShot(0, check_scroll_pos)
+
def createWindow(self, wintype):
"""Called by Qt when a page wants to create a new window.
diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py
index 754bdb81c..f288d3742 100644
--- a/qutebrowser/commands/runners.py
+++ b/qutebrowser/commands/runners.py
@@ -21,8 +21,7 @@
import collections
-from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QUrl
-from PyQt5.QtWebKitWidgets import QWebPage
+from PyQt5.QtCore import pyqtSlot, QUrl, QObject
from qutebrowser.config import config, configexc
from qutebrowser.commands import cmdexc, cmdutils
@@ -56,102 +55,6 @@ def replace_variables(win_id, arglist):
return args
-class SearchRunner(QObject):
-
- """Run searches on web pages.
-
- Attributes:
- _text: The text from the last search.
- _flags: The flags from the last search.
-
- Signals:
- do_search: Emitted when a search should be started.
- arg 1: Search string.
- arg 2: Flags to use.
- """
-
- do_search = pyqtSignal(str, 'QWebPage::FindFlags')
-
- def __init__(self, parent=None):
- super().__init__(parent)
- self._text = None
- self._flags = 0
-
- def __repr__(self):
- return utils.get_repr(self, text=self._text, flags=self._flags)
-
- @pyqtSlot(str)
- @cmdutils.register(instance='search-runner', scope='window', maxsplit=0)
- def search(self, text="", reverse=False):
- """Search for a text on the current page. With no text, clear results.
-
- Args:
- text: The text to search for.
- reverse: Reverse search direction.
- """
- if self._text is not None and self._text != text:
- # We first clear the marked text, then the highlights
- self.do_search.emit('', 0)
- self.do_search.emit('', QWebPage.HighlightAllOccurrences)
- self._text = text
- self._flags = 0
- ignore_case = config.get('general', 'ignore-case')
- if ignore_case == 'smart':
- if not text.islower():
- self._flags |= QWebPage.FindCaseSensitively
- elif not ignore_case:
- self._flags |= QWebPage.FindCaseSensitively
- if config.get('general', 'wrap-search'):
- self._flags |= QWebPage.FindWrapsAroundDocument
- if reverse:
- self._flags |= QWebPage.FindBackward
- # We actually search *twice* - once to highlight everything, then again
- # to get a mark so we can navigate.
- self.do_search.emit(self._text, self._flags)
- self.do_search.emit(self._text, self._flags |
- QWebPage.HighlightAllOccurrences)
-
- @pyqtSlot(str)
- def search_rev(self, text):
- """Search for a text on a website in reverse direction.
-
- Args:
- text: The text to search for.
- """
- self.search(text, reverse=True)
-
- @cmdutils.register(instance='search-runner', hide=True, scope='window')
- def search_next(self, count: {'special': 'count'}=1):
- """Continue the search to the ([count]th) next term.
-
- Args:
- count: How many elements to ignore.
- """
- if self._text is not None:
- for _ in range(count):
- self.do_search.emit(self._text, self._flags)
-
- @cmdutils.register(instance='search-runner', hide=True, scope='window')
- def search_prev(self, count: {'special': 'count'}=1):
- """Continue the search to the ([count]th) previous term.
-
- Args:
- count: How many elements to ignore.
- """
- if self._text is None:
- return
- # 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
- for _ in range(count):
- self.do_search.emit(self._text, flags)
-
-
class CommandRunner(QObject):
"""Parse and run qutebrowser commandline commands.
diff --git a/qutebrowser/mainwindow/mainwindow.py b/qutebrowser/mainwindow/mainwindow.py
index b9e456b42..ef10dfd59 100644
--- a/qutebrowser/mainwindow/mainwindow.py
+++ b/qutebrowser/mainwindow/mainwindow.py
@@ -113,11 +113,6 @@ class MainWindow(QWidget):
self._commandrunner = runners.CommandRunner(self.win_id)
- log.init.debug("Initializing search...")
- search_runner = runners.SearchRunner(self)
- objreg.register('search-runner', search_runner, scope='window',
- window=self.win_id)
-
log.init.debug("Initializing modes...")
modeman.init(self.win_id, self)
@@ -212,7 +207,6 @@ class MainWindow(QWidget):
completion_obj = self._get_object('completion')
tabs = self._get_object('tabbed-browser')
cmd = self._get_object('status-command')
- search_runner = self._get_object('search-runner')
message_bridge = self._get_object('message-bridge')
mode_manager = self._get_object('mode-manager')
prompter = self._get_object('prompter')
@@ -231,10 +225,7 @@ class MainWindow(QWidget):
keyparsers[usertypes.KeyMode.normal].keystring_updated.connect(
status.keystring.setText)
cmd.got_cmd.connect(self._commandrunner.run_safely)
- cmd.got_search.connect(search_runner.search)
- cmd.got_search_rev.connect(search_runner.search_rev)
cmd.returnPressed.connect(tabs.on_cmd_return_pressed)
- search_runner.do_search.connect(tabs.search)
tabs.got_cmd.connect(self._commandrunner.run_safely)
# config
diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py
index 48a106793..0803cfd48 100644
--- a/qutebrowser/mainwindow/statusbar/command.py
+++ b/qutebrowser/mainwindow/statusbar/command.py
@@ -39,10 +39,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
Signals:
got_cmd: Emitted when a command is triggered by the user.
arg: The command string.
- got_search: Emitted when the user started a new search.
- arg: The search term.
- got_rev_search: Emitted when the user started a new reverse search.
- arg: The search term.
clear_completion_selection: Emitted before the completion widget is
hidden.
hide_completion: Emitted when the completion widget should be hidden.
@@ -52,8 +48,6 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
"""
got_cmd = pyqtSignal(str)
- got_search = pyqtSignal(str)
- got_search_rev = pyqtSignal(str)
clear_completion_selection = pyqtSignal()
hide_completion = pyqtSignal()
update_completion = pyqtSignal()
@@ -167,16 +161,15 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
modes=[usertypes.KeyMode.command], scope='window')
def command_accept(self):
"""Execute the command currently in the commandline."""
- signals = {
- ':': self.got_cmd,
- '/': self.got_search,
- '?': self.got_search_rev,
+ prefixes = {
+ ':': '',
+ '/': 'search ',
+ '?': 'search -r ',
}
text = self.text()
self.history.append(text)
modeman.leave(self._win_id, usertypes.KeyMode.command, 'cmd accept')
- if text[0] in signals:
- signals[text[0]].emit(text[1:])
+ self.got_cmd.emit(prefixes[text[0]] + text[1:])
@pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode):
diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py
index 4445f716c..5cef4711e 100644
--- a/qutebrowser/mainwindow/tabbedbrowser.py
+++ b/qutebrowser/mainwindow/tabbedbrowser.py
@@ -403,36 +403,6 @@ class TabbedBrowser(tabwidget.TabWidget):
self._tab_insert_idx_right))
return idx
- @pyqtSlot(str, int)
- def search(self, text, flags):
- """Search for text in the current page.
-
- Args:
- text: The text to search for.
- flags: The QWebPage::FindFlags.
- """
- log.webview.debug("Searching with text '{}' and flags "
- "0x{:04x}.".format(text, int(flags)))
- widget = self.currentWidget()
- old_scroll_pos = widget.scroll_pos
- found = widget.findText(text, flags)
- if not found and not flags & QWebPage.HighlightAllOccurrences and text:
- message.error(self._win_id, "Text '{}' not found on "
- "page!".format(text), immediately=True)
- else:
- backward = int(flags) & QWebPage.FindBackward
-
- def check_scroll_pos():
- """Check if the scroll position got smaller and show info."""
- if not backward and widget.scroll_pos < old_scroll_pos:
- message.info(self._win_id, "Search hit BOTTOM, continuing "
- "at TOP", immediately=True)
- elif backward and widget.scroll_pos > old_scroll_pos:
- message.info(self._win_id, "Search hit TOP, continuing at "
- "BOTTOM", immediately=True)
- # We first want QWebPage to refresh.
- QTimer.singleShot(0, check_scroll_pos)
-
@config.change_filter('tabs', 'show-favicons')
def update_favicons(self):
"""Update favicons when config was changed."""