Clean up prompt code

This commit is contained in:
Florian Bruhin 2014-05-20 11:03:55 +02:00
parent 20f8c2b8b4
commit f43549d452
6 changed files with 120 additions and 67 deletions

View File

@ -40,8 +40,7 @@ from argparse import ArgumentParser
from base64 import b64encode from base64 import b64encode
from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox
from PyQt5.QtCore import pyqtSlot, QTimer, QEventLoop from PyQt5.QtCore import pyqtSlot, QTimer, QEventLoop, Qt, QStandardPaths
from PyQt5.QtCore import QStandardPaths
import qutebrowser import qutebrowser
import qutebrowser.commands.utils as cmdutils import qutebrowser.commands.utils as cmdutils
@ -366,10 +365,6 @@ class QuteBrowser(QApplication):
self.lastWindowClosed.connect(self.shutdown) self.lastWindowClosed.connect(self.shutdown)
tabs.quit.connect(self.shutdown) tabs.quit.connect(self.shutdown)
tabs.currentChanged.connect(self.mainwindow.update_inspector) tabs.currentChanged.connect(self.mainwindow.update_inspector)
self.networkmanager.authenticationRequired.connect(
status.on_authentication_required)
self.networkmanager.proxyAuthenticationRequired.connect(
status.on_proxy_authentication_required)
# status bar # status bar
self.modeman.entered.connect(status.on_mode_entered) self.modeman.entered.connect(status.on_mode_entered)
@ -396,6 +391,8 @@ class QuteBrowser(QApplication):
self.messagebridge.info.connect(status.disp_temp_text) self.messagebridge.info.connect(status.disp_temp_text)
self.messagebridge.text.connect(status.set_text) self.messagebridge.text.connect(status.set_text)
self.messagebridge.set_cmd_text.connect(cmd.set_cmd_text) self.messagebridge.set_cmd_text.connect(cmd.set_cmd_text)
self.messagebridge.question.connect(status.prompt.ask_question,
Qt.DirectConnection)
# config # config
self.config.style_changed.connect(style.invalidate_caches) self.config.style_changed.connect(style.invalidate_caches)

View File

@ -23,6 +23,7 @@ from PyQt5.QtNetwork import QNetworkAccessManager
import qutebrowser.config.config as config import qutebrowser.config.config as config
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
from qutebrowser.network.qutescheme import QuteSchemeHandler from qutebrowser.network.qutescheme import QuteSchemeHandler
from qutebrowser.utils.usertypes import PromptMode
class NetworkManager(QNetworkAccessManager): class NetworkManager(QNetworkAccessManager):
@ -44,6 +45,9 @@ class NetworkManager(QNetworkAccessManager):
if cookiejar is not None: if cookiejar is not None:
self.setCookieJar(cookiejar) self.setCookieJar(cookiejar)
self.sslErrors.connect(self.on_ssl_errors) self.sslErrors.connect(self.on_ssl_errors)
self.authenticationRequired.connect(self.on_authentication_required)
self.proxyAuthenticationRequired.connect(
self.on_proxy_authentication_required)
def abort_requests(self): def abort_requests(self):
"""Abort all running requests.""" """Abort all running requests."""
@ -68,6 +72,27 @@ class NetworkManager(QNetworkAccessManager):
queue=True) queue=True)
reply.ignoreSslErrors() reply.ignoreSslErrors()
@pyqtSlot('QNetworkReply', 'QAuthenticator')
def on_authentication_required(self, reply, authenticator):
"""Called when a website needs authentication."""
answer = message.modular_question(
text="Username ({}):".format(authenticator.realm()),
mode=PromptMode.user_pwd)
if answer is not None:
user, password = answer
authenticator.setUser(user)
authenticator.setPassword(password)
@pyqtSlot('QNetworkProxy', 'QAuthenticator')
def on_proxy_authentication_required(self, proxy, authenticator):
answer = message.modular_question(
text="Proxy username ({}):".format(authenticator.realm()),
mode=PromptMode.user_pwd)
if answer is not None:
user, password = answer
authenticator.setUser(user)
authenticator.setPassword(password)
def createRequest(self, op, req, outgoing_data): def createRequest(self, op, req, outgoing_data):
"""Return a new QNetworkReply object. """Return a new QNetworkReply object.

