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 PyQt5.QtWidgets import QApplication, QDialog, QMessageBox
from PyQt5.QtCore import pyqtSlot, QTimer, QEventLoop
from PyQt5.QtCore import QStandardPaths
from PyQt5.QtCore import pyqtSlot, QTimer, QEventLoop, Qt, QStandardPaths
import qutebrowser
import qutebrowser.commands.utils as cmdutils
@ -366,10 +365,6 @@ class QuteBrowser(QApplication):
self.lastWindowClosed.connect(self.shutdown)
tabs.quit.connect(self.shutdown)
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
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.text.connect(status.set_text)
self.messagebridge.set_cmd_text.connect(cmd.set_cmd_text)
self.messagebridge.question.connect(status.prompt.ask_question,
Qt.DirectConnection)
# config
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.utils.message as message
from qutebrowser.network.qutescheme import QuteSchemeHandler
from qutebrowser.utils.usertypes import PromptMode
class NetworkManager(QNetworkAccessManager):
@ -44,6 +45,9 @@ class NetworkManager(QNetworkAccessManager):
if cookiejar is not None:
self.setCookieJar(cookiejar)
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):
"""Abort all running requests."""
@ -68,6 +72,27 @@ class NetworkManager(QNetworkAccessManager):
queue=True)
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):
"""Return a new QNetworkReply object.

View File

@ -21,6 +21,8 @@ import logging
from PyQt5.QtCore import QObject, pyqtSignal, QCoreApplication
from qutebrowser.utils.usertypes import Question
def instance():
"""Get the global messagebridge instance."""
@ -60,6 +62,25 @@ def text(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():
"""Clear a persistent message in the statusbar."""
instance().text.emit('')
@ -78,3 +99,4 @@ class MessageBridge(QObject):
info = pyqtSignal(str, bool)
text = pyqtSignal(str)
set_cmd_text = pyqtSignal(str)
question = pyqtSignal(Question, bool)

View File

@ -25,6 +25,9 @@ import operator
import logging
import collections.abc
from PyQt5.QtCore import pyqtSignal, QObject
_UNSET = object()
@ -241,3 +244,50 @@ class FakeDict:
def __repr__(self):
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."""
from PyQt5.QtCore import pyqtSignal, QEventLoop, QObject
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QEventLoop
from PyQt5.QtWidgets import QHBoxLayout, QWidget, QLineEdit
import qutebrowser.keyinput.modeman as modeman
import qutebrowser.commands.utils as cmdutils
from qutebrowser.widgets.statusbar._textbase import TextBase
from qutebrowser.widgets.misc import MinimalLineEdit
from qutebrowser.utils.usertypes import enum
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()
from qutebrowser.utils.usertypes import PromptMode, Question
class Prompt(QWidget):
@ -181,13 +136,29 @@ class Prompt(QWidget):
self._input.setFocus()
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):
"""Local eventloop to spin in for a blocking question.
Return:
The answer to the question. No, it's not always 42.
"""
self.display()
self.question.answered.connect(self.loop.quit)
self.cancelled.connect(self.loop.quit)
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._percentage import Percentage
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
@ -317,18 +317,6 @@ class StatusBar(QWidget):
self._text_pop_timer.setInterval(config.get('ui',
'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')
def on_proxy_authentication_required(self, proxy, authenticator):
q = Question()