예제 #1
0
    def _start_cb(self, elems):
        """Initialize the elements and labels based on the context set."""
        filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True)
        elems = [e for e in elems if filterfunc(e)]
        if not elems:
            raise cmdexc.CommandError("No elements found.")
        strings = self._hint_strings(elems)
        log.hints.debug("hints: {}".format(', '.join(strings)))
        for e, string in zip(elems, strings):
            label = self._draw_label(e, string)
            elem = ElemTuple(e, label)
            self._context.all_elems.append(elem)
            self._context.elems[string] = elem
        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings)

        self._context.tab.contents_size_changed.connect(
            self.on_contents_size_changed)
        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')
예제 #2
0
파일: hints.py 프로젝트: melody40/monorepo
    def _start_cb(self, elems):
        """Initialize the elements and labels based on the context set."""
        if self._context is None:
            log.hints.debug("In _start_cb without context!")
            return

        if not elems:
            message.error("No elements found.")
            return

        strings = self._hint_strings(elems)
        log.hints.debug("hints: {}".format(', '.join(strings)))

        for elem, string in zip(elems, strings):
            label = HintLabel(elem, self._context)
            label.update_text('', string)
            self._context.all_labels.append(label)
            self._context.labels[string] = label

        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings)

        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')

        if self._context.first:
            self._fire(strings[0])
            return
        # to make auto_follow == 'always' work
        self._handle_auto_follow()
예제 #3
0
 def _on_clicked(self) -> None:
     """Enter insert mode if a docked inspector was clicked."""
     if self._position != Position.window:
         modeman.enter(self._win_id,
                       usertypes.KeyMode.insert,
                       reason='Inspector clicked',
                       only_if_normal=True)
예제 #4
0
 def _auto_insert_mode_cb(elem):
     """Called from JS after finding the focused element."""
     if elem is None:
         log.webview.debug("No focused element!")
         return
     if elem.is_editable():
         modeman.enter(self.win_id, usertypes.KeyMode.insert, "load finished", only_if_normal=True)
예제 #5
0
    def on_load_finished(self):
        """Handle auto-insert-mode after loading finished.

        We don't take loadFinished's ok argument here as it always seems to be
        true when the QWebPage has an ErrorPageExtension implemented.
        See https://github.com/The-Compiler/qutebrowser/issues/84
        """
        ok = not self.page().error_occured
        if ok and not self._has_ssl_errors:
            self._set_load_status(LoadStatus.success)
        elif ok:
            self._set_load_status(LoadStatus.warn)
        else:
            self._set_load_status(LoadStatus.error)
        if not config.get('input', 'auto-insert-mode'):
            return
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        cur_mode = mode_manager.mode
        if cur_mode == usertypes.KeyMode.insert or not ok:
            return
        frame = self.page().currentFrame()
        try:
            elem = webelem.WebElementWrapper(frame.findFirstElement(':focus'))
        except webelem.IsNullError:
            log.webview.debug("Focused element is null!")
            return
        log.modes.debug("focus element: {}".format(repr(elem)))
        if elem.is_editable():
            modeman.enter(self._win_id, usertypes.KeyMode.insert,
                          'load finished', only_if_normal=True)
예제 #6
0
 def eventFilter(self, _obj: QObject, event: QEvent) -> bool:
     """Enter insert mode if the inspector is clicked."""
     if event.type() == QEvent.MouseButtonPress:
         modeman.enter(self._win_id,
                       usertypes.KeyMode.insert,
                       reason='Inspector clicked')
     return False
예제 #7
0
    def click(self, click_target, *, force_event=False):
        """Simulate a click on the element.

        Args:
            click_target: A usertypes.ClickTarget member, what kind of click
                          to simulate.
            force_event: Force generating a fake mouse event.
        """
        if force_event:
            self._click_fake_event(click_target)
            return

        href_tags = ['a', 'area', 'link']
        if click_target == usertypes.ClickTarget.normal:
            if self.tag_name() in href_tags:
                log.webelem.debug("Clicking via JS click()")
                self._click_js(click_target)
            elif self.is_editable(strict=True):
                log.webelem.debug("Clicking via JS focus()")
                self._click_editable()
                modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                              'clicking input')
            else:
                self._click_fake_event(click_target)
        elif click_target in [
                usertypes.ClickTarget.tab, usertypes.ClickTarget.tab_bg,
                usertypes.ClickTarget.window
        ]:
            if self.tag_name() in href_tags:
                self._click_href(click_target)
            else:
                self._click_fake_event(click_target)
        else:
            raise ValueError("Unknown ClickTarget {}".format(click_target))
예제 #8
0
    def _start_cb(self, elems):
        """Initialize the elements and labels based on the context set."""
        if self._context is None:
            log.hints.debug("In _start_cb without context!")
            return

        if elems is None:
            message.error("There was an error while getting hint elements")
            return
        if not elems:
            message.error("No elements found.")
            return

        strings = self._hint_strings(elems)
        log.hints.debug("hints: {}".format(', '.join(strings)))

        for elem, string in zip(elems, strings):
            label = HintLabel(elem, self._context)
            label.update_text('', string)
            self._context.all_labels.append(label)
            self._context.labels[string] = label

        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings)

        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')

        # to make auto_follow == 'always' work
        self._handle_auto_follow()
예제 #9
0
    def _restore_ctx(self, ctx):
        """Restore state from a PromptContext.

        Args:
            ctx: A PromptContext previously saved by _get_ctx, or None.

        Return: True if a context was restored, False otherwise.
        """
        log.statusbar.debug("Restoring context {}".format(ctx))
        if ctx is None:
            self.hide_prompt.emit()
            self._busy = False
            return False
        self._question = ctx.question
        prompt = objreg.get('prompt', scope='window', window=self._win_id)
        prompt.txt.setText(ctx.text)
        prompt.lineedit.setText(ctx.input_text)
        prompt.lineedit.setEchoMode(ctx.echo_mode)
        prompt.lineedit.setVisible(ctx.input_visible)
        self.show_prompt.emit()
        mode = self.KEY_MODES[ctx.question.mode]
        ctx.question.aborted.connect(
            lambda: modeman.maybe_leave(self._win_id, mode, 'aborted'))
        modeman.enter(self._win_id, mode, 'question asked')
        return True
예제 #10
0
    def on_load_finished(self):
        """Handle auto-insert-mode after loading finished.

        We don't take loadFinished's ok argument here as it always seems to be
        true when the QWebPage has an ErrorPageExtension implemented.
        See https://github.com/The-Compiler/qutebrowser/issues/84
        """
        ok = not self.page().error_occured
        if ok and not self._has_ssl_errors:
            self._set_load_status(LoadStatus.success)
        elif ok:
            self._set_load_status(LoadStatus.warn)
        else:
            self._set_load_status(LoadStatus.error)
        if not config.get('input', 'auto-insert-mode'):
            return
        mode_manager = objreg.get('mode-manager',
                                  scope='window',
                                  window=self._win_id)
        cur_mode = mode_manager.mode
        if cur_mode == usertypes.KeyMode.insert or not ok:
            return
        frame = self.page().currentFrame()
        try:
            elem = webelem.WebElementWrapper(frame.findFirstElement(':focus'))
        except webelem.IsNullError:
            log.webview.debug("Focused element is null!")
            return
        log.modes.debug("focus element: {}".format(repr(elem)))
        if elem.is_editable():
            modeman.enter(self._win_id,
                          usertypes.KeyMode.insert,
                          'load finished',
                          only_if_normal=True)
