diff --git a/weboob/tools/application/console.py b/weboob/tools/application/console.py
index a6c978d0..c5f6fdc0 100644
--- a/weboob/tools/application/console.py
+++ b/weboob/tools/application/console.py
@@ -18,7 +18,7 @@
# along with weboob. If not, see .
-from copy import deepcopy
+from copy import copy
import getpass
import logging
import sys
@@ -64,8 +64,12 @@ class ConsoleApplication(BaseApplication):
def __init__(self, option_parser=None):
BaseApplication.__init__(self, option_parser)
+ self.weboob.callbacks['login'] = self.login_cb
self.enabled_backends = set()
+ def login_cb(self, backend_name, value):
+ return self.ask('[%s] Password' % backend_name, masked=True, default='', regexp=value.regexp)
+
def unload_backends(self, *args, **kwargs):
unloaded = self.weboob.unload_backends(*args, **kwargs)
for backend in unloaded.itervalues():
@@ -221,8 +225,8 @@ class ConsoleApplication(BaseApplication):
asked_config = True
print 'Configuration of new account %s' % website
print '-----------------------------%s' % ('-' * len(website))
- p = deepcopy(prop)
- p.set_value(self.ask(prop, default=account.properties[key].value if (key in account.properties) else prop.default))
+ p = copy(prop)
+ p.set(self.ask(prop, default=account.properties[key].get() if (key in account.properties) else prop.default))
account.properties[key] = p
if asked_config:
print '-----------------------------%s' % ('-' * len(website))
@@ -239,7 +243,7 @@ class ConsoleApplication(BaseApplication):
backend_config = {}
for key, value in account.properties.iteritems():
if key in backend.config:
- backend_config[key] = value.value
+ backend_config[key] = value.get()
if ask_add and self.ask('Do you want to add the new register account?', default=True):
return self.add_backend(name, backend_config, ask_register=False)
@@ -253,9 +257,12 @@ class ConsoleApplication(BaseApplication):
if params is None:
params = {}
+ backend = None
+ config = None
if not edit:
try:
backend = self.weboob.modules_loader.get_or_load_module(name)
+ config = backend.config
except ModuleLoadError:
backend = None
else:
@@ -264,15 +271,17 @@ class ConsoleApplication(BaseApplication):
backend = self.weboob.modules_loader.get_or_load_module(bname)
except ModuleLoadError:
backend = None
- items.update(params)
- params = items
+ else:
+ items.update(params)
+ params = items
+ config = backend.config.load(self.weboob, bname, name, params, nofail=True)
if not backend:
print >>sys.stderr, 'Backend "%s" does not exist. Hint: use the "backends" command.' % name
return 1
# ask for params non-specified on command-line arguments
asked_config = False
- for key, value in backend.config.iteritems():
+ for key, value in config.iteritems():
if not asked_config:
asked_config = True
print 'Configuration of backend'
@@ -284,21 +293,23 @@ class ConsoleApplication(BaseApplication):
if asked_config:
print '------------------------'
+ while not edit and self.weboob.backends_config.backend_exists(name):
+ print >>sys.stderr, 'Backend instance "%s" already exists in "%s"' % (name, self.weboob.backends_config.confpath)
+ if not self.ask('Add new instance of "%s" backend?' % backend.name, default=False):
+ return 1
+
+ name = self.ask('Please give new instance name (could be "%s_1")' % backend.name, regexp=r'^[\w\-_]+$')
+
try:
- self.weboob.backends_config.add_backend(name, name, params, edit=edit)
- print 'Backend "%s" successfully %s.' % (name, 'updated' if edit else 'added')
+ config = config.load(self.weboob, backend.name, name, params, nofail=True)
+ for key, value in params.iteritems():
+ config[key].set(value)
+ config.save(edit=edit)
+ print 'Backend "%s" successfully added.' % name
return name
except BackendAlreadyExists:
- print >>sys.stderr, 'Backend "%s" is already configured in file "%s"' % (name, self.weboob.backends_config.confpath)
- while self.ask('Add new instance of "%s" backend?' % name, default=False):
- new_name = self.ask('Please give new instance name (could be "%s_1")' % name, regexp=r'^[\w\-_]+$')
- try:
- self.weboob.backends_config.add_backend(new_name, name, params)
- print 'Backend "%s" successfully added.' % new_name
- return new_name
- except BackendAlreadyExists:
- print >>sys.stderr, 'Instance "%s" already exists for backend "%s".' % (new_name, name)
- return 1
+ print >>sys.stderr, 'Instance "%s" already exists.' % name
+ return 1
def ask(self, question, default=None, masked=False, regexp=None, choices=None):
"""
@@ -313,7 +324,7 @@ class ConsoleApplication(BaseApplication):
"""
if isinstance(question, Value):
- v = deepcopy(question)
+ v = copy(question)
if default:
v.default = default
if masked:
@@ -388,13 +399,13 @@ class ConsoleApplication(BaseApplication):
line = aliases[line]
try:
- v.set_value(line)
+ v.set(line)
except ValueError, e:
print >>sys.stderr, 'Error: %s' % e
else:
break
- return v.value
+ return v.get()
def bcall_error_handler(self, backend, error, backtrace):
"""
diff --git a/weboob/tools/application/qt/backendcfg.py b/weboob/tools/application/qt/backendcfg.py
index 7990bb95..6e11f6ba 100644
--- a/weboob/tools/application/qt/backendcfg.py
+++ b/weboob/tools/application/qt/backendcfg.py
@@ -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":
%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(
'
%s Backend %s
'
'Version: %s
'
@@ -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":
%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_()
diff --git a/weboob/tools/application/qt/qt.py b/weboob/tools/application/qt/qt.py
index 7d9bf7d1..730f283a 100644
--- a/weboob/tools/application/qt/qt.py
+++ b/weboob/tools/application/qt/qt.py
@@ -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))