Exemple #1
0
    def _fire(self, keystr):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
        """
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal: self._actions.click,
            Target.current: self._actions.click,
            Target.tab: self._actions.click,
            Target.tab_fg: self._actions.click,
            Target.tab_bg: self._actions.click,
            Target.window: self._actions.click,
            Target.hover: self._actions.click,
            # _download needs a QWebElement to get the frame.
            Target.download: self._actions.download,
            Target.userscript: self._actions.call_userscript,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._actions.yank,
            Target.yank_primary: self._actions.yank,
            Target.run: self._actions.run_cmd,
            Target.fill: self._actions.preset_cmd_text,
            Target.spawn: self._actions.spawn,
        }
        elem = self._context.labels[keystr].elem

        if not elem.has_frame():
            message.error("This element has no webframe.")
            return

        if self._context.target in elem_handlers:
            handler = functools.partial(elem_handlers[self._context.target],
                                        elem, self._context)
        elif self._context.target in url_handlers:
            url = elem.resolve_url(self._context.baseurl)
            if url is None:
                message.error("No suitable link found for this element.")
                return
            handler = functools.partial(url_handlers[self._context.target],
                                        url, self._context)
        else:
            raise ValueError("No suitable handler found!")

        if not self._context.rapid:
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.hint,
                                'followed')
        else:
            # Reset filtering
            self.filter_hints(None)
            # Undo keystring highlighting
            for string, label in self._context.labels.items():
                label.update_text('', string)

        try:
            handler()
        except HintingError as e:
            message.error(str(e))
    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)
        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()
        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)
        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
Exemple #3
0
    def fire(self, keystr, force=False):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
            force: When True, follow even when auto-follow is false.
        """
        if not (force or config.get('hints', 'auto-follow')):
            self.handle_partial_key(keystr)
            self._context.to_follow = keystr
            return
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal: self._click,
            Target.current: self._click,
            Target.tab: self._click,
            Target.tab_fg: self._click,
            Target.tab_bg: self._click,
            Target.window: self._click,
            Target.hover: self._click,
            # _download needs a QWebElement to get the frame.
            Target.download: self._download,
            Target.userscript: self._call_userscript,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._yank,
            Target.yank_primary: self._yank,
            Target.run: self._run_cmd,
            Target.fill: self._preset_cmd_text,
            Target.spawn: self._spawn,
        }
        elem = self._context.elems[keystr].elem
        if elem.webFrame() is None:
            message.error(self._win_id,
                          "This element has no webframe.",
                          immediately=True)
            return
        if self._context.target in elem_handlers:
            handler = functools.partial(elem_handlers[self._context.target],
                                        elem, self._context)
        elif self._context.target in url_handlers:
            url = self._resolve_url(elem, self._context.baseurl)
            if url is None:
                self._show_url_error()
                return
            handler = functools.partial(url_handlers[self._context.target],
                                        url, self._context)
        else:
            raise ValueError("No suitable handler found!")
        if not self._context.rapid:
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.hint,
                                'followed')
        else:
            # Reset filtering
            self.filter_hints(None)
            # Undo keystring highlighting
            for string, elem in self._context.elems.items():
                elem.label.setInnerXml(string)
        handler()