예제 #11
0
 def on_current_changed(self, idx):
     """Set last-focused-tab and leave hinting mode when focus changed."""
     if idx == -1 or self._shutting_down:
         # closing the last tab (before quitting) or shutting down
         return
     tab = self.widget(idx)
     log.modes.debug("Current tab changed, focusing {!r}".format(tab))
     tab.setFocus()
     for mode in (usertypes.KeyMode.hint, usertypes.KeyMode.insert,
                  usertypes.KeyMode.caret, usertypes.KeyMode.passthrough):
         modeman.maybe_leave(self._win_id, mode, 'tab changed')
     if self._now_focused is not None:
         objreg.register('last-focused-tab', self._now_focused, update=True,
                         scope='window', window=self._win_id)
     ai = False
     for r in pt_masks:
         if re.match(r, tab.url().host()) is not None:
             ai = True
             break
     if ai:
         modeman.enter(self._win_id, usertypes.KeyMode.passthrough,
                       'load finished', only_if_normal=True)
     self._now_focused = tab
     self.current_tab_changed.emit(tab)
     QTimer.singleShot(0, self.update_window_title)
     self._tab_insert_idx_left = self.currentIndex()
     self._tab_insert_idx_right = self.currentIndex() + 1
예제 #12
0
    def _start_cb(self, elems):
        """Initialize the elements and labels based on the context set."""
        filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True)
        elems = [e for e in elems if filterfunc(e)]
        if not elems:
            message.error(self._win_id, "No elements found.", immediately=True)
            return
        strings = self._hint_strings(elems)
        log.hints.debug("hints: {}".format(', '.join(strings)))

        for elem, string in zip(elems, strings):
            label = HintLabel(elem, self._context)
            label.update_text('', string)
            self._context.all_labels.append(label)
            self._context.labels[string] = label

        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings)

        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')

        # to make auto-follow == 'always' work
        self._handle_auto_follow()
예제 #13
0
 def _handle_auto_insert_mode(self, ok):
     """Handle auto-insert-mode after loading finished."""
     ai = False
     for mode in (usertypes.KeyMode.hint, usertypes.KeyMode.insert,
                  usertypes.KeyMode.caret, usertypes.KeyMode.passthrough):
         modeman.maybe_leave(self.win_id, mode, 'load finished')
     for r in pt_masks:
         if re.match(r, self.cur_url.host()) is not None:
             print(re.match(r, self.cur_url.host()), re.match(r, self.cur_url.host()).groups())
             ai = True
             break
     if ai:
         modeman.enter(self.win_id, usertypes.KeyMode.passthrough,
                       'load finished', only_if_normal=True)
         return
     if not config.get('input', 'auto-insert-mode'):
         return
     mode_manager = objreg.get('mode-manager', scope='window',
                               window=self.win_id)
     cur_mode = mode_manager.mode
     if cur_mode == usertypes.KeyMode.insert or not ok:
         return
     frame = self.page().currentFrame()
     try:
         elem = webelem.WebElementWrapper(frame.findFirstElement(':focus'))
     except webelem.IsNullError:
         log.webview.debug("Focused element is null!")
     log.modes.debug("focus element: {}".format(repr(elem)))
     print("bazqux" in self.cur_url.host(), self.cur_url.host())
     if elem.is_editable() or rss:
         modeman.enter(self.win_id, usertypes.KeyMode.insert,
                       'load finished', only_if_normal=True)
예제 #14
0
    def _start_cb(self, elems):
        """Initialize the elements and labels based on the context set."""
        if elems is None:
            message.error("There was an error while getting hint elements")
            return

        filterfunc = webelem.FILTERS.get(self._context.group, lambda e: True)
        elems = [e for e in elems if filterfunc(e)]
        if not elems:
            message.error("No elements found.")
            return
        strings = self._hint_strings(elems)
        log.hints.debug("hints: {}".format(', '.join(strings)))

        for elem, string in zip(elems, strings):
            label = HintLabel(elem, self._context)
            label.update_text('', string)
            self._context.all_labels.append(label)
            self._context.labels[string] = label

        keyparsers = objreg.get('keyparsers',
                                scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings)

        message_bridge = objreg.get('message-bridge',
                                    scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')

        # to make auto-follow == 'always' work
        self._handle_auto_follow()
예제 #15
0
    def _restore_ctx(self, ctx):
        """Restore state from a PromptContext.

        Args:
            ctx: A PromptContext previously saved by _get_ctx, or None.

        Return: True if a context was restored, False otherwise.
        """
        log.statusbar.debug("Restoring context {}".format(ctx))
        if ctx is None:
            self.hide_prompt.emit()
            self._busy = False
            return False
        self._question = ctx.question
        prompt = objreg.get('prompt', scope='window', window=self._win_id)
        prompt.txt.setText(ctx.text)
        prompt.lineedit.setText(ctx.input_text)
        prompt.lineedit.setEchoMode(ctx.echo_mode)
        prompt.lineedit.setVisible(ctx.input_visible)
        self.show_prompt.emit()
        mode = self.KEY_MODES[ctx.question.mode]
        ctx.question.aborted.connect(
            lambda: modeman.maybe_leave(self._win_id, mode, 'aborted'))
        modeman.enter(self._win_id, mode, 'question asked')
        return True
예제 #16
0
    def click(self, click_target, *, force_event=False):
        """Simulate a click on the element.

        Args:
            click_target: A usertypes.ClickTarget member, what kind of click
                          to simulate.
            force_event: Force generating a fake mouse event.
        """
        log.webelem.debug("Clicking {!r} with click_target {}, force_event {}"
                          .format(self, click_target, force_event))

        if force_event:
            self._click_fake_event(click_target)
            return

        if click_target == usertypes.ClickTarget.normal:
            if self.is_link():
                log.webelem.debug("Clicking via JS click()")
                self._click_js(click_target)
            elif self.is_editable(strict=True):
                log.webelem.debug("Clicking via JS focus()")
                self._click_editable(click_target)
                modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                              'clicking input')
            else:
                self._click_fake_event(click_target)
        elif click_target in [usertypes.ClickTarget.tab,
                              usertypes.ClickTarget.tab_bg,
                              usertypes.ClickTarget.window]:
            if self.is_link():
                self._click_href(click_target)
            else:
                self._click_fake_event(click_target)
        else:
            raise ValueError("Unknown ClickTarget {}".format(click_target))
예제 #17
0
 def _auto_insert_mode_cb(elem: 'webelem.AbstractWebElement') -> None:
     """Called from JS after finding the focused element."""
     if elem is None:
         log.webview.debug("No focused element!")
         return
     if elem.is_editable():
         modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                       'load finished', only_if_normal=True)
