support new config management and login callback in applications

This commit is contained in:
Romain Bignon 2011-05-21 10:28:03 +02:00
commit a255916fa3
3 changed files with 207 additions and 121 deletions

View file

@ -62,13 +62,14 @@ class BackendCfg(QDialog):
self.ui.configuredBackendsList.header().setResizeMode(QHeaderView.ResizeToContents)
self.ui.configFrame.hide()
self.icon_cache = {}
for name, backend in self.weboob.modules_loader.loaded.iteritems():
if not self.caps or backend.has_caps(*self.caps):
item = QListWidgetItem(name.capitalize())
if backend.icon_path:
img = QImage(backend.icon_path)
item.setIcon(QIcon(QPixmap.fromImage(img)))
item.setIcon(self.get_icon_cache(backend.icon_path))
self.ui.backendsList.addItem(item)
@ -86,6 +87,12 @@ class BackendCfg(QDialog):
self.connect(self.ui.configButtonBox, SIGNAL('accepted()'), self.acceptBackend)
self.connect(self.ui.configButtonBox, SIGNAL('rejected()'), self.rejectBackend)
def get_icon_cache(self, path):
if not path in self.icon_cache:
img = QImage(path)
self.icon_cache[path] = QIcon(QPixmap.fromImage(img))
return self.icon_cache[path]
def loadConfiguredBackendsList(self):
self.ui.configuredBackendsList.clear()
for instance_name, name, params in self.weboob.backends_config.iter_backends():
@ -102,8 +109,7 @@ class BackendCfg(QDialog):
else Qt.Unchecked)
if backend.icon_path:
img = QImage(backend.icon_path)
item.setIcon(0, QIcon(QPixmap.fromImage(img)))
item.setIcon(0, self.get_icon_cache(backend.icon_path))
self.ui.configuredBackendsList.addTopLevelItem(item)
@ -159,22 +165,23 @@ class BackendCfg(QDialog):
self.ui.configFrame.hide()
self.loadConfiguredBackendsList()
def editBackend(self, bname=None):
def editBackend(self, name=None):
self.ui.registerButton.hide()
self.ui.configFrame.show()
if bname is not None:
mname, params = self.weboob.backends_config.get_backend(bname)
if name is not None:
bname, params = self.weboob.backends_config.get_backend(name)
items = self.ui.backendsList.findItems(mname, Qt.MatchFixedString)
items = self.ui.backendsList.findItems(bname, Qt.MatchFixedString)
if not items:
warning('Backend not found')
else:
self.ui.backendsList.setCurrentItem(items[0])
self.ui.backendsList.setEnabled(False)
self.ui.nameEdit.setText(bname)
self.ui.nameEdit.setText(name)
self.ui.nameEdit.setEnabled(False)
if '_proxy' in params:
self.ui.proxyBox.setChecked(True)
self.ui.proxyEdit.setText(params.pop('_proxy'))
@ -184,13 +191,14 @@ class BackendCfg(QDialog):
params.pop('_enabled', None)
for key, value in params.iteritems():
backend = self.weboob.modules_loader.loaded[bname]
for key, value in backend.config.load(self.weboob, bname, name, params, nofail=True).iteritems():
try:
l, widget = self.config_widgets[key]
except KeyError:
warning('Key "%s" is not found' % key)
else:
widget.set_data(value)
widget.set_value(value)
else:
self.ui.nameEdit.clear()
self.ui.nameEdit.setEnabled(True)
@ -199,69 +207,6 @@ class BackendCfg(QDialog):
self.ui.backendsList.setEnabled(True)
self.ui.backendsList.setCurrentRow(-1)
def acceptBackend(self):
bname = unicode(self.ui.nameEdit.text())
selection = self.ui.backendsList.selectedItems()
if not selection:
QMessageBox.critical(self, self.tr('Unable to add a configured backend'),
self.tr('Please select a backend'))
return
try:
backend = self.weboob.modules_loader.get_or_load_module(unicode(selection[0].text()).lower())
except ModuleLoadError:
backend = None
if not backend:
QMessageBox.critical(self, self.tr('Unable to add a configured backend'),
self.tr('The selected backend does not exist.'))
return
params = {}
if not bname:
QMessageBox.critical(self, self.tr('Missing field'), self.tr('Please specify a backend name'))
return
if self.ui.nameEdit.isEnabled() and not re.match(r'^[\w\-_]+$', bname):
QMessageBox.critical(self, self.tr('Invalid value'),
self.tr('The backend name can only contain letters and digits'))
return
if self.ui.proxyBox.isChecked():
params['_proxy'] = unicode(self.ui.proxyEdit.text())
if not params['_proxy']:
QMessageBox.critical(self, self.tr('Missing field'), self.tr('Please specify a proxy URL'))
return
for key, field in backend.config.iteritems():
label, qtvalue = self.config_widgets[key]
try:
value = qtvalue.get_value()
except ValueError, e:
QMessageBox.critical(self, self.tr('Invalid value'),
unicode(self.tr('Invalid value for field "%s":<br /><br />%s')) % (field.label, e))
return
params[key] = value.value
try:
self.weboob.backends_config.add_backend(bname, backend.name, params, edit=not self.ui.nameEdit.isEnabled())
except BackendAlreadyExists, e:
QMessageBox.critical(self, self.tr('Unable to create backend'),
unicode(self.tr('Unable to create backend "%s": it already exists')) % bname)
return
self.to_load.add(bname)
self.ui.configFrame.hide()
self.loadConfiguredBackendsList()
def rejectBackend(self):
self.ui.configFrame.hide()
def backendSelectionChanged(self):
for key, (label, value) in self.config_widgets.iteritems():
label.hide()
@ -288,6 +233,7 @@ class BackendCfg(QDialog):
self.ui.nameEdit.setText(backend.name)
else:
self.ui.nameEdit.setText('')
self.ui.backendInfo.setText(unicode(self.tr(
'<h1>%s Backend %s</h1>'
'<b>Version</b>: %s<br />'
@ -313,13 +259,82 @@ class BackendCfg(QDialog):
for key, field in backend.config.iteritems():
label = QLabel(u'%s:' % field.label)
value = QtValue(field)
self.ui.configLayout.addRow(label, value)
self.config_widgets[key] = (label, value)
qvalue = QtValue(field)
self.ui.configLayout.addRow(label, qvalue)
self.config_widgets[key] = (label, qvalue)
def proxyEditEnabled(self, state):
self.ui.proxyEdit.setEnabled(state)
def acceptBackend(self):
bname = unicode(self.ui.nameEdit.text())
selection = self.ui.backendsList.selectedItems()
if not selection:
QMessageBox.critical(self, self.tr('Unable to add a configured backend'),
self.tr('Please select a backend'))
return
try:
backend = self.weboob.modules_loader.get_or_load_module(unicode(selection[0].text()).lower())
except ModuleLoadError:
backend = None
if not backend:
QMessageBox.critical(self, self.tr('Unable to add a configured backend'),
self.tr('The selected backend does not exist.'))
return
params = {}
if not bname:
QMessageBox.critical(self, self.tr('Missing field'), self.tr('Please specify a backend name'))
return
if self.ui.nameEdit.isEnabled():
if not re.match(r'^[\w\-_]+$', bname):
QMessageBox.critical(self, self.tr('Invalid value'),
self.tr('The backend name can only contain letters and digits'))
return
if self.weboob.backends_config.backend_exists(bname):
QMessageBox.critical(self, self.tr('Unable to create backend'),
unicode(self.tr('Unable to create backend "%s": it already exists')) % bname)
return
if self.ui.proxyBox.isChecked():
params['_proxy'] = unicode(self.ui.proxyEdit.text())
if not params['_proxy']:
QMessageBox.critical(self, self.tr('Missing field'), self.tr('Please specify a proxy URL'))
return
config = backend.config.load(self.weboob, backend.name, bname, {}, nofail=True)
for key, field in config.iteritems():
label, qtvalue = self.config_widgets[key]
try:
value = qtvalue.get_value()
except ValueError, e:
QMessageBox.critical(self, self.tr('Invalid value'),
unicode(self.tr('Invalid value for field "%s":<br /><br />%s')) % (field.label, e))
return
field.set(value.get())
try:
config.save(edit=not self.ui.nameEdit.isEnabled(), params=params)
except BackendAlreadyExists:
QMessageBox.critical(self, self.tr('Unable to create backend'),
unicode(self.tr('Unable to create backend "%s": it already exists')) % bname)
return
self.to_load.add(bname)
self.ui.configFrame.hide()
self.loadConfiguredBackendsList()
def rejectBackend(self):
self.ui.configFrame.hide()
def registerEvent(self):
selection = self.ui.backendsList.selectedItems()
if not selection:
@ -380,7 +395,7 @@ class BackendCfg(QDialog):
else:
for key, value in account.properties.iteritems():
if key in self.config_widgets:
self.config_widgets[key][1].set_data(value.value)
self.config_widgets[key][1].set_value(value)
def run(self):
self.exec_()

View file

@ -20,16 +20,18 @@
import sys
import logging
import re
from copy import deepcopy
from PyQt4.QtCore import QTimer, SIGNAL, QObject, QString, QSize, QVariant
from threading import Event
from copy import copy
from PyQt4.QtCore import QTimer, SIGNAL, QObject, QString, QSize, QVariant, QMutex
from PyQt4.QtGui import QMainWindow, QApplication, QStyledItemDelegate, \
QStyleOptionViewItemV4, QTextDocument, QStyle, \
QAbstractTextDocumentLayout, QPalette, QMessageBox, \
QSpinBox, QLineEdit, QComboBox, QCheckBox
QSpinBox, QLineEdit, QComboBox, QCheckBox, QInputDialog, \
QLineEdit
from weboob.core.ouiboube import Weboob
from weboob.core.scheduler import IScheduler
from weboob.tools.value import ValueInt, ValueBool
from weboob.tools.value import ValueInt, ValueBool, ValueBackendPassword
from ..base import BaseApplication
@ -77,12 +79,63 @@ class QtScheduler(IScheduler):
def run(self):
self.app.exec_()
class QCallbacksManager(QObject):
class Request(object):
def __init__(self):
self.event = Event()
self.answer = None
def __call__(self):
raise NotImplementedError()
class LoginRequest(Request):
def __init__(self, backend_name, value):
QCallbacksManager.Request.__init__(self)
self.backend_name = backend_name
self.value = value
def __call__(self):
password, ok = QInputDialog.getText(None,
'Password request',
'Please enter password for %s' % self.backend_name,
QLineEdit.Password)
return password
def __init__(self, weboob, parent=None):
QObject.__init__(self, parent)
self.weboob = weboob
self.weboob.callbacks['login'] = self.callback(self.LoginRequest)
self.mutex = QMutex()
self.requests = []
self.connect(self, SIGNAL('new_request'), self.do_request)
def callback(self, klass):
def cb(*args, **kwargs):
return self.add_request(klass(*args, **kwargs))
return cb
def do_request(self):
self.mutex.lock()
request = self.requests.pop()
request.answer = request()
request.event.set()
self.mutex.unlock()
def add_request(self, request):
self.mutex.lock()
self.requests.append(request)
self.mutex.unlock()
self.emit(SIGNAL('new_request'))
request.event.wait()
return request.answer
class QtApplication(QApplication, BaseApplication):
def __init__(self):
QApplication.__init__(self, sys.argv)
self.setApplicationName(self.APPNAME)
BaseApplication.__init__(self)
self.cbmanager = QCallbacksManager(self.weboob, self)
def create_weboob(self):
return Weboob(scheduler=QtScheduler(self))
@ -196,14 +249,19 @@ class _QtValueStr(QLineEdit):
if value.masked:
self.setEchoMode(self.Password)
def set_data(self, text):
self._value.set_value(unicode(text))
self.setText(self._value.value)
def set_value(self, value):
self._value = value
self.setText(self._value.get())
def get_value(self):
self._value.set_value(unicode(self.text()))
self._value.set(unicode(self.text()))
return self._value
class _QtValueBackendPassword(_QtValueStr):
def get_value(self):
self._value._domain = None
return _QtValueStr.get_value(self)
class _QtValueBool(QCheckBox):
def __init__(self, value):
QCheckBox.__init__(self)
@ -211,12 +269,12 @@ class _QtValueBool(QCheckBox):
if value.default:
self.setChecked(True)
def set_data(self, b):
self._value.set_value(b)
self.setChecked(self._value.value)
def set_value(self, value):
self._value = value
self.setChecked(self._value.get())
def get_value(self):
self._value.set_value(self.isChecked())
self._value.set(self.isChecked())
return self._value
class _QtValueInt(QSpinBox):
@ -226,12 +284,12 @@ class _QtValueInt(QSpinBox):
if value.default:
self.setValue(int(value.default))
def set_data(self, i):
self._value.set_value(i)
self.setValue(self._value.value)
def set_value(self, value):
self._value = value
self.setValue(self._value.get())
def get_value(self):
self._value.set_value(self.getValue())
self._value.set(self.getValue())
return self._value
class _QtValueChoices(QComboBox):
@ -243,15 +301,15 @@ class _QtValueChoices(QComboBox):
if value.default == k:
self.setCurrentIndex(self.count()-1)
def set_data(self, c):
self._value.set_value(c)
def set_value(self, value):
self._value = value
for i in xrange(self.count()):
if unicode(self.itemData(i).toString()) == self._value.value:
if unicode(self.itemData(i).toString()) == self._value.get():
self.setCurrentIndex(i)
return
def get_value(self):
self._value.set_value(unicode(self.itemData(self.currentIndex()).toString()))
self._value.set(unicode(self.itemData(self.currentIndex()).toString()))
return self._value
def QtValue(value):
@ -259,9 +317,11 @@ def QtValue(value):
klass = _QtValueBool
elif isinstance(value, ValueInt):
klass = _QtValueInt
elif isinstance(value, ValueBackendPassword):
klass = _QtValueBackendPassword
elif value.choices is not None:
klass = _QtValueChoices
else:
klass = _QtValueStr
return klass(deepcopy(value))
return klass(copy(value))