Example #1
0
    def __init__(self, weboob, caps=None, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_BackendCfg()
        self.ui.setupUi(self)

        self.ui.backendsList.sortByColumn(0, Qt.AscendingOrder)

        self.to_unload = set()
        self.to_load = set()

        self.weboob = weboob
        self.caps = caps
        self.config_widgets = {}

        # This attribute is set when itemChanged it called, because when
        # a backend is enabled/disabled, we don't want to display its config
        # frame, and the itemClicked event is always emit just after a
        # itemChanged event.
        # is_enabling is a counter to prevent race conditions.
        self.is_enabling = 0

        self.ui.backendsList.header().setResizeMode(
            QHeaderView.ResizeToContents)
        self.ui.configFrame.hide()

        self.icon_cache = {}
        self.icon_threads = {}

        self.loadModules()
        self.loadBackendsList()

        self.connect(self.ui.updateButton, SIGNAL('clicked()'),
                     self.updateModules)
        self.connect(self.ui.repositoriesButton, SIGNAL('clicked()'),
                     self.editRepositories)
        self.connect(self.ui.backendsList,
                     SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
                     self.backendClicked)
        self.connect(self.ui.backendsList,
                     SIGNAL('itemChanged(QTreeWidgetItem *, int)'),
                     self.backendEnabled)
        self.connect(self.ui.modulesList, SIGNAL('itemSelectionChanged()'),
                     self.moduleSelectionChanged)
        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)
Example #2
0
    def __init__(self, weboob, caps=None, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_BackendCfg()
        self.ui.setupUi(self)

        self.to_unload = set()
        self.to_load = set()

        self.weboob = weboob
        self.caps = caps
        self.config_widgets = {}

        # This attribute is set when itemChanged it called, because when
        # a backend is enabled/disabled, we don't want to display its config
        # frame, and the itemClicked event is always emit just after a
        # itemChanged event.
        # is_enabling is a counter to prevent race conditions.
        self.is_enabling = 0

        self.weboob.modules_loader.load_all()

        self.ui.configuredBackendsList.header().setResizeMode(QHeaderView.ResizeToContents)
        self.ui.configFrame.hide()

        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)))

                self.ui.backendsList.addItem(item)

        self.loadConfiguredBackendsList()

        self.connect(self.ui.configuredBackendsList, SIGNAL('itemClicked(QTreeWidgetItem *, int)'), self.configuredBackendClicked)
        self.connect(self.ui.configuredBackendsList, SIGNAL('itemChanged(QTreeWidgetItem *, int)'), self.configuredBackendEnabled)
        self.connect(self.ui.backendsList, SIGNAL('itemSelectionChanged()'), self.backendSelectionChanged)
        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)
Example #3
0
    def __init__(self, weboob, caps=None, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_BackendCfg()
        self.ui.setupUi(self)

        self.ui.backendsList.sortByColumn(0, Qt.AscendingOrder)

        self.to_unload = set()
        self.to_load = set()

        self.weboob = weboob
        self.caps = caps
        self.config_widgets = {}

        # This attribute is set when itemChanged it called, because when
        # a backend is enabled/disabled, we don't want to display its config
        # frame, and the itemClicked event is always emit just after a
        # itemChanged event.
        # is_enabling is a counter to prevent race conditions.
        self.is_enabling = 0

        self.ui.backendsList.header().setResizeMode(QHeaderView.ResizeToContents)
        self.ui.configFrame.hide()

        self.icon_cache = {}
        self.icon_threads = {}

        self.loadModules()
        self.loadBackendsList()

        self.connect(self.ui.updateButton, SIGNAL('clicked()'), self.updateModules)
        self.connect(self.ui.repositoriesButton, SIGNAL('clicked()'), self.editRepositories)
        self.connect(self.ui.backendsList, SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
                     self.backendClicked)
        self.connect(self.ui.backendsList, SIGNAL('itemChanged(QTreeWidgetItem *, int)'),
                     self.backendEnabled)
        self.connect(self.ui.modulesList, SIGNAL('itemSelectionChanged()'), self.moduleSelectionChanged)
        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)