예제 #18
0
    def _start_cb(self, elems: _ElemsType) -> None:
        """Initialize the elements and labels based on the context set."""
        if self._context is None:
            log.hints.debug("In _start_cb without context!")
            return

        if not elems:
            message.error("No elements found.")
            return

        # Because _start_cb is called asynchronously, it's possible that the
        # user switched to another tab or closed the tab/window. In that case
        # we should not start hinting.
        tabbed_browser = objreg.get('tabbed-browser',
                                    default=None,
                                    scope='window',
                                    window=self._win_id)
        tab = tabbed_browser.widget.currentWidget()
        if tab.tab_id != self._context.tab.tab_id:
            log.hints.debug(
                "Current tab changed ({} -> {}) before _start_cb is run.".
                format(self._context.tab.tab_id, tab.tab_id))
            return

        unique, urls = self._get_unique_url_elems_collection(elems)

        strings = self._hint_strings(unique)
        log.hints.debug("hints: {}".format(', '.join(strings)))

        #urls = dict(map(lambda e: (e[1][1], e[1]), urls.items()))
        strings = list(
            map(
                lambda e: strings[unique.index(e)]
                if e in unique else strings[unique.index(
                    [item[0] for item in urls.values() if e in item][0])],
                elems))

        for elem, string in zip(elems, strings):
            label = HintLabel(elem, self._context)
            label.update_text('', string)
            self._context.all_labels.append(label)
            self._context.labels[string] = label

        keyparser = self._get_keyparser(usertypes.KeyMode.hint)
        keyparser.update_bindings(strings)

        message_bridge = objreg.get('message-bridge',
                                    scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')

        if self._context.first:
            self._fire(strings[0])
            return
        # to make auto_follow == 'always' work
        self._handle_auto_follow()
예제 #19
0
    def ask_question(self, question, blocking):
        """Dispkay a question in the statusbar.

        Args:
            question: The Question object to ask.
            blocking: If True, this function blocks and returns the result.

        Return:
            The answer of the user when blocking=True.
            None if blocking=False.
        """
        log.statusbar.debug("Asking question {}, blocking {}, loops {}, queue "
                            "{}".format(question, blocking, self._loops,
                                        self._queue))

        if self._shutting_down:
            # If we're currently shutting down we have to ignore this question
            # to avoid segfaults - see
            # https://github.com/The-Compiler/qutebrowser/issues/95
            log.statusbar.debug("Ignoring question because we're shutting "
                                "down.")
            question.abort()
            return None

        if self._busy and not blocking:
            # We got an async question, but we're already busy with one, so we
            # just queue it up for later.
            log.statusbar.debug("Adding {} to queue.".format(question))
            self._queue.append(question)
            return

        if blocking:
            # If we're blocking we save the old state on the stack, so we can
            # restore it after exec, if exec gets called multiple times.
            context = self._get_ctx()

        self._question = question
        self._display_question()
        mode = self.KEY_MODES[self._question.mode]
        question.aborted.connect(
            lambda: modeman.maybe_leave(self._win_id, mode, 'aborted'))
        modeman.enter(self._win_id, mode, 'question asked')
        if blocking:
            loop = qtutils.EventLoop()
            self._loops.append(loop)
            loop.destroyed.connect(lambda: self._loops.remove(loop))
            question.completed.connect(loop.quit)
            question.completed.connect(loop.deleteLater)
            loop.exec_()
            if not self._restore_ctx(context):
                # Nothing left to restore, so we can go back to popping async
                # questions.
                if self._queue:
                    self._pop_later()
            return self._question.answer
        else:
            question.completed.connect(self._pop_later)
예제 #20
0
    def ask_question(self, question, blocking):
        """Display a question in the statusbar.

        Args:
            question: The Question object to ask.
            blocking: If True, this function blocks and returns the result.

        Return:
            The answer of the user when blocking=True.
            None if blocking=False.
        """
        log.statusbar.debug("Asking question {}, blocking {}, loops {}, queue "
                            "{}".format(question, blocking, self._loops,
                                        self._queue))

        if self._shutting_down:
            # If we're currently shutting down we have to ignore this question
            # to avoid segfaults - see
            # https://github.com/The-Compiler/qutebrowser/issues/95
            log.statusbar.debug("Ignoring question because we're shutting "
                                "down.")
            question.abort()
            return None

        if self._busy and not blocking:
            # We got an async question, but we're already busy with one, so we
            # just queue it up for later.
            log.statusbar.debug("Adding {} to queue.".format(question))
            self._queue.append(question)
            return

        if blocking:
            # If we're blocking we save the old state on the stack, so we can
            # restore it after exec, if exec gets called multiple times.
            context = self._get_ctx()

        self._question = question
        self._display_question()
        mode = self.KEY_MODES[self._question.mode]
        question.aborted.connect(
            lambda: modeman.maybe_leave(self._win_id, mode, 'aborted'))
        modeman.enter(self._win_id, mode, 'question asked')
        if blocking:
            loop = qtutils.EventLoop()
            self._loops.append(loop)
            loop.destroyed.connect(lambda: self._loops.remove(loop))
            question.completed.connect(loop.quit)
            question.completed.connect(loop.deleteLater)
            loop.exec_()
            if not self._restore_ctx(context):
                # Nothing left to restore, so we can go back to popping async
                # questions.
                if self._queue:
                    self._pop_later()
            return self._question.answer
        else:
            question.completed.connect(self._pop_later)
예제 #21
0
파일: hints.py 프로젝트: har5ha/qutebrowser
    def start(self, group=webelem.Group.all, target=Target.normal,
              *args: {'nargs': '*'}):
        """Start hinting.

        Args:
            group: The hinting mode to use.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.

            target: What to do with the selected element.

                - `normal`: Open the link in the current tab.
                - `tab`: Open the link in a new tab.
                - `tab-bg`: Open the link in a new background tab.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `rapid`: Open the link in a new tab and stay in hinting mode.
                - `download`: Download the link.
                - `userscript`: Call an userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            *args: Arguments for spawn/userscript/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
        """
        tabbed_browser = objreg.get('tabbed-browser')
        widget = tabbed_browser.currentWidget()
        if widget is None:
            raise cmdexc.CommandError("No WebView available yet!")
        mainframe = widget.page().mainFrame()
        if mainframe is None:
            raise cmdexc.CommandError("No frame focused!")
        self._check_args(target, *args)
        self._context = HintContext()
        self._context.target = target
        self._context.baseurl = tabbed_browser.current_url()
        self._context.frames = webelem.get_child_frames(mainframe)
        self._context.args = args
        self._init_elements(mainframe, group)
        objreg.get('message-bridge').set_text(self.HINT_TEXTS[target])
        self._connect_frame_signals()
        try:
            modeman.enter(usertypes.KeyMode.hint, 'HintManager.start')
        except modeman.ModeLockedError:
            self._cleanup()
예제 #22
0
    def ask_question(self, question, blocking):
        """Dispkay a question in the statusbar.

        Args:
            question: The Question object to ask.
            blocking: If True, this function blocks and returns the result.

        Return:
            The answer of the user when blocking=True.
            None if blocking=False.
        """
        log.statusbar.debug("Asking question {}, blocking {}, loops {}, queue "
                            "{}".format(question, blocking, self._loops,
                                        self._queue))

        if self._busy and not blocking:
            # We got an async question, but we're already busy with one, so we
            # just queue it up for later.
            log.statusbar.debug("Adding {} to queue.".format(question))
            self._queue.append(question)
            return

        if blocking:
            # If we're blocking we save the old state on the stack, so we can
            # restore it after exec, if exec gets called multiple times.
            context = self._get_ctx()

        self._question = question
        mode = self._display_question()
        question.aborted.connect(
            lambda: modeman.maybe_leave(self._win_id, mode, 'aborted'))
        mode_manager = objreg.get('mode-manager',
                                  scope='window',
                                  window=self._win_id)
        try:
            modeman.enter(self._win_id, mode, 'question asked', override=True)
        except modeman.ModeLockedError:
            if mode_manager.mode() != usertypes.KeyMode.prompt:
                question.abort()
                return None
        mode_manager.locked = True
        if blocking:
            loop = qtutils.EventLoop()
            self._loops.append(loop)
            loop.destroyed.connect(lambda: self._loops.remove(loop))
            question.completed.connect(loop.quit)
            question.completed.connect(loop.deleteLater)
            loop.exec_()
            if not self._restore_ctx(context):
                # Nothing left to restore, so we can go back to popping async
                # questions.
                if self._queue:
                    self._pop_later()
            return self._question.answer
        else:
            question.completed.connect(self._pop_later)
예제 #23
0
    def set_cmd_text(self, text: str) -> None:
        """Preset the statusbar to some text.

        Args:
            text: The text to set as string.
        """
        self.setText(text)
        log.modes.debug("Setting command text, focusing {!r}".format(self))
        modeman.enter(self._win_id, usertypes.KeyMode.command, 'cmd focus')
        self.setFocus()
        self.show_cmd.emit()
예제 #24
0
    def set_cmd_text(self, text):
        """Preset the statusbar to some text.

        Args:
            text: The text to set as string.
        """
        self.setText(text)
        log.modes.debug("Setting command text, focusing {!r}".format(self))
        modeman.enter(self._win_id, usertypes.KeyMode.command, 'cmd focus')
        self.setFocus()
        self.show_cmd.emit()
예제 #25
0
    def ask_question(self, question, blocking):
        """Dispkay a question in the statusbar.

        Args:
            question: The Question object to ask.
            blocking: If True, this function blocks and returns the result.

        Return:
            The answer of the user when blocking=True.
            None if blocking=False.
        """
        log.statusbar.debug("Asking question {}, blocking {}, loops {}, queue "
                            "{}".format(question, blocking, self._loops,
                                        self._queue))

        if self._busy and not blocking:
            # We got an async question, but we're already busy with one, so we
            # just queue it up for later.
            log.statusbar.debug("Adding {} to queue.".format(question))
            self._queue.append(question)
            return

        if blocking:
            # If we're blocking we save the old state on the stack, so we can
            # restore it after exec, if exec gets called multiple times.
            context = self._get_ctx()

        self._question = question
        mode = self._display_question()
        question.aborted.connect(lambda: modeman.maybe_leave(mode, 'aborted'))
        mode_manager = objreg.get('mode-manager')
        try:
            modeman.enter(mode, 'question asked', override=True)
        except modeman.ModeLockedError:
            if mode_manager.mode() != usertypes.KeyMode.prompt:
                question.abort()
                return None
        mode_manager.locked = True
        if blocking:
            loop = qtutils.EventLoop()
            self._loops.append(loop)
            loop.destroyed.connect(lambda: self._loops.remove(loop))
            question.completed.connect(loop.quit)
            question.completed.connect(loop.deleteLater)
            loop.exec_()
            if not self._restore_ctx(context):
                # Nothing left to restore, so we can go back to popping async
                # questions.
                if self._queue:
                    self._pop_later()
            return self._question.answer
        else:
            question.completed.connect(self._pop_later)
예제 #26
0
파일: hints.py 프로젝트: ykgmfq/qutebrowser
    def _start_cb(self, elems):
        """Initialize the elements and labels based on the context set."""
        if self._context is None:
            log.hints.debug("In _start_cb without context!")
            return

        if not elems:
            message.error("No elements found.")
            return

        # Because _start_cb is called asynchronously, it's possible that the
        # user switched to another tab or closed the tab/window. In that case
        # we should not start hinting.
        tabbed_browser = objreg.get('tabbed-browser',
                                    default=None,
                                    scope='window',
                                    window=self._win_id)
        tab = tabbed_browser.widget.currentWidget()
        if tab.tab_id != self._tab_id:
            log.hints.debug(
                "Current tab changed ({} -> {}) before _start_cb is run.".
                format(self._tab_id, tab.tab_id))
            return

        strings = self._hint_strings(elems)
        log.hints.debug("hints: {}".format(', '.join(strings)))

        for elem, string in zip(elems, strings):
            label = HintLabel(elem, self._context)
            label.update_text('', string)
            self._context.all_labels.append(label)
            self._context.labels[string] = label

        keyparsers = objreg.get('keyparsers',
                                scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings)

        message_bridge = objreg.get('message-bridge',
                                    scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')

        if self._context.first:
            self._fire(strings[0])
            return
        # to make auto_follow == 'always' work
        self._handle_auto_follow()
예제 #27
0
    def _on_show_prompts(self, question):
        """Show a prompt for the given question.

        Args:
            question: A Question object or None.
        """
        item = self._layout.takeAt(0)
        if item is not None:
            widget = item.widget()
            log.prompt.debug("Deleting old prompt {}".format(widget))
            widget.hide()
            widget.deleteLater()

        if question is None:
            log.prompt.debug("No prompts left, hiding prompt container.")
            self._prompt = None
            self.hide()
            return

        classes = {
            usertypes.PromptMode.yesno: YesNoPrompt,
            usertypes.PromptMode.text: LineEditPrompt,
            usertypes.PromptMode.user_pwd: AuthenticationPrompt,
            usertypes.PromptMode.download: DownloadFilenamePrompt,
            usertypes.PromptMode.alert: AlertPrompt,
        }
        klass = classes[question.mode]
        prompt = klass(question)

        log.prompt.debug("Displaying prompt {}".format(prompt))
        self._prompt = prompt

        if not question.interrupted:
            # If this question was interrupted, we already connected the signal
            def on_aborted():
                try:
                    modeman.leave(self._win_id, prompt.KEY_MODE,
                                  'aborted', maybe=True)
                except objreg.RegistryUnavailableError:
                    # window was deleted: ignore
                    pass
            question.aborted.connect(on_aborted)
        modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked')

        self.setSizePolicy(prompt.sizePolicy())
        self._layout.addWidget(prompt)
        prompt.show()
        self.show()
        prompt.setFocus()
        self.update_geometry.emit()
예제 #28
0
        def mouserelease_insertmode_cb(elem):
            """Callback which gets called from JS."""
            if elem is None:
                log.mouse.debug("Element vanished!")
                return

            if elem.is_editable():
                log.mouse.debug("Clicked editable element (delayed)!")
                modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                              'click-delayed', only_if_normal=True)
            else:
                log.mouse.debug("Clicked non-editable element (delayed)!")
                if config.get('input', 'auto-leave-insert-mode'):
                    modeman.leave(self._tab.win_id, usertypes.KeyMode.insert,
                                  'click-delayed', maybe=True)
예제 #29
0
        def mouserelease_insertmode_cb(elem):
            """Callback which gets called from JS."""
            if elem is None:
                log.mouse.debug("Element vanished!")
                return

            if elem.is_editable():
                log.mouse.debug("Clicked editable element (delayed)!")
                modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                              'click-delayed', only_if_normal=True)
            else:
                log.mouse.debug("Clicked non-editable element (delayed)!")
                if config.val.input.insert_mode.auto_leave:
                    modeman.leave(self._tab.win_id, usertypes.KeyMode.insert,
                                  'click-delayed', maybe=True)