View File

@ -21,6 +21,8 @@ import logging
from PyQt5.QtCore import QObject, pyqtSignal, QCoreApplication from PyQt5.QtCore import QObject, pyqtSignal, QCoreApplication
from qutebrowser.utils.usertypes import Question
def instance(): def instance():
"""Get the global messagebridge instance.""" """Get the global messagebridge instance."""
@ -60,6 +62,25 @@ def text(message):
instance().text.emit(message) instance().text.emit(message)
def modular_question(text, mode, default=None):
"""Ask a modular question in the statusbar.
Args:
text: The message to display to the user.
mode: A PromptMode.
default: The default value to display.
Return:
The answer the user gave or None if the prompt was cancelled.
"""
q = Question()
q.text = text
q.mode = mode
q.default = default
instance().question.emit(q, True)
return q.answer
def clear(): def clear():
"""Clear a persistent message in the statusbar.""" """Clear a persistent message in the statusbar."""
instance().text.emit('') instance().text.emit('')
@ -78,3 +99,4 @@ class MessageBridge(QObject):
info = pyqtSignal(str, bool) info = pyqtSignal(str, bool)
text = pyqtSignal(str) text = pyqtSignal(str)
set_cmd_text = pyqtSignal(str) set_cmd_text = pyqtSignal(str)
question = pyqtSignal(Question, bool)

View File

@ -25,6 +25,9 @@ import operator
import logging import logging
import collections.abc import collections.abc
from PyQt5.QtCore import pyqtSignal, QObject
_UNSET = object() _UNSET = object()
@ -241,3 +244,50 @@ class FakeDict:
def __repr__(self): def __repr__(self):
return "FakeDict('{}')".format(self._val) return "FakeDict('{}')".format(self._val)
# The mode of a Question.
PromptMode = enum('yesno', 'text', 'user_pwd')
class Question(QObject):
"""A question asked to the user, e.g. via the status bar.
Attributes:
mode: A PromptMode enum member.
yesno: A question which can be answered with yes/no.
text: A question which requires a free text answer.
user_pwd: A question for an username and password.
default: The default value.
For yesno, None (no default), True or False.
For text, a default text as string.
For user_pwd, a default username as string.
text: The prompt text to display to the user.
user: The value the user entered as username.
answer: The value the user entered (as password for user_pwd).
Signals:
answered: Emitted when the question has been answered by the user.
"""
answered = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.mode = None
self.default = None
self.text = None
self.user = None
self._answer = None
@property
def answer(self):
"""Getter for answer so we can define a setter."""
return self._answer
@answer.setter
def answer(self, val):
"""Setter for answer to emit the answered signal after setting."""
self._answer = val
self.answered.emit()

View File

