From a792b6601ca6de14184b78cd5175e0a8b3abc21b Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Tue, 26 Oct 2010 21:00:29 +0200 Subject: [PATCH] support new Values* classes and ICapAccount with a 'Register' button (closes #390) --- weboob/tools/application/qt/backendcfg.py | 157 ++++++++++++++-------- weboob/tools/application/qt/backendcfg.ui | 25 +++- weboob/tools/application/qt/qt.py | 86 +++++++++++- 3 files changed, 206 insertions(+), 62 deletions(-) diff --git a/weboob/tools/application/qt/backendcfg.py b/weboob/tools/application/qt/backendcfg.py index e2281977..b56df414 100644 --- a/weboob/tools/application/qt/backendcfg.py +++ b/weboob/tools/application/qt/backendcfg.py @@ -15,15 +15,18 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from PyQt4.QtGui import QDialog, QTreeWidgetItem, QLabel, QLineEdit, QCheckBox, \ +from PyQt4.QtGui import QDialog, QTreeWidgetItem, QLabel, QFormLayout, \ QMessageBox, QPixmap, QImage, QIcon, QHeaderView, \ - QListWidgetItem, QTextDocument, QComboBox + QListWidgetItem, QTextDocument, QVBoxLayout, \ + QDialogButtonBox from PyQt4.QtCore import SIGNAL, Qt, QVariant, QUrl -import re from logging import warning +from weboob.capabilities.account import ICapAccount, Account, AccountRegisterError from weboob.tools.application.qt.backendcfg_ui import Ui_BackendCfg +from weboob.tools.ordereddict import OrderedDict +from .qt import QtValue class BackendCfg(QDialog): def __init__(self, weboob, caps=None, parent=None): @@ -68,6 +71,7 @@ class BackendCfg(QDialog): self.connect(self.ui.proxyBox, SIGNAL('toggled(bool)'), self.proxyEditEnabled) self.connect(self.ui.addButton, SIGNAL('clicked()'), self.addEvent) self.connect(self.ui.removeButton, SIGNAL('clicked()'), self.removeEvent) + self.connect(self.ui.registerButton, SIGNAL('clicked()'), self.registerEvent) self.connect(self.ui.configButtonBox, SIGNAL('accepted()'), self.acceptBackend) self.connect(self.ui.configButtonBox, SIGNAL('rejected()'), self.rejectBackend) @@ -140,6 +144,7 @@ class BackendCfg(QDialog): self.loadConfiguredBackendsList() def editBackend(self, bname=None): + self.ui.registerButton.hide() self.ui.configFrame.show() if bname is not None: @@ -164,18 +169,12 @@ class BackendCfg(QDialog): params.pop('_enabled', None) for key, value in params.iteritems(): - l, widget = self.config_widgets[key] - if isinstance(widget, QLineEdit): - widget.setText(unicode(value)) - elif isinstance(widget, QCheckBox): - widget.setChecked(value.lower() in ('1', 'true', 'yes', 'on')) - elif isinstance(widget, QComboBox): - for i in xrange(widget.count()): - if unicode(widget.itemData(i).toString()) == value: - widget.setCurrentIndex(i) - break + try: + l, widget = self.config_widgets[key] + except KeyError: + warning('Key "%s" is not found' % key) else: - warning('Unknown type field "%s": %s', key, widget) + widget.set_data(value) else: self.ui.nameEdit.clear() self.ui.nameEdit.setEnabled(True) @@ -201,44 +200,31 @@ class BackendCfg(QDialog): return params = {} - missing = [] if not bname: - missing.append(self.tr('Name')) + QMessageBox.critical(self, self.tr('Missing field'), + self.tr('Please specify a backend name')) + return if self.ui.proxyBox.isChecked(): params['_proxy'] = unicode(self.ui.proxyEdit.text()) if not params['_proxy']: - missing.append(self.tr('Proxy')) - - for key, field in backend.config.iteritems(): - label, value = self.config_widgets[key] - - if isinstance(value, QLineEdit): - params[key] = unicode(value.text()) - elif isinstance(value, QCheckBox): - params[key] = '1' if value.isChecked() else '0' - elif isinstance(value, QComboBox): - params[key] = unicode(value.itemData(value.currentIndex()).toString()) - else: - warning('Unknown type field "%s": %s', key, value) - - if not params[key]: - params[key] = field.default - - if not params[key]: - missing.append(field.description) - elif field.regexp and not re.match(field.regexp, params[key]): - QMessageBox.critical(self, - self.tr('Invalid value'), - unicode(self.tr('Invalid value for field "%s":\n\n%s')) % (field.description, params[key])) + QMessageBox.critical(self, self.tr('Missing field'), + self.tr('Please specify a proxy URL')) return - if missing: - QMessageBox.critical(self, - self.tr('Missing fields'), - unicode(self.tr('Please set a value in this fields:\n%s')) % ('\n'.join(['- %s' % s for s in missing]))) - 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 self.weboob.backends_config.add_backend(bname, backend.name, params, edit=not self.ui.nameEdit.isEnabled()) self.to_load.add(bname) @@ -287,28 +273,81 @@ class BackendCfg(QDialog): backend.description, ', '.join([cap.__name__ for cap in backend.iter_caps()]))) + if backend.has_caps(ICapAccount) and self.ui.nameEdit.isEnabled(): + self.ui.registerButton.show() + else: + self.ui.registerButton.hide() + for key, field in backend.config.iteritems(): - label = QLabel(u'%s:' % field.description) - if isinstance(field.default, bool): - value = QCheckBox() - if field.default: - value.setChecked(True) - elif field.choices: - value = QComboBox() - for k, l in (field.choices.iteritems() if isinstance(field.choices, dict) else ((k,k) for k in field.choices)): - value.addItem(l, QVariant(k)) - else: - value = QLineEdit() - if field.default is not None: - value.setText(unicode(field.default)) - if field.is_masked: - value.setEchoMode(value.Password) + label = QLabel(u'%s:' % field.label) + value = QtValue(field) self.ui.configLayout.addRow(label, value) self.config_widgets[key] = (label, value) def proxyEditEnabled(self, state): self.ui.proxyEdit.setEnabled(state) + def registerEvent(self): + selection = self.ui.backendsList.selectedItems() + if not selection: + return + + backend = self.weboob.modules_loader.get_or_load_module(unicode(selection[0].text()).lower()) + + if not backend: + return + + dialog = QDialog(self) + vbox = QVBoxLayout(dialog) + if backend.website: + website = 'on the website %s' % backend.website + else: + website = 'with the backend %s' % backend.name + vbox.addWidget(QLabel('To create an account %s, please give that informations:' % website)) + formlayout = QFormLayout() + props_widgets = OrderedDict() + for key, prop in backend.klass.ACCOUNT_REGISTER_PROPERTIES.iteritems(): + widget = QtValue(prop) + formlayout.addRow(QLabel(u'%s:' % prop.label), widget) + props_widgets[prop.id] = widget + + vbox.addLayout(formlayout) + buttonBox = QDialogButtonBox(dialog) + buttonBox.setStandardButtons(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) + self.connect(buttonBox, SIGNAL("accepted()"), dialog.accept) + self.connect(buttonBox, SIGNAL("rejected()"), dialog.reject) + vbox.addWidget(buttonBox) + + end = False + while not end: + end = True + if dialog.exec_(): + account = Account() + account.properties = {} + for key, widget in props_widgets.iteritems(): + try: + v = widget.get_value() + except ValueError, e: + QMessageBox.critical(self, + self.tr('Invalid value'), + unicode(self.tr('Invalid value for field "%s":

%s')) % (key, e)) + end = False + break + else: + account.properties[key] = v + if end: + try: + backend.klass.register_account(account) + except AccountRegisterError, e: + QMessageBox.critical(self, + self.tr('Error during register'), + unicode(self.tr('Unable to register account %s:

%s')) % (website, e)) + end = False + else: + for key, value in account.properties.iteritems(): + if key in self.config_widgets: + self.config_widgets[key][1].set_data(value.value) + def run(self): self.exec_() diff --git a/weboob/tools/application/qt/backendcfg.ui b/weboob/tools/application/qt/backendcfg.ui index e6597f85..df17b771 100644 --- a/weboob/tools/application/qt/backendcfg.ui +++ b/weboob/tools/application/qt/backendcfg.ui @@ -6,7 +6,7 @@ 0 0 - 645 + 646 652 @@ -189,6 +189,9 @@ + + QFormLayout::ExpandingFieldsGrow + @@ -213,6 +216,13 @@ + + + + Register an account... + + + @@ -241,6 +251,19 @@ + + configuredBackendsList + addButton + removeButton + backendsList + backendInfo + nameEdit + proxyBox + proxyEdit + registerButton + configButtonBox + buttonBox + diff --git a/weboob/tools/application/qt/qt.py b/weboob/tools/application/qt/qt.py index 2b56d4c0..1618ccca 100644 --- a/weboob/tools/application/qt/qt.py +++ b/weboob/tools/application/qt/qt.py @@ -18,13 +18,16 @@ import sys import logging import re -from PyQt4.QtCore import QTimer, SIGNAL, QObject, QString, QSize +from copy import deepcopy +from PyQt4.QtCore import QTimer, SIGNAL, QObject, QString, QSize, QVariant from PyQt4.QtGui import QMainWindow, QApplication, QStyledItemDelegate, \ QStyleOptionViewItemV4, QTextDocument, QStyle, \ - QAbstractTextDocumentLayout, QPalette, QMessageBox + QAbstractTextDocumentLayout, QPalette, QMessageBox, \ + QSpinBox, QLineEdit, QComboBox, QCheckBox from weboob.core.ouiboube import Weboob from weboob.core.scheduler import IScheduler +from weboob.tools.value import ValueInt, ValueBool from ..base import BaseApplication @@ -181,3 +184,82 @@ class HTMLDelegate(QStyledItemDelegate): doc.setTextWidth(optionV4.rect.width()) return QSize(doc.idealWidth(), max(doc.size().height(), optionV4.decorationSize.height())) + +class _QtValueStr(QLineEdit): + def __init__(self, value): + QLineEdit.__init__(self) + self._value = value + if value.default: + self.setText(unicode(value.default)) + if value.masked: + self.setEchoMode(self.Password) + + def set_data(self, text): + self._value.set_value(unicode(text)) + self.setText(self._value.value) + + def get_value(self): + self._value.set_value(unicode(self.text())) + return self._value + +class _QtValueBool(QCheckBox): + def __init__(self, value): + QCheckBox.__init__(self) + self._value = value + if value.default: + self.setChecked(True) + + def set_data(self, b): + self._value.set_value(b) + self.setChecked(self._value.value) + + def get_value(self): + self._value.set_value(self.isChecked()) + return self._value + +class _QtValueInt(QSpinBox): + def __init__(self, value): + QSpinBox.__init__(self) + self._value = value + if value.default: + self.setValue(int(value.default)) + + def set_data(self, i): + self._value.set_value(i) + self.setValue(self._value.value) + + def get_value(self): + self._value.set_value(self.getValue()) + return self._value + +class _QtValueChoices(QComboBox): + def __init__(self, value): + QComboBox.__init__(self) + self._value = value + for k, l in value.choices.iteritems(): + self.addItem(l, QVariant(k)) + if value.default == k: + self.setCurrentIndex(self.count()-1) + + def set_data(self, c): + self._value.set_value(c) + for i in xrange(self.count()): + if unicode(self.itemData(i).toString()) == self._value.value: + self.setCurrentIndex(i) + return + + def get_value(self): + self._value.set_value(unicode(self.itemData(self.currentIndex()).toString())) + return self._value + +def QtValue(value): + if isinstance(value, ValueBool): + klass = _QtValueBool + elif isinstance(value, ValueInt): + klass = _QtValueInt + elif value.choices is not None: + klass = _QtValueChoices + else: + klass = _QtValueStr + + return klass(deepcopy(value))