예제 #30
0
    def _mousepress_insertmode(self, e):
        """Switch to insert mode when an editable element was clicked.

        Args:
            e: The QMouseEvent.
        """
        pos = e.pos()
        frame = self.page().frameAt(pos)
        if frame is None:
            # This happens when we click inside the webview, but not actually
            # on the QWebPage - for example when clicking the scrollbar
            # sometimes.
            log.mouse.debug("Clicked at {} but frame is None!".format(pos))
            return
        # You'd think we have to subtract frame.geometry().topLeft() from the
        # position, but it seems QWebFrame::hitTestContent wants a position
        # relative to the QWebView, not to the frame. This makes no sense to
        # me, but it works this way.
        hitresult = frame.hitTestContent(pos)
        if hitresult.isNull():
            # For some reason, the whole hit result can be null sometimes (e.g.
            # on doodle menu links). If this is the case, we schedule a check
            # later (in mouseReleaseEvent) which uses webelem.focus_elem.
            log.mouse.debug("Hitresult is null!")
            self._check_insertmode = True
            return
        try:
            elem = webelem.WebElementWrapper(hitresult.element())
        except webelem.IsNullError:
            # For some reason, the hit result element can be a null element
            # sometimes (e.g. when clicking the timetable fields on
            # http://www.sbb.ch/ ). If this is the case, we schedule a check
            # later (in mouseReleaseEvent) which uses webelem.focus_elem.
            log.mouse.debug("Hitresult element is null!")
            self._check_insertmode = True
            return
        if ((hitresult.isContentEditable() and elem.is_writable())
                or elem.is_editable()):
            log.mouse.debug("Clicked editable element!")
            modeman.enter(self.win_id,
                          usertypes.KeyMode.insert,
                          'click',
                          only_if_normal=True)
        else:
            log.mouse.debug("Clicked non-editable element!")
            if config.get('input', 'auto-leave-insert-mode'):
                modeman.maybe_leave(self.win_id, usertypes.KeyMode.insert,
                                    'click')