Exemple #4
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
Exemple #5
0
    def _fire(self, keystr):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
        """
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal: self._actions.click,
            Target.current: self._actions.click,
            Target.tab: self._actions.click,
            Target.tab_fg: self._actions.click,
            Target.tab_bg: self._actions.click,
            Target.window: self._actions.click,
            Target.hover: self._actions.click,
            # _download needs a QWebElement to get the frame.
            Target.download: self._actions.download,
            Target.userscript: self._actions.call_userscript,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._actions.yank,
            Target.yank_primary: self._actions.yank,
            Target.run: self._actions.run_cmd,
            Target.fill: self._actions.preset_cmd_text,
            Target.spawn: self._actions.spawn,
        }
        elem = self._context.labels[keystr].elem

        if not elem.has_frame():
            message.error("This element has no webframe.")
            return

        if self._context.target in elem_handlers:
            handler = functools.partial(elem_handlers[self._context.target],
                                        elem, self._context)
        elif self._context.target in url_handlers:
            url = elem.resolve_url(self._context.baseurl)
            if url is None:
                message.error("No suitable link found for this element.")
                return
            handler = functools.partial(url_handlers[self._context.target],
                                        url, self._context)
        else:
            raise ValueError("No suitable handler found!")

        if not self._context.rapid:
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.hint,
                                'followed')
        else:
            # Reset filtering
            self.filter_hints(None)
            # Undo keystring highlighting
            for string, label in self._context.labels.items():
                label.update_text('', string)

        try:
            handler()
        except HintingError as e:
            message.error(str(e))
Exemple #6
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)
Exemple #7
0
    def fire(self, keystr, force=False):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
            force: When True, follow even when auto-follow is false.
        """
        if not (force or config.get('hints', 'auto-follow')):
            self.handle_partial_key(keystr)
            self._context.to_follow = keystr
            return
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal: self._click,
            Target.current: self._click,
            Target.tab: self._click,
            Target.tab_fg: self._click,
            Target.tab_bg: self._click,
            Target.window: self._click,
            Target.hover: self._click,
            # _download needs a QWebElement to get the frame.
            Target.download: self._download,
            Target.userscript: self._call_userscript,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._yank,
            Target.yank_primary: self._yank,
            Target.run: self._run_cmd,
            Target.fill: self._preset_cmd_text,
            Target.spawn: self._spawn,
        }
        elem = self._context.elems[keystr].elem
        if elem.webFrame() is None:
            message.error(self._win_id,
                          "This element has no webframe.",
                          immediately=True)
            return
        if self._context.target in elem_handlers:
            handler = functools.partial(elem_handlers[self._context.target],
                                        elem, self._context)
        elif self._context.target in url_handlers:
            url = self._resolve_url(elem, self._context.baseurl)
            if url is None:
                self._show_url_error()
                return
            handler = functools.partial(url_handlers[self._context.target],
                                        url, self._context)
        else:
            raise ValueError("No suitable handler found!")
        if not self._context.rapid:
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.hint,
                                'followed')
        else:
            # Show all hints again
            self.filter_hints(None)
            # Undo keystring highlighting
            for (text, elems) in self._context.elems.items():
                elems.label.setInnerXml(text)
        handler()
 def prompt_no(self):
     """Answer no to a yes/no prompt."""
     if self._question.mode != usertypes.PromptMode.yesno:
         # We just ignore this if we don't have a yes/no question.
         return
     self._question.answer = False
     modeman.maybe_leave(self._win_id, usertypes.KeyMode.yesno, "prompt accept")
     self._question.done()
Exemple #9
0
 def prompt_no(self):
     """Answer no to a yes/no prompt."""
     if self._question.mode != usertypes.PromptMode.yesno:
         # We just ignore this if we don't have a yes/no question.
         return
     self._question.answer = False
     modeman.maybe_leave(self._win_id, usertypes.KeyMode.yesno,
                         'prompt accept')
     self._question.done()
 def prompt_yes(self):
     """Answer yes to a yes/no prompt."""
     if self._question.mode != usertypes.PromptMode.yesno:
         # We just ignore this if we don't have a yes/no question.
         return
     self._question.answer = True
     modeman.maybe_leave(self._win_id, usertypes.KeyMode.yesno,
                         'yesno accept')
     self._question.done()
Exemple #11
0
 def prompt_open_download(self):
     """Immediately open a download."""
     if self._question.mode != usertypes.PromptMode.download:
         # We just ignore this if we don't have a download question.
         return
     self._question.answer = usertypes.OpenFileDownloadTarget()
     modeman.maybe_leave(self._win_id, usertypes.KeyMode.prompt,
                         'download open')
     self._question.done()
