diff --git a/build.mk b/build.mk
index 090df13a760f8a3be9a654fcd9c3ae69e6f6e380..f9c3929c404cb33f7f810a365b4eae03510256a1 100644
--- a/build.mk
+++ b/build.mk
@@ -1,4 +1,4 @@
-core := weboob/tools/application/qt weboob/tools/application/qt5
+core := weboob/tools/application/qt5
applications := qboobmsg qhavedate qwebcontentedit qflatboob qcineoob qcookboob qhandjoob qbooblyrics
ifeq ($(WIN32),)
applications += qvideoob
diff --git a/weboob/tools/application/qt/Makefile b/weboob/tools/application/qt/Makefile
deleted file mode 100644
index 9ec35f9a33b073c1ffda13d25b97b11dd9bea0e7..0000000000000000000000000000000000000000
--- a/weboob/tools/application/qt/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-UI_FILES = $(wildcard *.ui)
-UI_PY_FILES = $(UI_FILES:%.ui=%_ui.py)
-PYUIC = pyuic4
-
-all: $(UI_PY_FILES)
-
-%_ui.py: %.ui
- $(PYUIC) -o $@ $^
-
-clean:
- rm -f *.pyc
- rm -f $(UI_PY_FILES)
diff --git a/weboob/tools/application/qt/__init__.py b/weboob/tools/application/qt/__init__.py
deleted file mode 100644
index af213a8c2fd36edbe6a3b7c2fe566528bd7ec5db..0000000000000000000000000000000000000000
--- a/weboob/tools/application/qt/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from .qt import QtApplication, QtMainWindow, QtDo, HTMLDelegate
-from .backendcfg import BackendCfg
-
-__all__ = ['QtApplication', 'QtMainWindow', 'QtDo', 'HTMLDelegate',
- 'BackendCfg']
diff --git a/weboob/tools/application/qt/backendcfg.py b/weboob/tools/application/qt/backendcfg.py
deleted file mode 100644
index 5f19696bc6154298a629ed9eaff47d365cdff2be..0000000000000000000000000000000000000000
--- a/weboob/tools/application/qt/backendcfg.py
+++ /dev/null
@@ -1,559 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright(C) 2010-2012 Romain Bignon
-#
-# This file is part of weboob.
-#
-# weboob is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# weboob is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with weboob. If not, see .
-
-
-from PyQt4.QtGui import QDialog, QTreeWidgetItem, QLabel, QFormLayout, \
- QMessageBox, QPixmap, QImage, QIcon, QHeaderView, \
- QListWidgetItem, QTextDocument, QVBoxLayout, \
- QDialogButtonBox, QProgressDialog
-from PyQt4.QtCore import Qt, QVariant, QUrl, QThread
-from PyQt4.QtCore import pyqtSignal as Signal, pyqtSlot as Slot
-
-import re
-import os
-from logging import warning
-
-from weboob.core.repositories import IProgress
-from weboob.core.backendscfg import BackendAlreadyExists
-from weboob.capabilities.account import CapAccount, Account, AccountRegisterError
-from weboob.exceptions import ModuleInstallError, ModuleLoadError
-from .backendcfg_ui import Ui_BackendCfg
-from .reposdlg_ui import Ui_RepositoriesDlg
-from weboob.tools.ordereddict import OrderedDict
-from weboob.tools.misc import to_unicode
-from .qt import QtValue
-
-
-class RepositoriesDialog(QDialog):
- def __init__(self, filename, parent=None):
- QDialog.__init__(self, parent)
- self.filename = filename
- self.ui = Ui_RepositoriesDlg()
- self.ui.setupUi(self)
-
- self.ui.buttonBox.accepted.connect(self.save)
-
- with open(self.filename, 'r') as fp:
- self.ui.reposEdit.setPlainText(fp.read())
-
- @Slot()
- def save(self):
- with open(self.filename, 'w') as fp:
- fp.write(self.ui.reposEdit.toPlainText())
- self.accept()
-
-
-class IconFetcher(QThread):
- retrieved = Signal()
-
- def __init__(self, weboob, item, minfo):
- QThread.__init__(self)
- self.weboob = weboob
- self.items = [item]
- self.minfo = minfo
-
- def run(self):
- self.weboob.repositories.retrieve_icon(self.minfo)
- self.retrieved.emit()
-
-
-class ProgressDialog(IProgress, QProgressDialog):
- def __init__(self, *args, **kwargs):
- QProgressDialog.__init__(self, *args, **kwargs)
-
- def progress(self, percent, message):
- self.setValue(int(percent * 100))
- self.setLabelText(message)
-
- def error(self, message):
- QMessageBox.critical(self, self.tr('Error'), '%s' % message, QMessageBox.Ok)
-
- def prompt(self, message):
- reply = QMessageBox.question(self, '', unicode(message), QMessageBox.Yes|QMessageBox.No)
-
- return reply == QMessageBox.Yes
-
-
-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.ui.updateButton.clicked.connect(self.updateModules)
- self.ui.repositoriesButton.clicked.connect(self.editRepositories)
- self.ui.backendsList.itemClicked.connect(self.backendClicked)
- self.ui.backendsList.itemChanged.connect(self.backendEnabled)
- self.ui.modulesList.itemSelectionChanged.connect(self.moduleSelectionChanged)
- self.ui.proxyBox.toggled.connect(self.proxyEditEnabled)
- self.ui.addButton.clicked.connect(self.addEvent)
- self.ui.removeButton.clicked.connect(self.removeEvent)
- self.ui.registerButton.clicked.connect(self.registerEvent)
- self.ui.configButtonBox.accepted.connect(self.acceptBackend)
- self.ui.configButtonBox.rejected.connect(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)
- thread.retrieved.connect(self._set_icon_slot)
- self.icon_threads[minfo.name] = thread
- thread.start()
- return
-
- self._set_icon([item], minfo)
-
- @Slot()
- def _set_icon_slot(self):
- thread = self.sender()
- self._set_icon(thread.items, thread.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)
-
- @Slot()
- 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)
-
- @Slot()
- 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 backend_name, module_name, params in self.weboob.backends_config.iter_backends():
- info = self.weboob.repositories.get_module_info(module_name)
- if not info or (self.caps and not info.has_caps(self.caps)):
- continue
-
- item = QTreeWidgetItem(None, [backend_name, module_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)
-
- @Slot(object, object)
- def backendEnabled(self, item, col):
- self.is_enabling += 1
-
- backend_name = unicode(item.text(0))
- module_name = unicode(item.text(1))
- if item.checkState(0) == Qt.Checked:
- self.to_load.add(backend_name)
- enabled = 'true'
- else:
- self.to_unload.add(backend_name)
- try:
- self.to_load.remove(backend_name)
- except KeyError:
- pass
- enabled = 'false'
-
- self.weboob.backends_config.edit_backend(backend_name, module_name, {'_enabled': enabled})
-
- @Slot(object, object)
- def backendClicked(self, item, col):
- if self.is_enabling:
- self.is_enabling -= 1
- return
-
- backend_name = unicode(item.text(0))
-
- self.editBackend(backend_name)
-
- @Slot()
- def addEvent(self):
- self.editBackend()
-
- @Slot()
- def removeEvent(self):
- item = self.ui.backendsList.currentItem()
- if not item:
- return
-
- backend_name = 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'?")) % backend_name,
- QMessageBox.Yes|QMessageBox.No)
-
- if reply != QMessageBox.Yes:
- return
-
- self.weboob.backends_config.remove_backend(backend_name)
- self.to_unload.add(backend_name)
- try:
- self.to_load.remove(backend_name)
- except KeyError:
- pass
- self.ui.configFrame.hide()
- self.loadBackendsList()
-
- def editBackend(self, backend_name=None):
- self.ui.registerButton.hide()
- self.ui.configFrame.show()
-
- if backend_name is not None:
- module_name, params = self.weboob.backends_config.get_backend(backend_name)
-
- items = self.ui.modulesList.findItems(module_name, 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(backend_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(module_name)
- if info and (info.is_installed() or self.installModule(info)):
- module = self.weboob.modules_loader.get_or_load_module(module_name)
- for key, value in module.config.load(self.weboob, module_name, backend_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)
-
- @Slot()
- 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'
%s Module %s
'
- 'Version: %s
'
- 'Maintainer: %s
'
- 'License: %s
'
- '%s'
- 'Description: %s
'
- 'Capabilities: %s
'))
- % ('',
- module.name.capitalize(),
- module.version,
- to_unicode(module.maintainer).replace(u'&', u'&').replace(u'<', u'<').replace(u'>', u'>'),
- module.license,
- (unicode(self.tr('Website: %s
')) % 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)
-
- @Slot(object)
- def proxyEditEnabled(self, state):
- self.ui.proxyEdit.setEnabled(state)
-
- @Slot()
- def acceptBackend(self):
- backend_name = 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 backend_name:
- 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\-_]+$', backend_name):
- 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(backend_name):
- QMessageBox.critical(self, self.tr('Unable to create backend'),
- unicode(self.tr('Unable to create backend "%s": it already exists')) % backend_name)
- 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, backend_name, {}, 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":
%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')) % backend_name)
- return
-
- self.to_load.add(backend_name)
- self.ui.configFrame.hide()
-
- self.loadBackendsList()
-
- @Slot()
- def rejectBackend(self):
- self.ui.configFrame.hide()
-
- @Slot()
- 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 %s' % module.website
- else:
- website = 'with the module %s' % 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)
- buttonBox.accepted.connect(dialog.accept)
- buttonBox.rejected.connect(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":
%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:
%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
diff --git a/weboob/tools/application/qt/backendcfg.ui b/weboob/tools/application/qt/backendcfg.ui
deleted file mode 100644
index 09122b8be13708073c85293a4fe022e606bb2a45..0000000000000000000000000000000000000000
--- a/weboob/tools/application/qt/backendcfg.ui
+++ /dev/null
@@ -1,328 +0,0 @@
-
-
- BackendCfg
-
-
-
- 0
- 0
- 622
- 516
-
-
-
- Backends configuration
-
-
-
- 6
-
-
- 4
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
- 4
-
-
-
-
-
- Update modules
-
-
-
- -
-
-
- Repositories
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
-
-
-
-
- QAbstractItemView::NoEditTriggers
-
-
-
- 24
- 24
-
-
-
- false
-
-
- false
-
-
- false
-
-
- true
-
-
- true
-
-
- false
-
-
- false
-
-
- false
-
-
- true
-
-
-
- Name
-
-
-
-
- Module
-
-
-
-
- -
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- Add
-
-
-
- -
-
-
- Remove
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
- -
-
-
-
-
-
- Available modules:
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 24
- 24
-
-
-
- 1
-
-
- true
-
-
-
-
-
- -
-
-
-
- 1
- 0
-
-
-
- QFrame::NoFrame
-
-
- QFrame::Plain
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- true
-
-
-
- -
-
-
- QFormLayout::ExpandingFieldsGrow
-
-
-
-
-
- -
-
-
- Proxy:
-
-
-
- -
-
-
- false
-
-
-
- -
-
-
- Register an account...
-
-
-
- -
-
-
- Name:
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
-
-
-
-
- -
-
-
- QDialogButtonBox::Close
-
-
-
-
-
-
- backendsList
- addButton
- removeButton
- modulesList
- moduleInfo
- nameEdit
- proxyBox
- proxyEdit
- registerButton
- configButtonBox
- buttonBox
-
-
-
-
- buttonBox
- clicked(QAbstractButton*)
- BackendCfg
- accept()
-
-
- 312
- 591
-
-
- 312
- 306
-
-
-
-
-
diff --git a/weboob/tools/application/qt/qt.py b/weboob/tools/application/qt/qt.py
deleted file mode 100644
index b18a30f813b8def9dce38f45380aeb7710c21326..0000000000000000000000000000000000000000
--- a/weboob/tools/application/qt/qt.py
+++ /dev/null
@@ -1,419 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright(C) 2010-2011 Romain Bignon
-#
-# This file is part of weboob.
-#
-# weboob is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# weboob is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with weboob. If not, see .
-
-from __future__ import print_function
-
-import sys
-import logging
-import re
-from threading import Event
-from copy import copy
-from PyQt4.QtCore import QTimer, QObject, QString, QSize, QVariant, QMutex, Qt
-from PyQt4.QtCore import pyqtSignal as Signal, pyqtSlot as Slot
-from PyQt4.QtGui import QMainWindow, QApplication, QStyledItemDelegate, \
- QStyleOptionViewItemV4, QTextDocument, QStyle, \
- QAbstractTextDocumentLayout, QPalette, QMessageBox, \
- QSpinBox, QLineEdit, QComboBox, QCheckBox, QInputDialog
-
-from weboob.core.ouiboube import Weboob, VersionsMismatchError
-from weboob.core.scheduler import IScheduler
-from weboob.tools.config.iconfig import ConfigError
-from weboob.exceptions import BrowserUnavailable, BrowserIncorrectPassword, BrowserForbidden, ModuleInstallError
-from weboob.tools.value import ValueInt, ValueBool, ValueBackendPassword
-from weboob.tools.misc import to_unicode
-from weboob.capabilities import UserError
-
-from ..base import Application, MoreResultsAvailable
-
-
-__all__ = ['QtApplication', 'QtMainWindow', 'QtDo', 'HTMLDelegate']
-
-
-class QtScheduler(QObject, IScheduler):
- def __init__(self, app):
- QObject.__init__(self)
- self.app = app
- self.params = {}
-
- def schedule(self, interval, function, *args):
- timer = QTimer()
- timer.setInterval(interval * 1000)
- timer.setSingleShot(True)
-
- self.params[timer] = (None, function, args)
-
- timer.start()
- timer.timeout.connect(self.timeout)
-
- def repeat(self, interval, function, *args):
- timer = QTimer()
- timer.setSingleShot(False)
-
- self.params[timer] = (interval, function, args)
-
- timer.start(0)
- timer.timeout.connect(self.timeout)
-
- @Slot()
- def timeout(self):
- timer = self.sender()
- interval, function, args = self.params[timer]
-
- function(*args)
- if interval is None:
- self.params.pop(timer)
- else:
- timer.setInterval(interval * 1000)
-
- def want_stop(self):
- self.app.quit()
-
- 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,
- '%s request' % self.value.label,
- 'Please enter %s for %s' % (self.value.label,
- self.backend_name),
- QLineEdit.Password)
- return password
-
- new_request = Signal()
-
- def __init__(self, weboob, parent=None):
- QObject.__init__(self, parent)
- self.weboob = weboob
- self.weboob.requests.register('login', self.callback(self.LoginRequest))
- self.mutex = QMutex()
- self.requests = []
- self.new_request.connect(self.do_request)
-
- def callback(self, klass):
- def cb(*args, **kwargs):
- return self.add_request(klass(*args, **kwargs))
- return cb
-
- @Slot()
- 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.new_request.emit()
- request.event.wait()
- return request.answer
-
-
-class QtApplication(QApplication, Application):
- def __init__(self):
- QApplication.__init__(self, sys.argv)
- self.setApplicationName(self.APPNAME)
-
- Application.__init__(self)
- self.cbmanager = QCallbacksManager(self.weboob, self)
-
- def create_weboob(self):
- return Weboob(scheduler=QtScheduler(self))
-
- def load_backends(self, *args, **kwargs):
- while True:
- try:
- return Application.load_backends(self, *args, **kwargs)
- except VersionsMismatchError as e:
- msg = 'Versions of modules mismatch with version of weboob.'
- except ConfigError as e:
- msg = unicode(e)
-
- res = QMessageBox.question(None, 'Configuration error', u'%s\n\nDo you want to update repositories?' % msg, QMessageBox.Yes|QMessageBox.No)
- if res == QMessageBox.No:
- raise e
-
- # Do not import it globally, it causes circular imports
- from .backendcfg import ProgressDialog
- pd = ProgressDialog('Update of repositories', "Cancel", 0, 100)
- pd.setWindowModality(Qt.WindowModal)
- try:
- self.weboob.update(pd)
- except ModuleInstallError as err:
- QMessageBox.critical(None, self.tr('Update error'),
- unicode(self.tr('Unable to update repositories: %s' % err)),
- QMessageBox.Ok)
- pd.setValue(100)
- QMessageBox.information(None, self.tr('Update of repositories'),
- self.tr('Repositories updated!'), QMessageBox.Ok)
-
-
-class QtMainWindow(QMainWindow):
- def __init__(self, parent=None):
- QMainWindow.__init__(self, parent)
-
-
-class QtDo(QObject):
- gotResponse = Signal(object)
- gotError = Signal(object, object, object)
- finished = Signal()
-
- def __init__(self, weboob, cb, eb=None, fb=None):
- QObject.__init__(self)
-
- if not eb:
- eb = self.default_eb
-
- self.weboob = weboob
- self.process = None
- self.cb = cb
- self.eb = eb
- self.fb = fb
-
- self.gotResponse.connect(self.local_cb)
- self.gotError.connect(self.local_eb)
- self.finished.connect(self.local_fb)
-
- def stop(self, wait=False):
- if self.process is not None:
- self.process.stop(wait)
-
- def do(self, *args, **kwargs):
- self.process = self.weboob.do(*args, **kwargs)
- self.process.callback_thread(self.thread_cb, self.thread_eb, self.thread_fb)
-
- @Slot(object, object, object)
- def default_eb(self, backend, error, backtrace):
- if isinstance(error, MoreResultsAvailable):
- # This is not an error, ignore.
- return
-
- msg = unicode(error)
- if isinstance(error, BrowserIncorrectPassword):
- if not msg:
- msg = 'Invalid login/password.'
- elif isinstance(error, BrowserUnavailable):
- if not msg:
- msg = 'Website is unavailable.'
- elif isinstance(error, BrowserForbidden):
- if not msg:
- msg = 'This action is forbidden.'
- elif isinstance(error, NotImplementedError):
- msg = u'This feature is not supported by this backend.\n\n' \
- u'To help the maintainer of this backend implement this feature, please contact: %s <%s>' % (backend.MAINTAINER, backend.EMAIL)
- elif isinstance(error, UserError):
- if not msg:
- msg = type(error).__name__
- elif logging.root.level <= logging.DEBUG:
- msg += u'
'
- ul_opened = False
- for line in backtrace.split('\n'):
- m = re.match(' File (.*)', line)
- if m:
- if not ul_opened:
- msg += u''
- ul_opened = True
- else:
- msg += u''
- msg += u'- %s' % m.group(1)
- else:
- msg += u'
%s' % to_unicode(line)
- if ul_opened:
- msg += u'
'
- print(error, file=sys.stderr)
- print(backtrace, file=sys.stderr)
- QMessageBox.critical(None, unicode(self.tr('Error with backend %s')) % backend.name,
- msg, QMessageBox.Ok)
-
- @Slot(object)
- def local_cb(self, data):
- if self.cb:
- self.cb(data)
-
- @Slot(object, object, object)
- def local_eb(self, backend, error, backtrace):
- if self.eb:
- self.eb(backend, error, backtrace)
-
- @Slot()
- def local_fb(self):
- if self.fb:
- self.fb()
-
- self.gotResponse.disconnect(self.local_cb)
- self.gotError.disconnect(self.local_eb)
- self.finished.disconnect(self.local_fb)
- self.process = None
-
- def thread_cb(self, data):
- self.gotResponse.emit(data)
-
- def thread_eb(self, backend, error, backtrace):
- self.gotError.emit(backend, error, backtrace)
-
- def thread_fb(self):
- self.finished.emit()
-
-
-class HTMLDelegate(QStyledItemDelegate):
- def paint(self, painter, option, index):
- optionV4 = QStyleOptionViewItemV4(option)
- self.initStyleOption(optionV4, index)
-
- style = optionV4.widget.style() if optionV4.widget else QApplication.style()
-
- doc = QTextDocument()
- doc.setHtml(optionV4.text)
-
- # painting item without text
- optionV4.text = QString()
- style.drawControl(QStyle.CE_ItemViewItem, optionV4, painter)
-
- ctx = QAbstractTextDocumentLayout.PaintContext()
-
- # Hilight text if item is selected
- if optionV4.state & QStyle.State_Selected:
- ctx.palette.setColor(QPalette.Text, optionV4.palette.color(QPalette.Active, QPalette.HighlightedText))
-
- textRect = style.subElementRect(QStyle.SE_ItemViewItemText, optionV4)
- painter.save()
- painter.translate(textRect.topLeft())
- painter.setClipRect(textRect.translated(-textRect.topLeft()))
- doc.documentLayout().draw(painter, ctx)
- painter.restore()
-
- def sizeHint(self, option, index):
- optionV4 = QStyleOptionViewItemV4(option)
- self.initStyleOption(optionV4, index)
-
- doc = QTextDocument()
- doc.setHtml(optionV4.text)
- 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_value(self, value):
- self._value = value
- self.setText(self._value.get())
-
- def get_value(self):
- 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)
- self._value = value
- if value.default:
- self.setChecked(True)
-
- def set_value(self, value):
- self._value = value
- self.setChecked(self._value.get())
-
- def get_value(self):
- self._value.set(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_value(self, value):
- self._value = value
- self.setValue(self._value.get())
-
- def get_value(self):
- self._value.set(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_value(self, value):
- self._value = value
- for i in xrange(self.count()):
- if unicode(self.itemData(i).toString()) == self._value.get():
- self.setCurrentIndex(i)
- return
-
- def get_value(self):
- self._value.set(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 isinstance(value, ValueBackendPassword):
- klass = _QtValueBackendPassword
- elif value.choices is not None:
- klass = _QtValueChoices
- else:
- klass = _QtValueStr
-
- return klass(copy(value))
diff --git a/weboob/tools/application/qt/reposdlg.ui b/weboob/tools/application/qt/reposdlg.ui
deleted file mode 100644
index 6dc74e326478c1fda5ade9e5f469c7c2beb7d7ac..0000000000000000000000000000000000000000
--- a/weboob/tools/application/qt/reposdlg.ui
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
- RepositoriesDlg
-
-
-
- 0
- 0
- 400
- 300
-
-
-
- Repositories
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
-
-
- buttonBox
- rejected()
- RepositoriesDlg
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
-