예제 #31
0
    def _mode_override(self, url: QUrl) -> None:
        """Override mode if url matches pattern.

        Args:
            url: The QUrl to match for
        """
        if not url.isValid():
            return
        mode = config.instance.get('input.mode_override', url=url)
        if mode:
            log.modes.debug(f"Mode change to {mode} triggered for url {url}")
            modeman.enter(
                self._win_id,
                usertypes.KeyMode[mode],
                reason='mode_override',
            )
예제 #32
0
    def _start_cb(self, elems):
        """Initialize the elements and labels based on the context set."""
        if self._context is None:
            log.hints.debug("In _start_cb without context!")
            return

        if not elems:
            message.error("No elements found.")
            return

        # Because _start_cb is called asynchronously, it's possible that the
        # user switched to another tab or closed the tab/window. In that case
        # we should not start hinting.
        tabbed_browser = objreg.get('tabbed-browser', default=None,
                                    scope='window', window=self._win_id)
        tab = tabbed_browser.widget.currentWidget()
        if tab.tab_id != self._tab_id:
            log.hints.debug(
                "Current tab changed ({} -> {}) before _start_cb is run."
                .format(self._tab_id, tab.tab_id))
            return

        strings = self._hint_strings(elems)
        log.hints.debug("hints: {}".format(', '.join(strings)))

        for elem, string in zip(elems, strings):
            label = HintLabel(elem, self._context)
            label.update_text('', string)
            self._context.all_labels.append(label)
            self._context.labels[string] = label

        keyparsers = objreg.get('keyparsers', scope='window',
                                window=self._win_id)
        keyparser = keyparsers[usertypes.KeyMode.hint]
        keyparser.update_bindings(strings)

        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')

        if self._context.first:
            self._fire(strings[0])
            return
        # to make auto_follow == 'always' work
        self._handle_auto_follow()
예제 #33
0
    def _mousepress_insertmode(self, e):
        """Switch to insert mode when an editable element was clicked.

        Args:
            e: The QMouseEvent.
        """
        pos = e.pos()
        frame = self.page().frameAt(pos)
        if frame is None:
            # This happens when we click inside the webview, but not actually
            # on the QWebPage - for example when clicking the scrollbar
            # sometimes.
            log.mouse.debug("Clicked at {} but frame is None!".format(pos))
            return
        # You'd think we have to subtract frame.geometry().topLeft() from the
        # position, but it seems QWebFrame::hitTestContent wants a position
        # relative to the QWebView, not to the frame. This makes no sense to
        # me, but it works this way.
        hitresult = frame.hitTestContent(pos)
        if hitresult.isNull():
            # For some reason, the whole hitresult can be null sometimes (e.g.
            # on doodle menu links). If this is the case, we schedule a check
            # later (in mouseReleaseEvent) which uses webelem.focus_elem.
            log.mouse.debug("Hitresult is null!")
            self._check_insertmode = True
            return
        try:
            elem = webelem.WebElementWrapper(hitresult.element())
        except webelem.IsNullError:
            # For some reason, the hitresult element can be a null element
            # sometimes (e.g. when clicking the timetable fields on
            # http://www.sbb.ch/ ). If this is the case, we schedule a check
            # later (in mouseReleaseEvent) which uses webelem.focus_elem.
            log.mouse.debug("Hitresult element is null!")
            self._check_insertmode = True
            return
        if ((hitresult.isContentEditable() and elem.is_writable()) or
                elem.is_editable()):
            log.mouse.debug("Clicked editable element!")
            modeman.enter(self._win_id, usertypes.KeyMode.insert, 'click',
                          only_if_normal=True)
        else:
            log.mouse.debug("Clicked non-editable element!")
            if config.get('input', 'auto-leave-insert-mode'):
                modeman.maybe_leave(self._win_id, usertypes.KeyMode.insert,
                                    'click')
예제 #34
0
    def _on_show_prompts(self, question):
        """Show a prompt for the given question.

        Args:
            question: A Question object or None.
        """
        item = self._layout.takeAt(0)
        if item is not None:
            widget = item.widget()
            log.prompt.debug("Deleting old prompt {}".format(widget))
            widget.hide()
            widget.deleteLater()

        if question is None:
            log.prompt.debug("No prompts left, hiding prompt container.")
            self._prompt = None
            self.hide()
            return

        classes = {
            usertypes.PromptMode.yesno: YesNoPrompt,
            usertypes.PromptMode.text: LineEditPrompt,
            usertypes.PromptMode.user_pwd: AuthenticationPrompt,
            usertypes.PromptMode.download: DownloadFilenamePrompt,
            usertypes.PromptMode.alert: AlertPrompt,
        }
        klass = classes[question.mode]
        prompt = klass(question)

        log.prompt.debug("Displaying prompt {}".format(prompt))
        self._prompt = prompt

        if not question.interrupted:
            # If this question was interrupted, we already connected the signal
            question.aborted.connect(
                lambda: modeman.leave(self._win_id, prompt.KEY_MODE, 'aborted',
                                      maybe=True))
        modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked')

        self.setSizePolicy(prompt.sizePolicy())
        self._layout.addWidget(prompt)
        prompt.show()
        self.show()
        prompt.setFocus()
        self.update_geometry.emit()