Exemple #12
0
 def on_current_changed(self, idx):
     """Set last-focused-tab and leave hinting mode when focus changed."""
     tab = self.widget(idx)
     tab.setFocus()
     modeman.maybe_leave(usertypes.KeyMode.hint, 'tab changed')
     if self._now_focused is not None:
         objreg.register('last-focused-tab', self._now_focused, update=True)
     self._now_focused = tab
     self.current_tab_changed.emit(tab)
     self._change_app_title(self.tabText(idx))
     self._tab_insert_idx_left = self.currentIndex()
     self._tab_insert_idx_right = self.currentIndex() + 1
    def prompt_accept(self):
        """Accept the current prompt.

        //

        This executes the next action depending on the question mode, e.g. asks
        for the password or leaves the mode.
        """
        prompt = objreg.get('prompt', scope='window', window=self._win_id)
        if (self._question.mode == usertypes.PromptMode.user_pwd and
                self._question.user is None):
            # User just entered a username
            self._question.user = prompt.lineedit.text()
            prompt.txt.setText("Password:"******"Invalid question mode!")
Exemple #14
0
    def prompt_accept(self):
        """Accept the current prompt.

        //

        This executes the next action depending on the question mode, e.g. asks
        for the password or leaves the mode.
        """
        prompt = objreg.get('prompt', scope='window', window=self._win_id)
        if (self._question.mode == usertypes.PromptMode.user_pwd
                and self._question.user is None):
            # User just entered a username
            self._question.user = prompt.lineedit.text()
            prompt.txt.setText("Password:"******"Invalid question mode!")
Exemple #15
0
    def _on_global_mode_left(self, mode):
        """Leave prompt/yesno mode in this window if it was left elsewhere.

        This ensures no matter where a prompt was answered, we leave the prompt
        mode and dispose of the prompt object in every window.
        """
        if mode not in [usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]:
            return
        modeman.maybe_leave(self._win_id, mode, 'left in other window')
        item = self._layout.takeAt(0)
        if item is not None:
            widget = item.widget()
            log.prompt.debug("Deleting prompt {}".format(widget))
            widget.hide()
            widget.deleteLater()
Exemple #16
0
    def _on_global_mode_left(self, mode):
        """Leave prompt/yesno mode in this window if it was left elsewhere.

        This ensures no matter where a prompt was answered, we leave the prompt
        mode and dispose of the prompt object in every window.
        """
        if mode not in [usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]:
            return
        modeman.maybe_leave(self._win_id, mode, 'left in other window')
        item = self._layout.takeAt(0)
        if item is not None:
            widget = item.widget()
            log.prompt.debug("Deleting prompt {}".format(widget))
            widget.hide()
            widget.deleteLater()
Exemple #17
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')
Exemple #18
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.maybe_leave(self._tab.win_id,
                                        usertypes.KeyMode.insert,
                                        'click-delayed')
Exemple #19
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
    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
Exemple #21
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.maybe_enter(usertypes.KeyMode.insert, 'click-delayed')
     else:
         log.mouse.debug("Clicked non-editable element (delayed)!")
         if config.get('input', 'auto-leave-insert-mode'):
             modeman.maybe_leave(usertypes.KeyMode.insert, 'click-delayed')
Exemple #22
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')
Exemple #23
0
 def on_current_changed(self, idx):
     """Set last-focused-tab and leave hinting mode when focus changed."""
     if idx == -1:
         # closing the last tab (before quitting)
         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):
         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)
     self._now_focused = tab
     self.current_tab_changed.emit(tab)
     self._change_app_title(self.tabText(idx))
     self._tab_insert_idx_left = self.currentIndex()
     self._tab_insert_idx_right = self.currentIndex() + 1
Exemple #24
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)
    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)
 def on_current_changed(self, idx):
     """Set last-focused-tab and leave hinting mode when focus changed."""
     if idx == -1:
         # closing the last tab (before quitting)
         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):
         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)
     self._now_focused = tab
     self.current_tab_changed.emit(tab)
     self._change_app_title(self.tabText(idx))
     self._tab_insert_idx_left = self.currentIndex()
     self._tab_insert_idx_right = self.currentIndex() + 1