Example #4
0
class BackendCfg(QDialog):
    def __init__(self, weboob, caps=None, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_BackendCfg()
        self.ui.setupUi(self)

        self.ui.backendsList.sortByColumn(0, Qt.AscendingOrder)

        self.to_unload = set()
        self.to_load = set()

        self.weboob = weboob
        self.caps = caps
        self.config_widgets = {}

        # This attribute is set when itemChanged it called, because when
        # a backend is enabled/disabled, we don't want to display its config
        # frame, and the itemClicked event is always emit just after a
        # itemChanged event.
        # is_enabling is a counter to prevent race conditions.
        self.is_enabling = 0

        self.ui.backendsList.header().setResizeMode(
            QHeaderView.ResizeToContents)
        self.ui.configFrame.hide()

        self.icon_cache = {}
        self.icon_threads = {}

        self.loadModules()
        self.loadBackendsList()

        self.connect(self.ui.updateButton, SIGNAL('clicked()'),
                     self.updateModules)
        self.connect(self.ui.repositoriesButton, SIGNAL('clicked()'),
                     self.editRepositories)
        self.connect(self.ui.backendsList,
                     SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
                     self.backendClicked)
        self.connect(self.ui.backendsList,
                     SIGNAL('itemChanged(QTreeWidgetItem *, int)'),
                     self.backendEnabled)
        self.connect(self.ui.modulesList, SIGNAL('itemSelectionChanged()'),
                     self.moduleSelectionChanged)
        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)

    def get_icon_cache(self, path):
        if path not in self.icon_cache:
            img = QImage(path)
            self.icon_cache[path] = QIcon(QPixmap.fromImage(img))
        return self.icon_cache[path]

    def set_icon(self, item, minfo):
        icon_path = self.weboob.repositories.get_module_icon_path(minfo)

        icon = self.icon_cache.get(icon_path, None)
        if icon is None and not os.path.exists(icon_path):
            if minfo.name in self.icon_threads:
                self.icon_threads[minfo.name].items.append(item)
            else:
                thread = IconFetcher(self.weboob, item, minfo)
                self.connect(thread, SIGNAL('retrieved'),
                             lambda t: self._set_icon(t.items, t.minfo))
                self.icon_threads[minfo.name] = thread
                thread.start()
            return

        self._set_icon([item], minfo)

    def _set_icon(self, items, minfo):
        icon_path = self.weboob.repositories.get_module_icon_path(minfo)
        icon = self.get_icon_cache(icon_path)

        if icon is None:
            return

        for item in items:
            try:
                item.setIcon(icon)
            except TypeError:
                item.setIcon(0, icon)

        self.icon_threads.pop(minfo.name, None)

    def updateModules(self):
        self.ui.configFrame.hide()
        pd = ProgressDialog('Update of modules', "Cancel", 0, 100, self)
        pd.setWindowModality(Qt.WindowModal)
        try:
            self.weboob.repositories.update(pd)
        except ModuleInstallError as err:
            QMessageBox.critical(
                self, self.tr('Update error'),
                unicode(self.tr('Unable to update modules: %s' % (err))),
                QMessageBox.Ok)
        pd.setValue(100)
        self.loadModules()
        QMessageBox.information(self, self.tr('Update of modules'),
                                self.tr('Modules updated!'), QMessageBox.Ok)

    def editRepositories(self):
        if RepositoriesDialog(self.weboob.repositories.sources_list).exec_():
            self.updateModules()

    def loadModules(self):
        self.ui.modulesList.clear()
        for name, module in sorted(
                self.weboob.repositories.get_all_modules_info(
                    self.caps).iteritems()):
            item = QListWidgetItem(name.capitalize())
            self.set_icon(item, module)
            self.ui.modulesList.addItem(item)

    def askInstallModule(self, minfo):
        reply = QMessageBox.question(
            self, self.tr('Install a module'),
            unicode(
                self.
                tr("Module %s is not installed. Do you want to install it?")) %
            minfo.name, QMessageBox.Yes | QMessageBox.No)

        if reply != QMessageBox.Yes:
            return False

        return self.installModule(minfo)

    def installModule(self, minfo):
        pd = ProgressDialog('Installation of %s' % minfo.name, "Cancel", 0,
                            100, self)
        pd.setWindowModality(Qt.WindowModal)

        try:
            self.weboob.repositories.install(minfo, pd)
        except ModuleInstallError as err:
            QMessageBox.critical(
                self, self.tr('Install error'),
                unicode(
                    self.tr('Unable to install module %s: %s' %
                            (minfo.name, err))), QMessageBox.Ok)
        pd.setValue(100)
        return True

    def loadBackendsList(self):
        self.ui.backendsList.clear()
        for instance_name, name, params in self.weboob.backends_config.iter_backends(
        ):
            info = self.weboob.repositories.get_module_info(name)
            if not info or (self.caps and not info.has_caps(self.caps)):
                continue

            item = QTreeWidgetItem(None, [instance_name, name])
            item.setCheckState(
                0, Qt.Checked if params.get('_enabled', '1').lower()
                in ('1', 'y', 'true', 'on', 'yes') else Qt.Unchecked)

            self.set_icon(item, info)

            self.ui.backendsList.addTopLevelItem(item)

    def backendEnabled(self, item, col):
        self.is_enabling += 1

        instname = unicode(item.text(0))
        bname = unicode(item.text(1))
        if item.checkState(0) == Qt.Checked:
            self.to_load.add(instname)
            enabled = 'true'
        else:
            self.to_unload.add(instname)
            try:
                self.to_load.remove(instname)
            except KeyError:
                pass
            enabled = 'false'

        self.weboob.backends_config.edit_backend(instname, bname,
                                                 {'_enabled': enabled})

    def backendClicked(self, item, col):
        if self.is_enabling:
            self.is_enabling -= 1
            return

        bname = unicode(item.text(0))

        self.editBackend(bname)

    def addEvent(self):
        self.editBackend()

    def removeEvent(self):
        item = self.ui.backendsList.currentItem()
        if not item:
            return

        bname = unicode(item.text(0))
        reply = QMessageBox.question(
            self, self.tr('Remove a backend'),
            unicode(
                self.tr("Are you sure you want to remove the backend '%s'?")) %
            bname, QMessageBox.Yes | QMessageBox.No)

        if reply != QMessageBox.Yes:
            return

        self.weboob.backends_config.remove_backend(bname)
        self.to_unload.add(bname)
        try:
            self.to_load.remove(bname)
        except KeyError:
            pass
        self.ui.configFrame.hide()
        self.loadBackendsList()

    def editBackend(self, name=None):
        self.ui.registerButton.hide()
        self.ui.configFrame.show()

        if name is not None:
            bname, params = self.weboob.backends_config.get_backend(name)

            items = self.ui.modulesList.findItems(bname, Qt.MatchFixedString)
            if not items:
                warning('Backend not found')
            else:
                self.ui.modulesList.setCurrentItem(items[0])
                self.ui.modulesList.setEnabled(False)

            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'))
            else:
                self.ui.proxyBox.setChecked(False)
                self.ui.proxyEdit.clear()

            params.pop('_enabled', None)

            info = self.weboob.repositories.get_module_info(bname)
            if info and (info.is_installed() or self.installModule(info)):
                module = self.weboob.modules_loader.get_or_load_module(bname)
                for key, value in module.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:
                        # Do not prompt user for value (for example a password if it is empty).
                        value.noprompt = True
                        widget.set_value(value)
                return

        self.ui.nameEdit.clear()
        self.ui.nameEdit.setEnabled(True)
        self.ui.proxyBox.setChecked(False)
        self.ui.proxyEdit.clear()
        self.ui.modulesList.setEnabled(True)
        self.ui.modulesList.setCurrentRow(-1)

    def moduleSelectionChanged(self):
        for key, (label, value) in self.config_widgets.iteritems():
            label.hide()
            value.hide()
            self.ui.configLayout.removeWidget(label)
            self.ui.configLayout.removeWidget(value)
            label.deleteLater()
            value.deleteLater()
        self.config_widgets = {}
        self.ui.moduleInfo.clear()

        selection = self.ui.modulesList.selectedItems()
        if not selection:
            return

        minfo = self.weboob.repositories.get_module_info(
            unicode(selection[0].text()).lower())
        if not minfo:
            warning('Module not found')
            return

        if not minfo.is_installed() and not self.installModule(minfo):
            self.editBackend(None)
            return

        module = self.weboob.modules_loader.get_or_load_module(minfo.name)

        icon_path = os.path.join(self.weboob.repositories.icons_dir,
                                 '%s.png' % minfo.name)
        img = QImage(icon_path)
        self.ui.moduleInfo.document().addResource(QTextDocument.ImageResource,
                                                  QUrl('mydata://logo.png'),
                                                  QVariant(img))

        if module.name not in [
                n for n, ign, ign2 in
                self.weboob.backends_config.iter_backends()
        ]:
            self.ui.nameEdit.setText(module.name)
        else:
            self.ui.nameEdit.setText('')

        self.ui.moduleInfo.setText(
            to_unicode(
                self.tr(u'<h1>%s Module %s</h1>'
                        '<b>Version</b>: %s<br />'
                        '<b>Maintainer</b>: %s<br />'
                        '<b>License</b>: %s<br />'
                        '%s'
                        '<b>Description</b>: %s<br />'
                        '<b>Capabilities</b>: %s<br />')) %
            ('<img src="mydata://logo.png" />', module.name.capitalize(),
             module.version, to_unicode(module.maintainer).replace(
                 u'&', u'&amp;').replace(u'<', u'&lt;').replace(
                     u'>', u'&gt;'), module.license,
             (unicode(self.tr('<b>Website</b>: %s<br />')) % module.website)
             if module.website else '', module.description, ', '.join(
                 sorted(
                     cap.__name__.replace('Cap', '')
                     for cap in module.iter_caps()))))

        if module.has_caps(CapAccount) and self.ui.nameEdit.isEnabled() and \
                module.klass.ACCOUNT_REGISTER_PROPERTIES is not None:
            self.ui.registerButton.show()
        else:
            self.ui.registerButton.hide()

        for key, field in module.config.iteritems():
            label = QLabel(u'%s:' % field.label)
            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.modulesList.selectedItems()

        if not selection:
            QMessageBox.critical(self, self.tr('Unable to add a backend'),
                                 self.tr('Please select a module'))
            return

        try:
            module = self.weboob.modules_loader.get_or_load_module(
                unicode(selection[0].text()).lower())
        except ModuleLoadError:
            module = None

        if not module:
            QMessageBox.critical(
                self, self.tr('Unable to add a backend'),
                self.tr('The selected module 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 = module.config.load(self.weboob,
                                    module.name,
                                    bname, {},
                                    nofail=True)
        for key, field in config.iteritems():
            label, qtvalue = self.config_widgets[key]

            try:
                value = qtvalue.get_value()
            except ValueError as 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.loadBackendsList()

    def rejectBackend(self):
        self.ui.configFrame.hide()

    def registerEvent(self):
        selection = self.ui.modulesList.selectedItems()
        if not selection:
            return

        try:
            module = self.weboob.modules_loader.get_or_load_module(
                unicode(selection[0].text()).lower())
        except ModuleLoadError:
            module = None

        if not module:
            return

        dialog = QDialog(self)
        vbox = QVBoxLayout(dialog)
        if module.website:
            website = 'on the website <b>%s</b>' % module.website
        else:
            website = 'with the module <b>%s</b>' % module.name
        vbox.addWidget(
            QLabel(
                'To create an account %s, please provide this information:' %
                website))
        formlayout = QFormLayout()
        props_widgets = OrderedDict()
        for key, prop in module.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 as e:
                        QMessageBox.critical(
                            self, self.tr('Invalid value'),
                            unicode(
                                self.
                                tr('Invalid value for field "%s":<br /><br />%s'
                                   )) % (key, e))
                        end = False
                        break
                    else:
                        account.properties[key] = v
                if end:
                    try:
                        module.klass.register_account(account)
                    except AccountRegisterError as e:
                        QMessageBox.critical(
                            self, self.tr('Error during register'),
                            unicode(
                                self.
                                tr('Unable to register account %s:<br /><br />%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_value(value)

    def run(self):
        self.exec_()

        ret = (len(self.to_load) > 0 or len(self.to_unload) > 0)

        self.weboob.unload_backends(self.to_unload)
        self.weboob.load_backends(names=self.to_load)

        return ret
Example #5
0
class BackendCfg(QDialog):
    def __init__(self, weboob, caps=None, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_BackendCfg()
        self.ui.setupUi(self)

        self.ui.backendsList.sortByColumn(0, Qt.AscendingOrder)

        self.to_unload = set()
        self.to_load = set()

        self.weboob = weboob
        self.caps = caps
        self.config_widgets = {}

        # This attribute is set when itemChanged it called, because when
        # a backend is enabled/disabled, we don't want to display its config
        # frame, and the itemClicked event is always emit just after a
        # itemChanged event.
        # is_enabling is a counter to prevent race conditions.
        self.is_enabling = 0

        self.ui.backendsList.header().setResizeMode(
            QHeaderView.ResizeToContents)
        self.ui.configFrame.hide()

        self.icon_cache = {}
        self.icon_threads = {}

        self.loadModules()
        self.loadBackendsList()

        self.connect(self.ui.updateButton, SIGNAL('clicked()'),
                     self.updateModules)
        self.connect(self.ui.repositoriesButton, SIGNAL('clicked()'),
                     self.editRepositories)
        self.connect(self.ui.backendsList,
                     SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
                     self.backendClicked)
        self.connect(self.ui.backendsList,
                     SIGNAL('itemChanged(QTreeWidgetItem *, int)'),
                     self.backendEnabled)
        self.connect(self.ui.modulesList, SIGNAL('itemSelectionChanged()'),
                     self.moduleSelectionChanged)
        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)

    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 set_icon(self, item, minfo):
        icon_path = self.weboob.repositories.get_module_icon_path(minfo)

        icon = self.icon_cache.get(icon_path, None)
        if icon is None and not os.path.exists(icon_path):
            if minfo.name in self.icon_threads:
                self.icon_threads[minfo.name].items.append(item)
            else:
                thread = IconFetcher(self.weboob, item, minfo)
                self.connect(thread, SIGNAL('retrieved'),
                             lambda t: self._set_icon(t.items, t.minfo))
                self.icon_threads[minfo.name] = thread
                thread.start()
            return

        self._set_icon([item], minfo)

    def _set_icon(self, items, minfo):
        icon_path = self.weboob.repositories.get_module_icon_path(minfo)
        icon = self.get_icon_cache(icon_path)

        if icon is None:
            return

        for item in items:
            try:
                item.setIcon(icon)
            except TypeError:
                item.setIcon(0, icon)

        self.icon_threads.pop(minfo.name, None)

    def updateModules(self):
        self.ui.configFrame.hide()
        pd = ProgressDialog('Update of modules', "Cancel", 0, 100, self)
        pd.setWindowModality(Qt.WindowModal)
        try:
            self.weboob.repositories.update(pd)
        except ModuleInstallError, err:
            QMessageBox.critical(
                self, self.tr('Update error'),
                unicode(self.tr('Unable to update modules: %s' % (err))),
                QMessageBox.Ok)
        pd.setValue(100)
        self.loadModules()
        QMessageBox.information(self, self.tr('Update of modules'),
                                self.tr('Modules updated!'), QMessageBox.Ok)
Example #6
0
class BackendCfg(QDialog):
    def __init__(self, weboob, caps=None, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_BackendCfg()
        self.ui.setupUi(self)

        self.ui.backendsList.sortByColumn(0, Qt.AscendingOrder)

        self.to_unload = set()
        self.to_load = set()

        self.weboob = weboob
        self.caps = caps
        self.config_widgets = {}

        # This attribute is set when itemChanged it called, because when
        # a backend is enabled/disabled, we don't want to display its config
        # frame, and the itemClicked event is always emit just after a
        # itemChanged event.
        # is_enabling is a counter to prevent race conditions.
        self.is_enabling = 0

        self.ui.backendsList.header().setResizeMode(QHeaderView.ResizeToContents)
        self.ui.configFrame.hide()

        self.icon_cache = {}
        self.icon_threads = {}

        self.loadModules()
        self.loadBackendsList()

        self.connect(self.ui.updateButton, SIGNAL('clicked()'), self.updateModules)
        self.connect(self.ui.repositoriesButton, SIGNAL('clicked()'), self.editRepositories)
        self.connect(self.ui.backendsList, SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
                     self.backendClicked)
        self.connect(self.ui.backendsList, SIGNAL('itemChanged(QTreeWidgetItem *, int)'),
                     self.backendEnabled)
        self.connect(self.ui.modulesList, SIGNAL('itemSelectionChanged()'), self.moduleSelectionChanged)
        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)

    def get_icon_cache(self, path):
        if path not in self.icon_cache:
            img = QImage(path)
            self.icon_cache[path] = QIcon(QPixmap.fromImage(img))
        return self.icon_cache[path]

    def set_icon(self, item, minfo):
        icon_path = self.weboob.repositories.get_module_icon_path(minfo)

        icon = self.icon_cache.get(icon_path, None)
        if icon is None and not os.path.exists(icon_path):
            if minfo.name in self.icon_threads:
                self.icon_threads[minfo.name].items.append(item)
            else:
                thread = IconFetcher(self.weboob, item, minfo)
                self.connect(thread, SIGNAL('retrieved'), lambda t: self._set_icon(t.items, t.minfo))
                self.icon_threads[minfo.name] = thread
                thread.start()
            return

        self._set_icon([item], minfo)

    def _set_icon(self, items, minfo):
        icon_path = self.weboob.repositories.get_module_icon_path(minfo)
        icon = self.get_icon_cache(icon_path)

        if icon is None:
            return

        for item in items:
            try:
                item.setIcon(icon)
            except TypeError:
                item.setIcon(0, icon)

        self.icon_threads.pop(minfo.name, None)

    def updateModules(self):
        self.ui.configFrame.hide()
        pd = ProgressDialog('Update of modules', "Cancel", 0, 100, self)
        pd.setWindowModality(Qt.WindowModal)
        try:
            self.weboob.repositories.update(pd)
        except ModuleInstallError as err:
            QMessageBox.critical(self, self.tr('Update error'),
                                 unicode(self.tr('Unable to update modules: %s' % (err))),
                                 QMessageBox.Ok)
        pd.setValue(100)
        self.loadModules()
        QMessageBox.information(self, self.tr('Update of modules'),
                                self.tr('Modules updated!'), QMessageBox.Ok)

    def editRepositories(self):
        if RepositoriesDialog(self.weboob.repositories.sources_list).exec_():
            self.updateModules()

    def loadModules(self):
        self.ui.modulesList.clear()
        for name, module in sorted(self.weboob.repositories.get_all_modules_info(self.caps).iteritems()):
            item = QListWidgetItem(name.capitalize())
            self.set_icon(item, module)
            self.ui.modulesList.addItem(item)

    def askInstallModule(self, minfo):
        reply = QMessageBox.question(self, self.tr('Install a module'),
            unicode(self.tr("Module %s is not installed. Do you want to install it?")) % minfo.name,
            QMessageBox.Yes|QMessageBox.No)

        if reply != QMessageBox.Yes:
            return False

        return self.installModule(minfo)

    def installModule(self, minfo):
        pd = ProgressDialog('Installation of %s' % minfo.name, "Cancel", 0, 100, self)
        pd.setWindowModality(Qt.WindowModal)

        try:
            self.weboob.repositories.install(minfo, pd)
        except ModuleInstallError as err:
            QMessageBox.critical(self, self.tr('Install error'),
                                 unicode(self.tr('Unable to install module %s: %s' % (minfo.name, err))),
                                 QMessageBox.Ok)
        pd.setValue(100)
        return True

    def loadBackendsList(self):
        self.ui.backendsList.clear()
        for instance_name, name, params in self.weboob.backends_config.iter_backends():
            info = self.weboob.repositories.get_module_info(name)
            if not info or (self.caps and not info.has_caps(self.caps)):
                continue

            item = QTreeWidgetItem(None, [instance_name, name])
            item.setCheckState(0, Qt.Checked if params.get('_enabled', '1').lower() in ('1', 'y', 'true')
                else Qt.Unchecked)

            self.set_icon(item, info)

            self.ui.backendsList.addTopLevelItem(item)

    def backendEnabled(self, item, col):
        self.is_enabling += 1

        instname = unicode(item.text(0))
        bname = unicode(item.text(1))
        if item.checkState(0) == Qt.Checked:
            self.to_load.add(instname)
            enabled = '1'
        else:
            self.to_unload.add(instname)
            try:
                self.to_load.remove(instname)
            except KeyError:
                pass
            enabled = '0'

        self.weboob.backends_config.edit_backend(instname, bname, {'_enabled': enabled})

    def backendClicked(self, item, col):
        if self.is_enabling:
            self.is_enabling -= 1
            return

        bname = unicode(item.text(0))

        self.editBackend(bname)

    def addEvent(self):
        self.editBackend()

    def removeEvent(self):
        item = self.ui.backendsList.currentItem()
        if not item:
            return

        bname = unicode(item.text(0))
        reply = QMessageBox.question(self, self.tr('Remove a backend'),
            unicode(self.tr("Are you sure you want to remove the backend '%s'?")) % bname,
            QMessageBox.Yes|QMessageBox.No)

        if reply != QMessageBox.Yes:
            return

        self.weboob.backends_config.remove_backend(bname)
        self.to_unload.add(bname)
        try:
            self.to_load.remove(bname)
        except KeyError:
            pass
        self.ui.configFrame.hide()
        self.loadBackendsList()

    def editBackend(self, name=None):
        self.ui.registerButton.hide()
        self.ui.configFrame.show()

        if name is not None:
            bname, params = self.weboob.backends_config.get_backend(name)

            items = self.ui.modulesList.findItems(bname, Qt.MatchFixedString)
            if not items:
                warning('Backend not found')
            else:
                self.ui.modulesList.setCurrentItem(items[0])
                self.ui.modulesList.setEnabled(False)

            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'))
            else:
                self.ui.proxyBox.setChecked(False)
                self.ui.proxyEdit.clear()

            params.pop('_enabled', None)

            info = self.weboob.repositories.get_module_info(bname)
            if info and (info.is_installed() or self.installModule(info)):
                module = self.weboob.modules_loader.get_or_load_module(bname)
                for key, value in module.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:
                        # Do not prompt user for value (for example a password if it is empty).
                        value.noprompt = True
                        widget.set_value(value)
                return

        self.ui.nameEdit.clear()
        self.ui.nameEdit.setEnabled(True)
        self.ui.proxyBox.setChecked(False)
        self.ui.proxyEdit.clear()
        self.ui.modulesList.setEnabled(True)
        self.ui.modulesList.setCurrentRow(-1)

    def moduleSelectionChanged(self):
        for key, (label, value) in self.config_widgets.iteritems():
            label.hide()
            value.hide()
            self.ui.configLayout.removeWidget(label)
            self.ui.configLayout.removeWidget(value)
            label.deleteLater()
            value.deleteLater()
        self.config_widgets = {}
        self.ui.moduleInfo.clear()

        selection = self.ui.modulesList.selectedItems()
        if not selection:
            return

        minfo = self.weboob.repositories.get_module_info(unicode(selection[0].text()).lower())
        if not minfo:
            warning('Module not found')
            return

        if not minfo.is_installed() and not self.installModule(minfo):
            self.editBackend(None)
            return

        module = self.weboob.modules_loader.get_or_load_module(minfo.name)

        icon_path = os.path.join(self.weboob.repositories.icons_dir, '%s.png' % minfo.name)
        img = QImage(icon_path)
        self.ui.moduleInfo.document().addResource(QTextDocument.ImageResource, QUrl('mydata://logo.png'),
            QVariant(img))

        if module.name not in [n for n, ign, ign2 in self.weboob.backends_config.iter_backends()]:
            self.ui.nameEdit.setText(module.name)
        else:
            self.ui.nameEdit.setText('')

        self.ui.moduleInfo.setText(to_unicode(self.tr(
          u'<h1>%s Module %s</h1>'
           '<b>Version</b>: %s<br />'
           '<b>Maintainer</b>: %s<br />'
           '<b>License</b>: %s<br />'
           '%s'
           '<b>Description</b>: %s<br />'
           '<b>Capabilities</b>: %s<br />'))
           % ('<img src="mydata://logo.png" />',
              module.name.capitalize(),
              module.version,
              to_unicode(module.maintainer).replace(u'&', u'&amp;').replace(u'<', u'&lt;').replace(u'>', u'&gt;'),
              module.license,
              (unicode(self.tr('<b>Website</b>: %s<br />')) % module.website) if module.website else '',
              module.description,
              ', '.join(sorted(cap.__name__.replace('Cap', '') for cap in module.iter_caps()))))

        if module.has_caps(CapAccount) and self.ui.nameEdit.isEnabled() and \
                module.klass.ACCOUNT_REGISTER_PROPERTIES is not None:
            self.ui.registerButton.show()
        else:
            self.ui.registerButton.hide()

        for key, field in module.config.iteritems():
            label = QLabel(u'%s:' % field.label)
            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.modulesList.selectedItems()

        if not selection:
            QMessageBox.critical(self, self.tr('Unable to add a backend'),
                self.tr('Please select a module'))
            return

        try:
            module = self.weboob.modules_loader.get_or_load_module(unicode(selection[0].text()).lower())
        except ModuleLoadError:
            module = None

        if not module:
            QMessageBox.critical(self, self.tr('Unable to add a backend'),
                self.tr('The selected module 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 = module.config.load(self.weboob, module.name, bname, {}, nofail=True)
        for key, field in config.iteritems():
            label, qtvalue = self.config_widgets[key]

            try:
                value = qtvalue.get_value()
            except ValueError as 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.loadBackendsList()

    def rejectBackend(self):
        self.ui.configFrame.hide()

    def registerEvent(self):
        selection = self.ui.modulesList.selectedItems()
        if not selection:
            return

        try:
            module = self.weboob.modules_loader.get_or_load_module(unicode(selection[0].text()).lower())
        except ModuleLoadError:
            module = None

        if not module:
            return

        dialog = QDialog(self)
        vbox = QVBoxLayout(dialog)
        if module.website:
            website = 'on the website <b>%s</b>' % module.website
        else:
            website = 'with the module <b>%s</b>' % module.name
        vbox.addWidget(QLabel('To create an account %s, please provide this information:' % website))
        formlayout = QFormLayout()
        props_widgets = OrderedDict()
        for key, prop in module.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 as e:
                        QMessageBox.critical(self, self.tr('Invalid value'),
                            unicode(self.tr('Invalid value for field "%s":<br /><br />%s')) % (key, e))
                        end = False
                        break
                    else:
                        account.properties[key] = v
                if end:
                    try:
                        module.klass.register_account(account)
                    except AccountRegisterError as e:
                        QMessageBox.critical(self, self.tr('Error during register'),
                            unicode(self.tr('Unable to register account %s:<br /><br />%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_value(value)

    def run(self):
        self.exec_()

        ret = (len(self.to_load) > 0 or len(self.to_unload) > 0)

        self.weboob.unload_backends(self.to_unload)
        self.weboob.load_backends(names=self.to_load)

        return ret
Example #7
0
class BackendCfg(QDialog):
    def __init__(self, weboob, caps=None, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_BackendCfg()
        self.ui.setupUi(self)

        self.ui.backendsList.sortByColumn(0, Qt.AscendingOrder)

        self.to_unload = set()
        self.to_load = set()

        self.weboob = weboob
        self.caps = caps
        self.config_widgets = {}

        # This attribute is set when itemChanged it called, because when
        # a backend is enabled/disabled, we don't want to display its config
        # frame, and the itemClicked event is always emit just after a
        # itemChanged event.
        # is_enabling is a counter to prevent race conditions.
        self.is_enabling = 0

        self.ui.backendsList.header().setResizeMode(QHeaderView.ResizeToContents)
        self.ui.configFrame.hide()

        self.icon_cache = {}
        self.icon_threads = {}

        self.loadModules()
        self.loadBackendsList()

        self.connect(self.ui.updateButton, SIGNAL('clicked()'), self.updateModules)
        self.connect(self.ui.repositoriesButton, SIGNAL('clicked()'), self.editRepositories)
        self.connect(self.ui.backendsList, SIGNAL('itemClicked(QTreeWidgetItem *, int)'),
                     self.backendClicked)
        self.connect(self.ui.backendsList, SIGNAL('itemChanged(QTreeWidgetItem *, int)'),
                     self.backendEnabled)
        self.connect(self.ui.modulesList, SIGNAL('itemSelectionChanged()'), self.moduleSelectionChanged)
        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)

    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 set_icon(self, item, minfo):
        icon_path = self.weboob.repositories.get_module_icon_path(minfo)

        icon = self.icon_cache.get(icon_path, None)
        if icon is None and not os.path.exists(icon_path):
            if minfo.name in self.icon_threads:
                self.icon_threads[minfo.name].items.append(item)
            else:
                thread = IconFetcher(self.weboob, item, minfo)
                self.connect(thread, SIGNAL('retrieved'), lambda t: self._set_icon(t.items, t.minfo))
                self.icon_threads[minfo.name] = thread
                thread.start()
            return

        self._set_icon([item], minfo)

    def _set_icon(self, items, minfo):
        icon_path = self.weboob.repositories.get_module_icon_path(minfo)
        icon = self.get_icon_cache(icon_path)

        if icon is None:
            return

        for item in items:
            try:
                item.setIcon(icon)
            except TypeError:
                item.setIcon(0, icon)

        self.icon_threads.pop(minfo.name, None)

    def updateModules(self):
        self.ui.configFrame.hide()
        pd = ProgressDialog('Update of modules', "Cancel", 0, 100, self)
        pd.setWindowModality(Qt.WindowModal)
        try:
            self.weboob.repositories.update(pd)
        except ModuleInstallError, err:
            QMessageBox.critical(self, self.tr('Update error'),
                                 unicode(self.tr('Unable to update modules: %s' % (err))),
                                 QMessageBox.Ok)
        pd.setValue(100)
        self.loadModules()
        QMessageBox.information(self, self.tr('Update of modules'),
                                self.tr('Modules updated!'), QMessageBox.Ok)
Example #8
0
class BackendCfg(QDialog):
    def __init__(self, weboob, caps=None, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_BackendCfg()
        self.ui.setupUi(self)

        self.to_unload = set()
        self.to_load = set()

        self.weboob = weboob
        self.caps = caps
        self.config_widgets = {}

        # This attribute is set when itemChanged it called, because when
        # a backend is enabled/disabled, we don't want to display its config
        # frame, and the itemClicked event is always emit just after a
        # itemChanged event.
        # is_enabling is a counter to prevent race conditions.
        self.is_enabling = 0

        self.weboob.modules_loader.load_all()

        self.ui.configuredBackendsList.header().setResizeMode(QHeaderView.ResizeToContents)
        self.ui.configFrame.hide()

        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)))

                self.ui.backendsList.addItem(item)

        self.loadConfiguredBackendsList()

        self.connect(self.ui.configuredBackendsList, SIGNAL('itemClicked(QTreeWidgetItem *, int)'), self.configuredBackendClicked)
        self.connect(self.ui.configuredBackendsList, SIGNAL('itemChanged(QTreeWidgetItem *, int)'), self.configuredBackendEnabled)
        self.connect(self.ui.backendsList, SIGNAL('itemSelectionChanged()'), self.backendSelectionChanged)
        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)

    def loadConfiguredBackendsList(self):
        self.ui.configuredBackendsList.clear()
        for instance_name, name, params in self.weboob.backends_config.iter_backends():
            try:
                backend = self.weboob.modules_loader.get_or_load_module(name)
            except ModuleLoadError:
                backend = None

            if not backend or self.caps and not backend.has_caps(*self.caps):
                continue

            item = QTreeWidgetItem(None, [instance_name, name])
            item.setCheckState(0, Qt.Checked if params.get('_enabled', '1').lower() in ('1', 'y', 'true') else Qt.Unchecked)

            if backend.icon_path:
                img = QImage(backend.icon_path)
                item.setIcon(0, QIcon(QPixmap.fromImage(img)))

            self.ui.configuredBackendsList.addTopLevelItem(item)

    def configuredBackendEnabled(self, item, col):
        self.is_enabling += 1

        instname = unicode(item.text(0))
        bname = unicode(item.text(1))
        if item.checkState(0) == Qt.Checked:
            self.to_load.add(instname)
            enabled = '1'
        else:
            self.to_unload.add(instname)
            try:
                self.to_load.remove(instname)
            except KeyError:
                pass
            enabled = '0'

        self.weboob.backends_config.edit_backend(instname, bname, {'_enabled': enabled})

    def configuredBackendClicked(self, item, col):
        if self.is_enabling:
            self.is_enabling -= 1
            return

        bname = unicode(item.text(0))

        self.editBackend(bname)

    def addEvent(self):
        self.editBackend()

    def removeEvent(self):
        item = self.ui.configuredBackendsList.currentItem()
        if not item:
            return

        bname = unicode(item.text(0))
        reply = QMessageBox.question(self, self.tr('Remove a backend'),
                                     unicode(self.tr("Are you sure you want to remove the backend '%s'?")) % bname,
                                     QMessageBox.Yes|QMessageBox.No)

        if reply != QMessageBox.Yes:
            return

        self.weboob.backends_config.remove_backend(bname)
        self.to_unload.add(bname)
        try:
            self.to_load.remove(bname)
        except KeyError:
            pass
        self.ui.configFrame.hide()
        self.loadConfiguredBackendsList()

    def editBackend(self, bname=None):
        self.ui.registerButton.hide()
        self.ui.configFrame.show()

        if bname is not None:
            mname, params = self.weboob.backends_config.get_backend(bname)

            items = self.ui.backendsList.findItems(mname, 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.setEnabled(False)
            if '_proxy' in params:
                self.ui.proxyBox.setChecked(True)
                self.ui.proxyEdit.setText(params.pop('_proxy'))
            else:
                self.ui.proxyBox.setChecked(False)
                self.ui.proxyEdit.clear()

            params.pop('_enabled', None)

            for key, value in params.iteritems():
                try:
                    l, widget = self.config_widgets[key]
                except KeyError:
                    warning('Key "%s" is not found' % key)
                else:
                    widget.set_data(value)
        else:
            self.ui.nameEdit.clear()
            self.ui.nameEdit.setEnabled(True)
            self.ui.proxyBox.setChecked(False)
            self.ui.proxyEdit.clear()
            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

        self.weboob.backends_config.add_backend(bname, backend.name, params, edit=not self.ui.nameEdit.isEnabled())
        self.to_load.add(bname)
        self.ui.configFrame.hide()

        self.loadConfiguredBackendsList()