예제 #35
0
    def _on_show_prompts(self, question):
        """Show a prompt for the given question.

        Args:
            question: A Question object or None.
        """
        item = self._layout.takeAt(0)
        if item is not None:
            widget = item.widget()
            log.prompt.debug("Deleting old prompt {}".format(widget))
            widget.hide()
            widget.deleteLater()

        if question is None:
            log.prompt.debug("No prompts left, hiding prompt container.")
            self._prompt = None
            self.hide()
            return

        classes = {
            usertypes.PromptMode.yesno: YesNoPrompt,
            usertypes.PromptMode.text: LineEditPrompt,
            usertypes.PromptMode.user_pwd: AuthenticationPrompt,
            usertypes.PromptMode.download: DownloadFilenamePrompt,
            usertypes.PromptMode.alert: AlertPrompt,
        }
        klass = classes[question.mode]
        prompt = typing.cast(_BasePrompt, klass(question))

        log.prompt.debug("Displaying prompt {}".format(prompt))
        self._prompt = prompt

        # If this question was interrupted, we already connected the signal
        if not question.interrupted:
            question.aborted.connect(
                functools.partial(self._on_aborted, prompt.KEY_MODE))
        modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked')

        self.setSizePolicy(prompt.sizePolicy())
        self._layout.addWidget(prompt)
        prompt.show()
        self.show()
        prompt.setFocus()
        self.update_geometry.emit()
예제 #36
0
 def mouserelease_insertmode(self):
     """If we have an insertmode check scheduled, handle it."""
     if not self._check_insertmode:
         return
     self._check_insertmode = False
     try:
         elem = webelem.focus_elem(self.page().currentFrame())
     except (webelem.IsNullError, RuntimeError):
         log.mouse.debug("Element/page vanished!")
         return
     if elem.is_editable():
         log.mouse.debug("Clicked editable element (delayed)!")
         modeman.enter(self.win_id, usertypes.KeyMode.insert,
                       'click-delayed', only_if_normal=True)
     else:
         log.mouse.debug("Clicked non-editable element (delayed)!")
         if config.get('input', 'auto-leave-insert-mode'):
             modeman.maybe_leave(self.win_id, usertypes.KeyMode.insert,
                                 'click-delayed')
예제 #37
0
    def _mousepress_insertmode_cb(self, elem):
        """Check if the clicked element is editable."""
        if elem is None:
            # Something didn't work out, let's find the focus element after
            # a mouse release.
            log.mouse.debug("Got None element, scheduling check on "
                            "mouse release")
            self._check_insertmode_on_release = True
            return

        if elem.is_editable():
            log.mouse.debug("Clicked editable element!")
            modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                          'click', only_if_normal=True)
        else:
            log.mouse.debug("Clicked non-editable element!")
            if config.val.input.insert_mode.auto_leave:
                modeman.leave(self._tab.win_id, usertypes.KeyMode.insert,
                              'click', maybe=True)
예제 #38
0
    def _mousepress_insertmode_cb(self, elem):
        """Check if the clicked element is editable."""
        if elem is None:
            # Something didn't work out, let's find the focus element after
            # a mouse release.
            log.mouse.debug("Got None element, scheduling check on "
                            "mouse release")
            self._check_insertmode_on_release = True
            return

        if elem.is_editable():
            log.mouse.debug("Clicked editable element!")
            modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                          'click', only_if_normal=True)
        else:
            log.mouse.debug("Clicked non-editable element!")
            if config.get('input', 'auto-leave-insert-mode'):
                modeman.leave(self._tab.win_id, usertypes.KeyMode.insert,
                              'click', maybe=True)
예제 #39
0
 def mouserelease_insertmode(self):
     """If we have an insertmode check scheduled, handle it."""
     if not self._check_insertmode:
         return
     self._check_insertmode = False
     try:
         elem = webelem.focus_elem(self.page().currentFrame())
     except webelem.IsNullError:
         log.mouse.warning("Element vanished!")
         return
     if elem.is_editable():
         log.mouse.debug("Clicked editable element (delayed)!")
         modeman.enter(self._win_id, usertypes.KeyMode.insert,
                       'click-delayed', only_if_normal=True)
     else:
         log.mouse.debug("Clicked non-editable element (delayed)!")
         if config.get('input', 'auto-leave-insert-mode'):
             modeman.maybe_leave(self._win_id, usertypes.KeyMode.insert,
                                 'click-delayed')
예제 #40
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]

        mm_instance = modeman.instance(self._win_id)
        current_mode = mm_instance.mode
        log.modes.debug(
            "Mode before tab change: {} (mode_on_change = {})".format(
                current_mode.name, mode_on_change))
        if mode_on_change == 'normal':
            modes_to_leave += modeman.INPUT_MODES
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if (mode_on_change == 'restore'
                and current_mode not in modeman.PROMPT_MODES):
            modeman.enter(self._win_id, tab.data.input_mode, 'restore')
        if self._now_focused is not None:
            objreg.register('last-focused-tab',
                            self._now_focused,
                            update=True,
                            scope='window',
                            window=self._win_id)
        log.modes.debug(
            "Mode after tab change: {} (mode_on_change = {})".format(
                current_mode.name, mode_on_change))
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.widget.currentIndex()
        self._tab_insert_idx_right = self.widget.currentIndex() + 1
예제 #41
0
 def _handle_auto_insert_mode(self, ok):
     """Handle auto-insert-mode after loading finished."""
     if not config.get('input', 'auto-insert-mode'):
         return
     mode_manager = objreg.get('mode-manager', scope='window',
                               window=self.win_id)
     cur_mode = mode_manager.mode
     if cur_mode == usertypes.KeyMode.insert or not ok:
         return
     frame = self.page().currentFrame()
     try:
         elem = webelem.WebElementWrapper(frame.findFirstElement(':focus'))
     except webelem.IsNullError:
         log.webview.debug("Focused element is null!")
         return
     log.modes.debug("focus element: {}".format(repr(elem)))
     if elem.is_editable():
         modeman.enter(self.win_id, usertypes.KeyMode.insert,
                       'load finished', only_if_normal=True)
예제 #42
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        modes_to_save = [
            usertypes.KeyMode.insert, usertypes.KeyMode.passthrough
        ]
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return
        if self._now_focused is not None and mode_on_change == 'restore':
            current_mode = modeman.instance(self._win_id).mode
            if current_mode not in modes_to_save:
                current_mode = usertypes.KeyMode.normal
            self._now_focused.data.input_mode = current_mode

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]
        if mode_on_change != 'persist':
            modes_to_leave += modes_to_save
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if mode_on_change == 'restore':
            modeman.enter(self._win_id, tab.data.input_mode,
                          'restore input mode for tab')
        if self._now_focused is not None:
            objreg.register('last-focused-tab',
                            self._now_focused,
                            update=True,
                            scope='window',
                            window=self._win_id)
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.currentIndex()
        self._tab_insert_idx_right = self.currentIndex() + 1
예제 #43
0
    def click(self,
              click_target: usertypes.ClickTarget,
              *,
              force_event: bool = False) -> None:
        """Simulate a click on the element.

        Args:
            click_target: A usertypes.ClickTarget member, what kind of click
                          to simulate.
            force_event: Force generating a fake mouse event.
        """
        log.webelem.debug(
            "Clicking {!r} with click_target {}, force_event {}".format(
                self, click_target, force_event))

        if force_event:
            self._click_fake_event(click_target)
            return

        if click_target == usertypes.ClickTarget.normal:
            if self.is_link() and not self._requires_user_interaction():
                log.webelem.debug("Clicking via JS click()")
                self._click_js(click_target)
            elif self.is_editable(strict=True):
                log.webelem.debug("Clicking via JS focus()")
                self._click_editable(click_target)
                if config.val.input.insert_mode.auto_enter:
                    modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
                                  'clicking input')
            else:
                self._click_fake_event(click_target)
        elif click_target in [
                usertypes.ClickTarget.tab, usertypes.ClickTarget.tab_bg,
                usertypes.ClickTarget.window
        ]:
            if self.is_link():
                self._click_href(click_target)
            else:
                self._click_fake_event(click_target)
        else:
            raise ValueError("Unknown ClickTarget {}".format(click_target))