Exemple #27
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.maybe_leave(self._tab.win_id,
                                        usertypes.KeyMode.insert,
                                        'click-delayed')
Exemple #28
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)
Exemple #29
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')
Exemple #30
0
    def prompt_open_download(self, cmdline: str=None):
        """Immediately open a download.

        If no specific command is given, this will use the system's default
        application to open the file.

        Args:
            cmdline: The command which should be used to open the file. A `{}`
                     is expanded to the temporary file name. If no `{}` is
                     present, the filename is automatically appended to the
                     cmdline.
        """
        if self._question.mode != usertypes.PromptMode.download:
            # We just ignore this if we don't have a download question.
            return
        self._question.answer = usertypes.OpenFileDownloadTarget(cmdline)
        modeman.maybe_leave(self._win_id, usertypes.KeyMode.prompt,
                            'download open')
        self._question.done()
Exemple #31
0
    def prompt_open_download(self, cmdline: str = None):
        """Immediately open a download.

        If no specific command is given, this will use the system's default
        application to open the file.

        Args:
            cmdline: The command which should be used to open the file. A `{}`
                     is expanded to the temporary file name. If no `{}` is
                     present, the filename is automatically appended to the
                     cmdline.
        """
        if self._question.mode != usertypes.PromptMode.download:
            # We just ignore this if we don't have a download question.
            return
        self._question.answer = usertypes.OpenFileDownloadTarget(cmdline)
        modeman.maybe_leave(self._win_id, usertypes.KeyMode.prompt,
                            'download open')
        self._question.done()
 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)
     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
Exemple #33
0
    def fire(self, keystr, force=False):
        """Fire a completed hint.

        Args:
            keystr: The keychain string to follow.
            force: When True, follow even when auto-follow is false.
        """
        if not (force or config.get('hints', 'auto-follow')):
            self.handle_partial_key(keystr)
            self._context.to_follow = keystr
            return
        # Handlers which take a QWebElement
        elem_handlers = {
            Target.normal: self._click,
            Target.tab: self._click,
            Target.tab_bg: self._click,
            Target.rapid: self._click,
            # _download needs a QWebElement to get the frame.
            Target.download: self._download,
        }
        # Handlers which take a QUrl
        url_handlers = {
            Target.yank: self._yank,
            Target.yank_primary: self._yank,
            Target.fill: self._preset_cmd_text,
            Target.userscript: self._call_userscript,
            Target.spawn: self._spawn,
        }
        elem = self._context.elems[keystr].elem
        if self._context.target in elem_handlers:
            elem_handlers[self._context.target](elem)
        elif self._context.target in url_handlers:
            url = self._resolve_url(elem)
            if url is None:
                message.error("No suitable link found for this element.",
                              immediately=True)
                return
            url_handlers[self._context.target](url)
        else:
            raise ValueError("No suitable handler found!")
        if self._context.target != Target.rapid:
            modeman.maybe_leave(usertypes.KeyMode.hint, 'followed')
Exemple #34
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.maybe_leave(self._tab.win_id,
                                    usertypes.KeyMode.insert,
                                    'click')
Exemple #35
0
 def mouserelease_insertmode(self):
     """If we have an insertmode check scheduled, handle it."""
     # FIXME:qtwebengine Use tab.find_focus_element here
     if not self._check_insertmode:
         return
     self._check_insertmode = False
     try:
         elem = webkitelem.focus_elem(self.page().currentFrame())
     except (webkitelem.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')
Exemple #36
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)
Exemple #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.get('input', 'auto-leave-insert-mode'):
                modeman.maybe_leave(self._tab.win_id, usertypes.KeyMode.insert,
                                    'click')
