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
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()
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
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)
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()
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()
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()
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!")
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()
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')
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')
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 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')
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')
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
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 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)
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')
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 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
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')
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')
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')
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)
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()
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')
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')
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')