예제 #44
0
    def cycle_focus(self):
        """Cycle keyboard focus between the main/inspector widget."""
        if self.count() == 1:
            raise inspector.Error("No inspector inside main window")

        assert self._main_idx is not None
        assert self._inspector_idx is not None

        main_widget = self.widget(self._main_idx)
        inspector_widget = self.widget(self._inspector_idx)

        if not inspector_widget.isVisible():
            raise inspector.Error("No inspector inside main window")

        if main_widget.hasFocus():
            inspector_widget.setFocus()
            modeman.enter(self._win_id,
                          usertypes.KeyMode.insert,
                          reason='Inspector focused',
                          only_if_normal=True)
        elif inspector_widget.hasFocus():
            main_widget.setFocus()
예제 #45
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]

        mm_instance = modeman.instance(self._win_id)
        current_mode = mm_instance.mode
        log.modes.debug("Mode before tab change: {} (mode_on_change = {})"
                        .format(current_mode.name, mode_on_change))
        if mode_on_change == 'normal':
            modes_to_leave += modeman.INPUT_MODES
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if (mode_on_change == 'restore' and
                current_mode not in modeman.PROMPT_MODES):
            modeman.enter(self._win_id, tab.data.input_mode, 'restore')
        if self._now_focused is not None:
            objreg.register('last-focused-tab', self._now_focused, update=True,
                            scope='window', window=self._win_id)
        log.modes.debug("Mode after tab change: {} (mode_on_change = {})"
                        .format(current_mode.name, mode_on_change))
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.widget.currentIndex()
        self._tab_insert_idx_right = self.widget.currentIndex() + 1
예제 #46
0
    def on_current_changed(self, idx):
        """Set last-focused-tab and leave hinting mode when focus changed."""
        mode_on_change = config.val.tabs.mode_on_change
        modes_to_save = [usertypes.KeyMode.insert,
                         usertypes.KeyMode.passthrough]
        if idx == -1 or self.shutting_down:
            # closing the last tab (before quitting) or shutting down
            return
        tab = self.widget(idx)
        if tab is None:
            log.webview.debug("on_current_changed got called with invalid "
                              "index {}".format(idx))
            return
        if self._now_focused is not None and mode_on_change == 'restore':
            current_mode = modeman.instance(self._win_id).mode
            if current_mode not in modes_to_save:
                current_mode = usertypes.KeyMode.normal
            self._now_focused.data.input_mode = current_mode

        log.modes.debug("Current tab changed, focusing {!r}".format(tab))
        tab.setFocus()

        modes_to_leave = [usertypes.KeyMode.hint, usertypes.KeyMode.caret]
        if mode_on_change != 'persist':
            modes_to_leave += modes_to_save
        for mode in modes_to_leave:
            modeman.leave(self._win_id, mode, 'tab changed', maybe=True)
        if mode_on_change == 'restore':
            modeman.enter(self._win_id, tab.data.input_mode,
                          'restore input mode for tab')
        if self._now_focused is not None:
            objreg.register('last-focused-tab', self._now_focused, update=True,
                            scope='window', window=self._win_id)
        self._now_focused = tab
        self.current_tab_changed.emit(tab)
        QTimer.singleShot(0, self._update_window_title)
        self._tab_insert_idx_left = self.currentIndex()
        self._tab_insert_idx_right = self.currentIndex() + 1