Exemple #38
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.maybe_leave(self._win_id, prompt.KEY_MODE,
                                            '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()
Exemple #39
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.maybe_leave(self._win_id, prompt.KEY_MODE,
                                            '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()
Exemple #40
0
 def _on_prompt_done(self, key_mode):
     """Leave the prompt mode in this window if a question was answered."""
     modeman.maybe_leave(self._win_id, key_mode, ':prompt-accept')
Exemple #41
0
    def prompt_accept(self, value=None):
        """Accept the current prompt.

        //

        This executes the next action depending on the question mode, e.g. asks
        for the password or leaves the mode.

        Args:
            value: If given, uses this value instead of the entered one.
                   For boolean prompts, "yes"/"no" are accepted as value.
        """
        prompt = objreg.get('prompt', scope='window', window=self._win_id)
        text = value if value is not None else prompt.lineedit.text()

        if (self._question.mode == usertypes.PromptMode.user_pwd
                and self._question.user is None):
            # User just entered a username
            self._question.user = text
            prompt.txt.setText("Password:"******"Invalid value {} - expected "
                                          "yes/no!".format(value))
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.yesno,
                                'yesno accept')
            self._question.done()
        elif self._question.mode == usertypes.PromptMode.alert:
            if value is not None:
                raise cmdexc.CommandError("No value is permitted with alert "
                                          "prompts!")
            # User acknowledged an alert
            self._question.answer = None
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.prompt,
                                'alert accept')
            self._question.done()
        else:
            raise ValueError("Invalid question mode!")
Exemple #42
0
    def prompt_accept(self, value=None):
        """Accept the current prompt.

        //

        This executes the next action depending on the question mode, e.g. asks
        for the password or leaves the mode.

        Args:
            value: If given, uses this value instead of the entered one.
                   For boolean prompts, "yes"/"no" are accepted as value.
        """
        prompt = objreg.get('prompt', scope='window', window=self._win_id)
        text = value if value is not None else prompt.lineedit.text()

        if (self._question.mode == usertypes.PromptMode.user_pwd and
                self._question.user is None):
            # User just entered a username
            self._question.user = text
            prompt.txt.setText("Password:"******"Invalid value {} - expected "
                                          "yes/no!".format(value))
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.yesno,
                                'yesno accept')
            self._question.done()
        elif self._question.mode == usertypes.PromptMode.alert:
            if value is not None:
                raise cmdexc.CommandError("No value is permitted with alert "
                                          "prompts!")
            # User acknowledged an alert
            self._question.answer = None
            modeman.maybe_leave(self._win_id, usertypes.KeyMode.prompt,
                                'alert accept')
            self._question.done()
        else:
            raise ValueError("Invalid question mode!")
 def on_cur_load_started(self):
     """Leave insert/hint mode when loading started."""
     modeman.maybe_leave(self._win_id, usertypes.KeyMode.insert,
                         'load started')
     modeman.maybe_leave(self._win_id, usertypes.KeyMode.hint,
                         'load started')
Exemple #44
0
 def _on_prompt_done(self, key_mode):
     """Leave the prompt mode in this window if a question was answered."""
     modeman.maybe_leave(self._win_id, key_mode, ':prompt-accept')
Exemple #45
0
def on_mode_entered(mode, win_id):
    """Stop hinting when insert mode was entered."""
    if mode == usertypes.KeyMode.insert:
        modeman.maybe_leave(win_id, usertypes.KeyMode.hint, 'insert mode')
Exemple #46
0
def on_mode_entered(mode, win_id):
    """Stop hinting when insert mode was entered."""
    if mode == usertypes.KeyMode.insert:
        modeman.maybe_leave(win_id, usertypes.KeyMode.hint, 'insert mode')
 def on_cur_load_started(self):
     """Leave insert/hint mode when loading started."""
     modeman.maybe_leave(self._win_id, usertypes.KeyMode.insert,
                         'load started')
     modeman.maybe_leave(self._win_id, usertypes.KeyMode.hint,
                         'load started')