@ -17,59 +17,14 @@
"""Prompt shown in the statusbar.""" """Prompt shown in the statusbar."""
from PyQt5.QtCore import pyqtSignal, QEventLoop, QObject from PyQt5.QtCore import pyqtSignal, pyqtSlot, QEventLoop
from PyQt5.QtWidgets import QHBoxLayout, QWidget, QLineEdit from PyQt5.QtWidgets import QHBoxLayout, QWidget, QLineEdit
import qutebrowser.keyinput.modeman as modeman import qutebrowser.keyinput.modeman as modeman
import qutebrowser.commands.utils as cmdutils import qutebrowser.commands.utils as cmdutils
from qutebrowser.widgets.statusbar._textbase import TextBase from qutebrowser.widgets.statusbar._textbase import TextBase
from qutebrowser.widgets.misc import MinimalLineEdit from qutebrowser.widgets.misc import MinimalLineEdit
from qutebrowser.utils.usertypes import enum from qutebrowser.utils.usertypes import PromptMode, Question
PromptMode = enum('yesno', 'text', 'user_pwd')
class Question(QObject):
"""A question asked to the user via the status bar.
Attributes:
mode: A PromptMode enum member.
yesno: A question which can be answered with yes/no.
text: A question which requires a free text answer.
user_pwd: A question for an username and password.
default: The default value.
For yesno, None (no default), True or False.
For text, a default text as string.
For user_pwd, a default username as string.
text: The prompt text to display to the user.
user: The value the user entered as username.
answer: The value the user entered (as password for user_pwd).
Signals:
answered: Emitted when the question has been answered by the user.
"""
answered = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.mode = None
self.default = None
self.text = None
self.user = None
self._answer = None
@property
def answer(self):
"""Getter for answer so we can define a setter."""
return self._answer
@answer.setter
def answer(self, val):
"""Setter for answer to emit the answered signal after setting."""
self._answer = val
self.answered.emit()
class Prompt(QWidget): class Prompt(QWidget):
@ -181,13 +136,29 @@ class Prompt(QWidget):
self._input.setFocus() self._input.setFocus()
self.show_prompt.emit() self.show_prompt.emit()
@pyqtSlot(Question, bool)
def ask_question(self, question, blocking):
"""Slot which is called when there's a question to ask to the user.
Return:
The answer of the user when blocking=True.
None if blocking=False.
Args:
question: The Question object to ask.
blocking: If True, exec_ is called and the result is returned.
"""
self.question = question
self.display()
if blocking:
return self.exec_()
def exec_(self): def exec_(self):
"""Local eventloop to spin in for a blocking question. """Local eventloop to spin in for a blocking question.
Return: Return:
The answer to the question. No, it's not always 42. The answer to the question. No, it's not always 42.
""" """
self.display()
self.question.answered.connect(self.loop.quit) self.question.answered.connect(self.loop.quit)
self.cancelled.connect(self.loop.quit) self.cancelled.connect(self.loop.quit)
self.loop.exec_() self.loop.exec_()

View File

@ -32,7 +32,7 @@ from qutebrowser.widgets.statusbar._text import Text
from qutebrowser.widgets.statusbar._keystring import KeyString from qutebrowser.widgets.statusbar._keystring import KeyString
from qutebrowser.widgets.statusbar._percentage import Percentage from qutebrowser.widgets.statusbar._percentage import Percentage
from qutebrowser.widgets.statusbar._url import Url from qutebrowser.widgets.statusbar._url import Url
from qutebrowser.widgets.statusbar._prompt import Prompt, PromptMode, Question from qutebrowser.widgets.statusbar._prompt import Prompt
from qutebrowser.config.style import set_register_stylesheet, get_stylesheet from qutebrowser.config.style import set_register_stylesheet, get_stylesheet
@ -317,18 +317,6 @@ class StatusBar(QWidget):
self._text_pop_timer.setInterval(config.get('ui', self._text_pop_timer.setInterval(config.get('ui',
'message-timeout')) 'message-timeout'))
@pyqtSlot('QNetworkReply', 'QAuthenticator')
def on_authentication_required(self, reply, authenticator):
q = Question()
q.mode = PromptMode.user_pwd
q.text = "Username ({}):".format(authenticator.realm())
self.prompt.question = q
answer = self.prompt.exec_()
if answer is not None:
user, password = answer
authenticator.setUser(user)
authenticator.setPassword(password)
@pyqtSlot('QNetworkProxy', 'QAuthenticator') @pyqtSlot('QNetworkProxy', 'QAuthenticator')
def on_proxy_authentication_required(self, proxy, authenticator): def on_proxy_authentication_required(self, proxy, authenticator):
q = Question() q = Question()