예제 #47
0
    def start(self,
              group=webelem.Group.all,
              target=Target.normal,
              *args: {'nargs': '*'}):
        """Start hinting.

        Args:
            group: The hinting mode to use.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.

            target: What to do with the selected element.

                - `normal`: Open the link in the current tab.
                - `tab`: Open the link in a new tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `rapid`: Open the link in a new tab and stay in hinting mode.
                - `rapid-win`: Open the link in a new window and stay in
                               hinting mode.
                - `download`: Download the link.
                - `userscript`: Call an userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser',
                                    scope='window',
                                    window=self._win_id)
        widget = tabbed_browser.currentWidget()
        if widget is None:
            raise cmdexc.CommandError("No WebView available yet!")
        mainframe = widget.page().mainFrame()
        if mainframe is None:
            raise cmdexc.CommandError("No frame focused!")
        mode_manager = objreg.get('mode-manager',
                                  scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            raise cmdexc.CommandError("Already hinting!")
        self._check_args(target, *args)
        self._context = HintContext()
        self._context.target = target
        self._context.baseurl = tabbed_browser.current_url()
        self._context.frames = webelem.get_child_frames(mainframe)
        for frame in self._context.frames:
            # WORKAROUND for
            # https://github.com/The-Compiler/qutebrowser/issues/152
            frame.destroyed.connect(
                functools.partial(self._context.destroyed_frames.append,
                                  id(frame)))
        self._context.args = args
        self._init_elements(mainframe, group)
        message_bridge = objreg.get('message-bridge',
                                    scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self.HINT_TEXTS[target])
        self._connect_frame_signals()
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')
예제 #48
0
 def ifenter_passthrough(self,tab):
     """enter passthrough hook"""
     url = str(tab.url())
     if any([x in url for x in ['localhost:888','overleaf.com']]):
     #if "localhost:888" in  str(tab.url()): 
         modeman.enter(self._win_id, usertypes.KeyMode.passthrough,reason='super cool hack', only_if_normal=False)
예제 #49
0
파일: app.py 프로젝트: har5ha/qutebrowser
    def __init__(self, args):
        """Constructor.

        Args:
            Argument namespace from argparse.
        """
        self._quit_status = {
            'crash': True,
            'tabs': False,
            'main': False,
        }
        self._shutting_down = False
        self._crashdlg = None
        self._crashlogfile = None
        self._commandrunner = None

        if args.debug:
            # We don't enable this earlier because some imports trigger
            # warnings (which are not our fault).
            warnings.simplefilter('default')

        qt_args = qtutils.get_args(args)
        log.init.debug("Qt arguments: {}, based on {}".format(qt_args, args))
        super().__init__(qt_args)
        sys.excepthook = self._exception_hook

        self._args = args
        objreg.register('args', args)
        QTimer.singleShot(0, self._process_init_args)

        objreg.register('app', self)

        if self._args.version:
            print(version.version())
            print()
            print()
            print(qutebrowser.__copyright__)
            print()
            print(version.GPL_BOILERPLATE.strip())
            sys.exit(0)

        log.init.debug("Starting init...")
        self.setQuitOnLastWindowClosed(False)
        self.setOrganizationName("qutebrowser")
        self.setApplicationName("qutebrowser")
        self.setApplicationVersion(qutebrowser.__version__)
        utils.actute_warning()
        self._init_modules()

        log.init.debug("Initializing eventfilter...")
        mode_manager = objreg.get('mode-manager')
        self.installEventFilter(mode_manager)

        log.init.debug("Connecting signals...")
        self._connect_signals()
        modeman.enter(usertypes.KeyMode.normal, 'init')

        log.init.debug("Showing mainwindow...")
        if not args.nowindow:
            objreg.get('main-window').show()

        log.init.debug("Applying python hacks...")
        self._python_hacks()

        log.init.debug("Init done!")

        if self._crashdlg is not None:
            self._crashdlg.raise_()
예제 #50
0
    def start(self,
              rapid=False,
              group=webelem.Group.all,
              target=Target.normal,
              *args: {'nargs': '*'},
              win_id):
        """Start hinting.

        Args:
            rapid: Whether to do rapid hinting. This is only possible with
                   targets `tab` (with background-tabs=true), `tab-bg`,
                   `window`, `run`, `hover`, `userscript` and `spawn`.
            group: The hinting mode to use.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.

            target: What to do with the selected element.

                - `normal`: Open the link in the current tab.
                - `tab`: Open the link in a new tab (honoring the
                         background-tabs setting).
                - `tab-fg`: Open the link in a new foreground tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `download`: Download the link.
                - `userscript`: Call a userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute. Either store
                                     the userscript in
                                     `~/.local/share/qutebrowser/userscripts`
                                     (or `$XDG_DATA_DIR`), or use an absolute
                                     path.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser',
                                    scope='window',
                                    window=self._win_id)
        widget = tabbed_browser.currentWidget()
        if widget is None:
            raise cmdexc.CommandError("No WebView available yet!")
        mainframe = widget.page().mainFrame()
        if mainframe is None:
            raise cmdexc.CommandError("No frame focused!")
        mode_manager = objreg.get('mode-manager',
                                  scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            modeman.leave(win_id, usertypes.KeyMode.hint, 're-hinting')

        if rapid:
            if target in [
                    Target.tab_bg, Target.window, Target.run, Target.hover,
                    Target.userscript, Target.spawn, Target.download
            ]:
                pass
            elif (target == Target.tab
                  and config.get('tabs', 'background-tabs')):
                pass
            else:
                name = target.name.replace('_', '-')
                raise cmdexc.CommandError("Rapid hinting makes no sense with "
                                          "target {}!".format(name))

        self._check_args(target, *args)
        self._context = HintContext()
        self._context.target = target
        self._context.rapid = rapid
        try:
            self._context.baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdexc.CommandError("No URL set for this page yet!")
        self._context.frames = webelem.get_child_frames(mainframe)
        for frame in self._context.frames:
            # WORKAROUND for
            # https://github.com/The-Compiler/qutebrowser/issues/152
            frame.destroyed.connect(
                functools.partial(self._context.destroyed_frames.append,
                                  id(frame)))
        self._context.args = args
        self._context.mainframe = mainframe
        self._context.group = group
        self._init_elements()
        message_bridge = objreg.get('message-bridge',
                                    scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        self._connect_frame_signals()
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')
예제 #51
0
    def start(self, rapid=False, group=webelem.Group.all, target=Target.normal,
              *args: {'nargs': '*'}, win_id):
        """Start hinting.

        Args:
            rapid: Whether to do rapid hinting. This is only possible with
                   targets `tab` (with background-tabs=true), `tab-bg`,
                   `window`, `run`, `hover`, `userscript` and `spawn`.
            group: The hinting mode to use.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.

            target: What to do with the selected element.

                - `normal`: Open the link in the current tab.
                - `tab`: Open the link in a new tab (honoring the
                         background-tabs setting).
                - `tab-fg`: Open the link in a new foreground tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `download`: Download the link.
                - `userscript`: Call a userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute. Either store
                                     the userscript in
                                     `~/.local/share/qutebrowser/userscripts`
                                     (or `$XDG_DATA_DIR`), or use an absolute
                                     path.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        widget = tabbed_browser.currentWidget()
        if widget is None:
            raise cmdexc.CommandError("No WebView available yet!")
        mainframe = widget.page().mainFrame()
        if mainframe is None:
            raise cmdexc.CommandError("No frame focused!")
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            modeman.leave(win_id, usertypes.KeyMode.hint, 're-hinting')

        if rapid:
            if target in [Target.tab_bg, Target.window, Target.run,
                          Target.hover, Target.userscript, Target.spawn,
                          Target.download]:
                pass
            elif (target == Target.tab and
                  config.get('tabs', 'background-tabs')):
                pass
            else:
                name = target.name.replace('_', '-')
                raise cmdexc.CommandError("Rapid hinting makes no sense with "
                                          "target {}!".format(name))

        self._check_args(target, *args)
        self._context = HintContext()
        self._context.target = target
        self._context.rapid = rapid
        try:
            self._context.baseurl = tabbed_browser.current_url()
        except qtutils.QtValueError:
            raise cmdexc.CommandError("No URL set for this page yet!")
        self._context.frames = webelem.get_child_frames(mainframe)
        for frame in self._context.frames:
            # WORKAROUND for
            # https://github.com/The-Compiler/qutebrowser/issues/152
            frame.destroyed.connect(functools.partial(
                self._context.destroyed_frames.append, id(frame)))
        self._context.args = args
        self._context.mainframe = mainframe
        self._context.group = group
        self._init_elements()
        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self._get_text())
        self._connect_frame_signals()
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')
예제 #52
0
    def start(self, group=webelem.Group.all, target=Target.normal,
              *args: {'nargs': '*'}):
        """Start hinting.

        Args:
            group: The hinting mode to use.

                - `all`: All clickable elements.
                - `links`: Only links.
                - `images`: Only images.

            target: What to do with the selected element.

                - `normal`: Open the link in the current tab.
                - `tab`: Open the link in a new tab.
                - `tab-bg`: Open the link in a new background tab.
                - `window`: Open the link in a new window.
                - `hover` : Hover over the link.
                - `yank`: Yank the link to the clipboard.
                - `yank-primary`: Yank the link to the primary selection.
                - `run`: Run the argument as command.
                - `fill`: Fill the commandline with the command given as
                          argument.
                - `rapid`: Open the link in a new tab and stay in hinting mode.
                - `rapid-win`: Open the link in a new window and stay in
                               hinting mode.
                - `download`: Download the link.
                - `userscript`: Call an userscript with `$QUTE_URL` set to the
                                link.
                - `spawn`: Spawn a command.

            *args: Arguments for spawn/userscript/run/fill.

                - With `spawn`: The executable and arguments to spawn.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `userscript`: The userscript to execute.
                - With `fill`: The command to fill the statusbar with.
                                `{hint-url}` will get replaced by the selected
                                URL.
                - With `run`: Same as `fill`.
        """
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        widget = tabbed_browser.currentWidget()
        if widget is None:
            raise cmdexc.CommandError("No WebView available yet!")
        mainframe = widget.page().mainFrame()
        if mainframe is None:
            raise cmdexc.CommandError("No frame focused!")
        mode_manager = objreg.get('mode-manager', scope='window',
                                  window=self._win_id)
        if mode_manager.mode == usertypes.KeyMode.hint:
            raise cmdexc.CommandError("Already hinting!")
        self._check_args(target, *args)
        self._context = HintContext()
        self._context.target = target
        self._context.baseurl = tabbed_browser.current_url()
        self._context.frames = webelem.get_child_frames(mainframe)
        for frame in self._context.frames:
            # WORKAROUND for
            # https://github.com/The-Compiler/qutebrowser/issues/152
            frame.destroyed.connect(functools.partial(
                self._context.destroyed_frames.append, id(frame)))
        self._context.args = args
        self._init_elements(mainframe, group)
        message_bridge = objreg.get('message-bridge', scope='window',
                                    window=self._win_id)
        message_bridge.set_text(self.HINT_TEXTS[target])
        self._connect_frame_signals()
        modeman.enter(self._win_id, usertypes.KeyMode.hint,
                      'HintManager.start')