support new config management and login callback in applications
This commit is contained in:
parent
cb1372b99f
commit
a255916fa3
3 changed files with 207 additions and 121 deletions
|
|
@ -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_()
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue