pax_global_header 0000666 0000000 0000000 00000000064 13443173721 0014517 g ustar 00root root 0000000 0000000 52 comment=4d3ee01b1e4cfef44102fe710d4222023b7fd9cc
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/ 0000775 0000000 0000000 00000000000 13443173721 0021052 5 ustar 00root root 0000000 0000000 woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/ 0000775 0000000 0000000 00000000000 13443173721 0022327 5 ustar 00root root 0000000 0000000 woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/__init__.py 0000664 0000000 0000000 00000000245 13443173721 0024441 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
__title__ = 'weboob'
__version__ = '1.6'
__author__ = 'The Weboob Association'
__copyright__ = 'Copyright 2012-2019 The Weboob Association'
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/ 0000775 0000000 0000000 00000000000 13443173721 0025015 5 ustar 00root root 0000000 0000000 woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/__init__.py 0000664 0000000 0000000 00000000000 13443173721 0027114 0 ustar 00root root 0000000 0000000 woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/boobank/ 0000775 0000000 0000000 00000000000 13443173721 0026430 5 ustar 00root root 0000000 0000000 woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/boobank/__init__.py 0000664 0000000 0000000 00000001426 13443173721 0030544 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Christophe Benz
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see -- %s %s Receiving... %s0
0
0
%s
" % (obj.title)
result += ""
result += "
"
result += "
%s
')
extra = u''
if message.flags & message.IS_NOT_RECEIVED:
extra += u'Status: Unread
'
elif message.flags & message.IS_RECEIVED:
extra += u'Status: Read
'
elif message.flags & message.IS_UNREAD:
extra += u'Status: New
'
self.ui.messageBody.setText("%s
"
"Date: %s
"
"From: %s
"
"%s"
"%s
' % esc(update.message))
parts.extend(self.changesToHtml(update.changes))
parts.append('
')
return '\n'.join(parts)
def changesToHtml(self, changes):
if not changes:
return
yield ''
for change in changes:
yield '
'
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qboobtracker/main_window.py0000664 0000000 0000000 00000020163 13443173721 0032362 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2013 Sébastien Monel
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see %s)%s
' % self.housing.title
_area = u'%.0fm²' % self.housing.area if self.housing.area else self.housing.area
text += u'%s — %s — %s%s — %.0f %s/m2 (%s)' % (
self.housing.date.strftime('%Y-%m-%d') if self.housing.date else 'Unknown',
_area,
self.housing.cost,
self.housing.currency,
self.housing.price_per_meter,
self.housing.currency,
self.housing.backend)
text += u'
%s' % self.housing.text.strip()
text += u'
%s' % storage.get('notes', self.housing.fullid, default='').strip().replace('\n', '
')
self.setText(text)
if self.housing.fullid not in storage.get('read'):
self.setBackground(QBrush(QColor(200, 200, 255)))
self.read = False
elif self.housing.fullid in storage.get('bookmarks'):
self.setBackground(QBrush(QColor(255, 200, 200)))
elif self.background().color() != QColor(0, 0, 0):
self.setBackground(QBrush())
class MainWindow(QtMainWindow):
def __init__(self, config, storage, weboob, app, parent=None):
super(MainWindow, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.config = config
self.storage = storage
self.weboob = weboob
self.app = app
self.process = None
self.housing = None
self.displayed_photo_idx = 0
self.process_photo = {}
self.process_bookmarks = {}
self.ui.housingsList.setItemDelegate(HTMLDelegate())
self.ui.housingFrame.hide()
self.ui.actionBackends.triggered.connect(self.backendsConfig)
self.ui.queriesList.currentIndexChanged.connect(self.queryChanged)
self.ui.addQueryButton.clicked.connect(self.addQuery)
self.ui.editQueryButton.clicked.connect(self.editQuery)
self.ui.removeQueryButton.clicked.connect(self.removeQuery)
self.ui.bookmarksButton.clicked.connect(self.displayBookmarks)
self.ui.housingsList.currentItemChanged.connect(self.housingSelected)
self.ui.previousButton.clicked.connect(self.previousClicked)
self.ui.nextButton.clicked.connect(self.nextClicked)
self.ui.bookmark.stateChanged.connect(self.bookmarkChanged)
self.reloadQueriesList()
self.refreshHousingsList()
if self.weboob.count_backends() == 0:
self.backendsConfig()
if len(self.config.get('queries')) == 0:
self.addQuery()
def closeEvent(self, event):
self.setHousing(None)
QtMainWindow.closeEvent(self, event)
@Slot()
def backendsConfig(self):
bckndcfg = BackendCfg(self.weboob, (CapHousing,), self)
if bckndcfg.run():
pass
def reloadQueriesList(self, select_name=None):
self.ui.queriesList.currentIndexChanged.disconnect(self.queryChanged)
self.ui.queriesList.clear()
for name in self.config.get('queries', default={}):
self.ui.queriesList.addItem(name)
if name == select_name:
self.ui.queriesList.setCurrentIndex(len(self.ui.queriesList)-1)
self.ui.queriesList.currentIndexChanged.connect(self.queryChanged)
if select_name is not None:
self.queryChanged()
@Slot()
def removeQuery(self):
name = self.ui.queriesList.itemText(self.ui.queriesList.currentIndex())
queries = self.config.get('queries')
queries.pop(name, None)
self.config.set('queries', queries)
self.config.save()
self.reloadQueriesList()
self.queryChanged()
@Slot()
def editQuery(self):
name = self.ui.queriesList.itemText(self.ui.queriesList.currentIndex())
self.addQuery(name)
@Slot()
def addQuery(self, name=None):
querydlg = QueryDialog(self.weboob, self)
if name is not None:
query = self.config.get('queries', name)
querydlg.ui.nameEdit.setText(name)
querydlg.ui.nameEdit.setEnabled(False)
for c in query['cities']:
city = City(c['id'])
city.backend = c['backend']
city.name = c['name']
item = querydlg.buildCityItem(city)
querydlg.ui.citiesList.addItem(item)
querydlg.ui.typeBox.setCurrentIndex(int(query.get('type', 0)))
querydlg.ui.areaMin.setValue(query['area_min'])
querydlg.ui.areaMax.setValue(query['area_max'])
querydlg.ui.costMin.setValue(query['cost_min'])
querydlg.ui.costMax.setValue(query['cost_max'])
querydlg.selectComboValue(querydlg.ui.nbRooms, query['nb_rooms'])
if querydlg.exec_():
name = querydlg.ui.nameEdit.text()
query = {}
query['type'] = querydlg.ui.typeBox.currentIndex()
query['cities'] = []
for i in range(len(querydlg.ui.citiesList)):
item = querydlg.ui.citiesList.item(i)
city = item.data(Qt.UserRole)
query['cities'].append({'id': city.id, 'backend': city.backend, 'name': city.name})
query['area_min'] = querydlg.ui.areaMin.value()
query['area_max'] = querydlg.ui.areaMax.value()
query['cost_min'] = querydlg.ui.costMin.value()
query['cost_max'] = querydlg.ui.costMax.value()
try:
query['nb_rooms'] = int(querydlg.ui.nbRooms.itemText(querydlg.ui.nbRooms.currentIndex()))
except ValueError:
query['nb_rooms'] = 0
self.config.set('queries', name, query)
self.config.save()
self.reloadQueriesList(name)
@Slot(int)
def queryChanged(self, i=None):
self.refreshHousingsList()
def refreshHousingsList(self):
name = self.ui.queriesList.itemText(self.ui.queriesList.currentIndex())
q = self.config.get('queries', name)
if q is None:
return q
self.ui.housingsList.clear()
self.ui.queriesList.setEnabled(False)
self.ui.bookmarksButton.setEnabled(False)
query = Query()
query.type = list(POSTS_TYPES)[-q.get('type', 1)]
query.cities = []
for c in q['cities']:
city = City(c['id'])
city.backend = c['backend']
city.name = c['name']
query.cities.append(city)
query.area_min = int(q['area_min']) or None
query.area_max = int(q['area_max']) or None
query.cost_min = int(q['cost_min']) or None
query.cost_max = int(q['cost_max']) or None
query.nb_rooms = int(q['nb_rooms']) or None
self.process = QtDo(self.weboob, self.addHousing, fb=self.addHousingEnd)
self.process.do(self.app._do_complete, 20, None, 'search_housings', query)
@Slot()
def displayBookmarks(self):
self.ui.housingsList.clear()
self.ui.queriesList.setEnabled(False)
self.ui.queriesList.setCurrentIndex(-1)
self.ui.bookmarksButton.setEnabled(False)
self.processes = {}
for id in self.storage.get('bookmarks'):
_id, backend_name = id.rsplit('@', 1)
self.process_bookmarks[id] = QtDo(self.weboob, self.addHousing, fb=self.addHousingEnd)
self.process_bookmarks[id].do('get_housing', _id, backends=backend_name)
def addHousingEnd(self):
self.ui.queriesList.setEnabled(True)
self.ui.bookmarksButton.setEnabled(True)
self.process = None
def addHousing(self, housing):
if not housing:
return
item = HousingListWidgetItem(housing)
item.setAttrs(self.storage)
if housing.photos is NotLoaded:
process = QtDo(self.weboob, lambda c: self.setPhoto(c, item))
process.do('fillobj', housing, ['photos'], backends=housing.backend)
self.process_photo[housing.id] = process
elif housing.photos is not NotAvailable and len(housing.photos) > 0:
if not self.setPhoto(housing, item):
photo = housing.photos[0]
process = QtDo(self.weboob, lambda p: self.setPhoto(housing, item))
process.do('fillobj', photo, ['data'], backends=housing.backend)
self.process_photo[housing.id] = process
self.ui.housingsList.addItem(item)
if housing.fullid in self.process_bookmarks:
self.process_bookmarks.pop(housing.fullid)
@Slot(QListWidgetItem, QListWidgetItem)
def housingSelected(self, item, prev):
if item is not None:
housing = item.housing
self.ui.queriesFrame.setEnabled(False)
read = set(self.storage.get('read'))
read.add(housing.fullid)
self.storage.set('read', list(read))
self.storage.save()
self.process = QtDo(self.weboob, self.gotHousing)
self.process.do('fillobj', housing, backends=housing.backend)
else:
housing = None
self.setHousing(housing)
if prev:
prev.setAttrs(self.storage)
def setPhoto(self, housing, item):
if not housing:
return False
try:
self.process_photo.pop(housing.id, None)
except KeyError:
pass
if not housing.photos:
return False
img = None
for photo in housing.photos:
if photo.data:
img = QImage.fromData(photo.data)
break
if img:
item.setIcon(QIcon(QPixmap.fromImage(img)))
return True
return False
def setHousing(self, housing, nottext='Loading...'):
if self.housing is not None:
self.saveNotes()
self.housing = housing
if self.housing is None:
self.ui.housingFrame.hide()
return
self.ui.housingFrame.show()
self.display_photo()
self.ui.bookmark.setChecked(housing.fullid in self.storage.get('bookmarks'))
self.ui.titleLabel.setText('%s
' % housing.title)
_area = u'%.2f m²' % housing.area if housing.area else housing.area
self.ui.areaLabel.setText(u'%s' % _area)
self.ui.costLabel.setText(u'%s %s' % (housing.cost, housing.currency))
self.ui.pricePerMeterLabel.setText(u'%.2f %s/m²' % (housing.price_per_meter, housing.currency))
self.ui.dateLabel.setText(housing.date.strftime('%Y-%m-%d') if housing.date else nottext)
self.ui.phoneLabel.setText(housing.phone or nottext)
self.ui.locationLabel.setText(housing.location or nottext)
self.ui.stationLabel.setText(housing.station or nottext)
self.ui.urlLabel.setText('%s' % (housing.url or nottext, housing.url or nottext))
text = housing.text.replace('\n', '
') if housing.text else nottext
self.ui.descriptionEdit.setText(text)
self.ui.notesEdit.setText(self.storage.get('notes', housing.fullid, default=''))
while self.ui.detailsFrame.layout().count() > 0:
child = self.ui.detailsFrame.layout().takeAt(0)
child.widget().hide()
child.widget().deleteLater()
if housing.details:
for key, value in housing.details.items():
if empty(value):
continue
label = QLabel(value)
label.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.LinksAccessibleByMouse)
self.ui.detailsFrame.layout().addRow('%s:' % key, label)
def gotHousing(self, housing):
self.setHousing(housing, nottext='')
self.ui.queriesFrame.setEnabled(True)
self.process = None
@Slot(int)
def bookmarkChanged(self, state):
bookmarks = set(self.storage.get('bookmarks'))
if state == Qt.Checked:
bookmarks.add(self.housing.fullid)
elif self.housing.fullid in bookmarks:
bookmarks.remove(self.housing.fullid)
self.storage.set('bookmarks', list(bookmarks))
self.storage.save()
def saveNotes(self):
if not self.housing:
return
txt = self.ui.notesEdit.toPlainText().strip()
if len(txt) > 0:
self.storage.set('notes', self.housing.fullid, txt)
else:
self.storage.delete('notes', self.housing.fullid)
self.storage.save()
@Slot()
def previousClicked(self):
if not self.housing.photos or len(self.housing.photos) == 0:
return
self.displayed_photo_idx = (self.displayed_photo_idx - 1) % len(self.housing.photos)
self.display_photo()
@Slot()
def nextClicked(self):
if not self.housing.photos or len(self.housing.photos) == 0:
return
self.displayed_photo_idx = (self.displayed_photo_idx + 1) % len(self.housing.photos)
self.display_photo()
def display_photo(self):
if not self.housing.photos:
self.ui.photosFrame.hide()
return
if self.displayed_photo_idx >= len(self.housing.photos):
self.displayed_photo_idx = len(self.housing.photos) - 1
if self.displayed_photo_idx < 0:
self.ui.photosFrame.hide()
return
self.ui.photosFrame.show()
photo = self.housing.photos[self.displayed_photo_idx]
if photo.data:
data = photo.data
if photo.id in self.process_photo:
self.process_photo.pop(photo.id)
else:
self.process_photo[photo.id] = QtDo(self.weboob, lambda p: self.display_photo())
self.process_photo[photo.id].do('fillobj', photo, ['data'], backends=self.housing.backend)
return
img = QImage.fromData(data)
img = img.scaledToWidth(self.width()/3)
self.ui.photoLabel.setPixmap(QPixmap.fromImage(img))
if photo.url is not NotLoaded:
text = '%s' % (photo.url, photo.url)
self.ui.photoUrlLabel.setText(text)
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qflatboob/qflatboob.py 0000664 0000000 0000000 00000003027 13443173721 0031313 0 ustar 00root root 0000000 0000000 # -*- 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 Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see %s
" % job.title)
self.ui.idLabel.setText("%s" % job.id)
self.ui.jobNameLabel.setText("%s" % job.job_name)
self.ui.publicationDateLabel.setText("%s" % job.publication_date)
self.ui.societyNameLabel.setText("%s" % job.society_name)
self.ui.placeLabel.setText("%s" % job.place)
self.ui.payLabel.setText("%s" % job.pay)
self.ui.contractTypeLabel.setText("%s" % job.contract_type)
self.ui.formationLabel.setText("%s" % job.formation)
self.ui.experienceLabel.setText("%s" % job.experience)
self.ui.urlLabel.setText("%s" % (job.url, job.url))
self.ui.jobFrame.show()
else:
self.ui.jobFrame.hide()
QApplication.restoreOverrideCursor()
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qhandjoob/qhandjoob.py 0000664 0000000 0000000 00000002773 13443173721 0031312 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2013 Sébastien Monel
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see
')
self.ui.contentLabel.setText(content)
def __eq__(self, m):
if not isinstance(m, Message):
return False
return self.message == m.message
class ContactThread(QWidget):
"""
The thread of the selected contact.
"""
def __init__(self, weboob, contact, support_reply, parent=None):
super(ContactThread, self).__init__(parent)
self.ui = Ui_ContactThread()
self.ui.setupUi(self)
self.weboob = weboob
self.contact = contact
self.thread = None
self.messages = []
self.process_msg = None
self.ui.refreshButton.clicked.connect(self.refreshMessages)
if support_reply:
self.ui.sendButton.clicked.connect(self.postReply)
else:
self.ui.frame.hide()
self.refreshMessages()
@Slot()
def refreshMessages(self, fillobj=False):
if self.process_msg:
return
self.ui.refreshButton.setEnabled(False)
def finished():
#v = self.ui.scrollArea.verticalScrollBar()
#print v.minimum(), v.value(), v.maximum(), v.sliderPosition()
#self.ui.scrollArea.verticalScrollBar().setValue(self.ui.scrollArea.verticalScrollBar().maximum())
self.process_msg = None
self.process_msg = QtDo(self.weboob, self.gotThread, self.gotError, finished)
if fillobj and self.thread:
self.process_msg.do('fillobj', self.thread, ['root'], backends=self.contact.backend)
else:
self.process_msg.do('get_thread', self.contact.id, backends=self.contact.backend)
def gotError(self, backend, error, backtrace):
self.ui.textEdit.setEnabled(False)
self.ui.sendButton.setEnabled(False)
self.ui.refreshButton.setEnabled(True)
def gotThread(self, thread):
self.ui.textEdit.setEnabled(True)
self.ui.sendButton.setEnabled(True)
self.ui.refreshButton.setEnabled(True)
self.thread = thread
if thread.root is NotLoaded:
self._insert_load_button(0)
else:
for message in thread.iter_all_messages():
self._insert_message(message)
def _insert_message(self, message):
widget = ThreadMessage(message)
if widget in self.messages:
old_widget = self.messages[self.messages.index(widget)]
if old_widget.message.flags != widget.message.flags:
old_widget.set_message(widget.message)
return
for i, m in enumerate(self.messages):
if widget.message.date > m.message.date:
self.ui.scrollAreaContent.layout().insertWidget(i, widget)
self.messages.insert(i, widget)
if message.parent is NotLoaded:
self._insert_load_button(i)
return
self.ui.scrollAreaContent.layout().addWidget(widget)
self.messages.append(widget)
if message.parent is NotLoaded:
self._insert_load_button(-1)
def _insert_load_button(self, pos):
button = QPushButton(self.tr('More messages...'))
button.clicked.connect(self._load_button_pressed)
if pos >= 0:
self.ui.scrollAreaContent.layout().insertWidget(pos, button)
else:
self.ui.scrollAreaContent.layout().addWidget(button)
@Slot()
def _load_button_pressed(self):
button = self.sender()
self.ui.scrollAreaContent.layout().removeWidget(button)
button.hide()
button.deleteLater()
self.refreshMessages(fillobj=True)
@Slot()
def postReply(self):
text = self.ui.textEdit.toPlainText()
self.ui.textEdit.setEnabled(False)
self.ui.sendButton.setEnabled(False)
m = Message(thread=self.thread,
id=0,
title=u'',
sender=None,
receivers=None,
content=text,
parent=self.messages[0].message if len(self.messages) > 0 else None)
self.process_reply = QtDo(self.weboob, None, self._postReply_eb, self._postReply_fb)
self.process_reply.do('post_message', m, backends=self.contact.backend)
def _postReply_fb(self):
self.ui.textEdit.clear()
self.ui.textEdit.setEnabled(True)
self.ui.sendButton.setEnabled(True)
self.refreshMessages()
self.process_reply = None
def _postReply_eb(self, backend, error, backtrace):
content = self.tr('Unable to send message:\n%s\n') % to_unicode(error)
if logging.root.level <= logging.DEBUG:
content += '\n%s\n' % to_unicode(backtrace)
QMessageBox.critical(self, self.tr('Error while posting reply'),
content, QMessageBox.Ok)
self.process_reply = None
class ContactProfile(QWidget):
def __init__(self, weboob, contact, parent=None):
super(ContactProfile, self).__init__(parent)
self.ui = Ui_Profile()
self.ui.setupUi(self)
self.ui.previousButton.clicked.connect(self.previousClicked)
self.ui.nextButton.clicked.connect(self.nextClicked)
self.weboob = weboob
self.contact = contact
self.loaded_profile = False
self.displayed_photo_idx = 0
self.process_photo = {}
missing_fields = self.gotProfile(contact)
if len(missing_fields) > 0:
self.process_contact = QtDo(self.weboob, self.gotProfile, self.gotError)
self.process_contact.do('fillobj', self.contact, missing_fields, backends=self.contact.backend)
def gotError(self, backend, error, backtrace):
self.ui.frame_photo.hide()
self.ui.descriptionEdit.setText('Unable to show profile
%s
' % contact.name)
if contact.status == Contact.STATUS_ONLINE:
status_color = 0x00aa00
elif contact.status == Contact.STATUS_OFFLINE:
status_color = 0xff0000
elif contact.status == Contact.STATUS_AWAY:
status_color = 0xffad16
else:
status_color = 0xaaaaaa
self.ui.statusLabel.setText('%s' % (status_color, contact.status_msg))
self.ui.contactUrlLabel.setText('URL: %s' % (contact.url, contact.url))
if contact.summary is NotLoaded:
self.ui.descriptionEdit.setText('Description
Description
'))
if not contact.profile:
missing_fields.add('profile')
elif not self.loaded_profile:
self.loaded_profile = True
for head in contact.profile.values():
if head.flags & head.HEAD:
widget = self.ui.headWidget
else:
widget = self.ui.profileTab
self.process_node(head, widget)
return missing_fields
def process_node(self, node, widget):
# Set the value widget
value = None
if node.flags & node.SECTION:
value = QWidget()
value.setLayout(QFormLayout())
for sub in node.value.values():
self.process_node(sub, value)
elif isinstance(node.value, list):
value = QLabel('
'.join(unicode(s) for s in node.value))
value.setWordWrap(True)
elif isinstance(node.value, tuple):
value = QLabel(', '.join(unicode(s) for s in node.value))
value.setWordWrap(True)
elif isinstance(node.value, (basestring,int,long,float)):
value = QLabel(unicode(node.value))
else:
logging.warning('Not supported value: %r' % node.value)
return
if isinstance(value, QLabel):
value.setTextInteractionFlags(Qt.TextSelectableByMouse|Qt.TextSelectableByKeyboard|Qt.LinksAccessibleByMouse)
# Insert the value widget into the parent widget, depending
# of its type.
if isinstance(widget, QTabWidget):
widget.addTab(value, node.label)
elif isinstance(widget.layout(), QFormLayout):
label = QLabel(u'%s: ' % node.label)
widget.layout().addRow(label, value)
elif isinstance(widget.layout(), QVBoxLayout):
widget.layout().addWidget(QLabel(u'%s
' % node.label))
widget.layout().addWidget(value)
else:
logging.warning('Not supported widget: %r' % widget)
@Slot()
def previousClicked(self):
if len(self.contact.photos) == 0:
return
self.displayed_photo_idx = (self.displayed_photo_idx - 1) % len(self.contact.photos)
self.display_photo()
@Slot()
def nextClicked(self):
if len(self.contact.photos) == 0:
return
self.displayed_photo_idx = (self.displayed_photo_idx + 1) % len(self.contact.photos)
self.display_photo()
def display_photo(self):
if self.displayed_photo_idx >= len(self.contact.photos) or self.displayed_photo_idx < 0:
self.displayed_photo_idx = len(self.contact.photos) - 1
if self.displayed_photo_idx < 0:
self.ui.photoUrlLabel.setText('')
return
photo = list(self.contact.photos.values())[self.displayed_photo_idx]
if photo.data:
data = photo.data
if photo.id in self.process_photo:
self.process_photo.pop(photo.id)
else:
self.process_photo[photo.id] = QtDo(self.weboob, lambda p: self.display_photo())
self.process_photo[photo.id].do('fillobj', photo, ['data'], backends=self.contact.backend)
if photo.thumbnail_data:
data = photo.thumbnail_data
else:
return
img = QImage.fromData(data)
img = img.scaledToWidth(self.width()/3)
self.ui.photoLabel.setPixmap(QPixmap.fromImage(img))
if photo.url is not NotLoaded:
text = '%s' % (photo.url, photo.url)
if photo.hidden:
text += '
(Hidden photo)'
self.ui.photoUrlLabel.setText(text)
class ContactNotes(QWidget):
""" Widget for storing notes about a contact """
def __init__(self, weboob, contact, parent=None):
super(ContactNotes, self).__init__(parent)
self.ui = Ui_Notes()
self.ui.setupUi(self)
self.weboob = weboob
self.contact = contact
self.ui.textEdit.setEnabled(False)
self.ui.saveButton.setEnabled(False)
def finished():
self.process = None
self.ui.textEdit.setEnabled(True)
self.ui.saveButton.setEnabled(True)
self.process = QtDo(self.weboob, self._getNotes_cb, self._getNotes_eb, finished)
self.process.do('get_notes', self.contact.id, backends=(self.contact.backend,))
self.ui.saveButton.clicked.connect(self.saveNotes)
def _getNotes_cb(self, data):
if data:
self.ui.textEdit.setText(data)
def _getNotes_eb(self, backend, error, backtrace):
if isinstance(error, NotImplementedError):
return
self.ui.textEdit.setEnabled(True)
self.ui.saveButton.setEnabled(True)
content = self.tr('Unable to load notes:\n%s\n') % to_unicode(error)
if logging.root.level <= logging.DEBUG:
content += '\n%s\n' % to_unicode(backtrace)
QMessageBox.critical(self, self.tr('Error while loading notes'),
content, QMessageBox.Ok)
@Slot()
def saveNotes(self):
text = self.ui.textEdit.toPlainText()
self.ui.saveButton.setEnabled(False)
self.ui.textEdit.setEnabled(False)
self.process = QtDo(self.weboob, None, self._saveNotes_eb, self._saveNotes_fb)
self.process.do('save_notes', self.contact.id, text, backends=(self.contact.backend,))
def _saveNotes_fb(self):
self.ui.saveButton.setEnabled(True)
self.ui.textEdit.setEnabled(True)
def _saveNotes_eb(self, backend, error, backtrace):
content = self.tr('Unable to save notes:\n%s\n') % to_unicode(error)
if logging.root.level <= logging.DEBUG:
content += '\n%s\n' % to_unicode(backtrace)
QMessageBox.critical(self, self.tr('Error while saving notes'),
content, QMessageBox.Ok)
class IGroup(object):
def __init__(self, weboob, id, name):
self.id = id
self.name = name
self.weboob = weboob
def iter_contacts(self, cb):
raise NotImplementedError()
class MetaGroup(IGroup):
def iter_contacts(self, cb):
if self.id == 'online':
status = Contact.STATUS_ONLINE|Contact.STATUS_AWAY
elif self.id == 'offline':
status = Contact.STATUS_OFFLINE
else:
status = Contact.STATUS_ALL
self.process = QtDo(self.weboob, lambda d: self.cb(cb, d), fb=lambda: self.fb(cb))
self.process.do('iter_contacts', status, caps=CapContact)
def cb(self, cb, contact):
if contact:
cb(contact)
def fb(self, fb):
self.process = None
if fb:
fb(None)
class ContactsWidget(QWidget):
def __init__(self, weboob, parent=None):
super(ContactsWidget, self).__init__(parent)
self.ui = Ui_Contacts()
self.ui.setupUi(self)
self.weboob = weboob
self.contact = None
self.ui.contactList.setItemDelegate(HTMLDelegate())
self.url_process = None
self.photo_processes = {}
self.ui.groupBox.addItem('All', MetaGroup(self.weboob, 'all', self.tr('All')))
self.ui.groupBox.addItem('Online', MetaGroup(self.weboob, 'online', self.tr('Online')))
self.ui.groupBox.addItem('Offline', MetaGroup(self.weboob, 'offline', self.tr('Offline')))
self.ui.groupBox.setCurrentIndex(1)
self.ui.groupBox.currentIndexChanged.connect(self.groupChanged)
self.ui.contactList.itemClicked.connect(self.contactChanged)
self.ui.refreshButton.clicked.connect(self.refreshContactList)
self.ui.urlButton.clicked.connect(self.urlClicked)
def load(self):
self.refreshContactList()
model = BackendListModel(self.weboob)
model.addBackends(entry_all=False)
self.ui.backendsList.setModel(model)
@Slot()
def groupChanged(self):
self.refreshContactList()
@Slot()
def refreshContactList(self):
self.ui.contactList.clear()
self.ui.refreshButton.setEnabled(False)
i = self.ui.groupBox.currentIndex()
group = self.ui.groupBox.itemData(i)
group.iter_contacts(self.addContact)
def setPhoto(self, contact, item):
if not contact:
return False
try:
self.photo_processes.pop(contact.id, None)
except KeyError:
pass
img = None
for photo in contact.photos.values():
if photo.thumbnail_data:
img = QImage.fromData(photo.thumbnail_data)
break
if img:
item.setIcon(QIcon(QPixmap.fromImage(img)))
return True
return False
def addContact(self, contact):
if not contact:
self.ui.refreshButton.setEnabled(True)
return
status = ''
if contact.status == Contact.STATUS_ONLINE:
status = u'Online'
status_color = 0x00aa00
elif contact.status == Contact.STATUS_OFFLINE:
status = u'Offline'
status_color = 0xff0000
elif contact.status == Contact.STATUS_AWAY:
status = u'Away'
status_color = 0xffad16
else:
status = u'Unknown'
status_color = 0xaaaaaa
if contact.status_msg:
status += u' — %s' % contact.status_msg
item = QListWidgetItem()
item.setText('%s
%s
%s' % (contact.name, status_color, status, contact.backend))
item.setData(Qt.UserRole, contact)
if contact.photos is NotLoaded:
process = QtDo(self.weboob, lambda c: self.setPhoto(c, item))
process.do('fillobj', contact, ['photos'], backends=contact.backend)
self.photo_processes[contact.id] = process
elif len(contact.photos) > 0:
if not self.setPhoto(contact, item):
photo = list(contact.photos.values())[0]
process = QtDo(self.weboob, lambda p: self.setPhoto(contact, item))
process.do('fillobj', photo, ['thumbnail_data'], backends=contact.backend)
self.photo_processes[contact.id] = process
for i in range(self.ui.contactList.count()):
if self.ui.contactList.item(i).data(Qt.UserRole).status > contact.status:
self.ui.contactList.insertItem(i, item)
return
self.ui.contactList.addItem(item)
@Slot(QListWidgetItem)
def contactChanged(self, current):
if not current:
return
contact = current.data(Qt.UserRole)
self.setContact(contact)
def setContact(self, contact):
if not contact or contact == self.contact:
return
if not isinstance(contact, Contact):
return self.retrieveContact(contact)
self.ui.tabWidget.clear()
self.contact = contact
backend = self.weboob.get_backend(self.contact.backend)
self.ui.tabWidget.addTab(ContactProfile(self.weboob, self.contact), self.tr('Profile'))
if backend.has_caps(CapMessages):
self.ui.tabWidget.addTab(ContactThread(self.weboob, self.contact, backend.has_caps(CapMessagesPost)), self.tr('Messages'))
if backend.has_caps(CapChat):
self.ui.tabWidget.setTabEnabled(self.ui.tabWidget.addTab(QWidget(), self.tr('Chat')),
False)
self.ui.tabWidget.setTabEnabled(self.ui.tabWidget.addTab(QWidget(), self.tr('Calendar')),
False)
self.ui.tabWidget.addTab(ContactNotes(self.weboob, self.contact), self.tr('Notes'))
@Slot()
def urlClicked(self):
url = self.ui.urlEdit.text()
if not url:
return
self.retrieveContact(url)
def retrieveContact(self, url):
backend_name = self.ui.backendsList.currentText()
self.ui.urlButton.setEnabled(False)
def finished():
self.url_process = None
self.ui.urlButton.setEnabled(True)
self.url_process = QtDo(self.weboob, self.retrieveContact_cb, self.retrieveContact_eb, finished)
self.url_process.do('get_contact', url, backends=backend_name)
def retrieveContact_cb(self, contact):
self.ui.urlEdit.clear()
self.setContact(contact)
def retrieveContact_eb(self, backend, error, backtrace):
content = self.tr('Unable to get contact:\n%s\n') % to_unicode(error)
if logging.root.level <= logging.DEBUG:
content += u'\n%s\n' % to_unicode(backtrace)
QMessageBox.critical(self, self.tr('Error while getting contact'),
content, QMessageBox.Ok)
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qhavedate/events.py 0000664 0000000 0000000 00000013612 13443173721 0030640 0 ustar 00root root 0000000 0000000 # -*- 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 Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see %s
%s
%s' % (contact.name, status_color, status, event.backend)
date = event.date.strftime('%Y-%m-%d %H:%M')
type = event.type
message = event.message
item = QTreeWidgetItem(None, [name, date, type, message])
item.setData(0, Qt.UserRole, event)
if contact.photos is NotLoaded:
process = QtDo(self.weboob, lambda c: self.setPhoto(c, item))
process.do('fillobj', contact, ['photos'], backends=contact.backend)
self.photo_processes[contact.id] = process
elif len(contact.photos) > 0:
if not self.setPhoto(contact, item):
photo = list(contact.photos.values())[0]
process = QtDo(self.weboob, lambda p: self.setPhoto(contact, item))
process.do('fillobj', photo, ['thumbnail_data'], backends=contact.backend)
self.photo_processes[contact.id] = process
self.ui.eventsList.addTopLevelItem(item)
self.ui.eventsList.resizeColumnToContents(0)
self.ui.eventsList.resizeColumnToContents(1)
@Slot(QTreeWidgetItem, int)
def eventDoubleClicked(self, item, col):
event = item.data(0, Qt.UserRole)
self.display_contact.emit(event.contact)
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qhavedate/main_window.py 0000664 0000000 0000000 00000006434 13443173721 0031653 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2010-2014 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 Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see %s
' % backend.name)
self.accounts.append(account)
self.ui.statusFrame.layout().addWidget(account)
self.ui.statusFrame.layout().addStretch()
self.getNewProfiles()
def updateStats(self):
for account in self.accounts:
account.updateStats()
def getNewProfiles(self):
self.newprofiles_process = QtDo(self.weboob, self.retrieveNewContacts_cb)
self.newprofiles_process.do('iter_new_contacts')
def retrieveNewContacts_cb(self, contact):
self.contacts.insert(0, contact)
self.ui.queueLabel.setText('%d' % len(self.contacts))
if self.current is None:
next(self)
@Slot()
def next(self):
try:
contact = self.contacts.pop()
except IndexError:
contact = None
self.ui.queueLabel.setText('%d' % len(self.contacts))
self.setContact(contact)
self.updateStats()
def setContact(self, contact):
self.current = contact
if contact is not None:
widget = ContactProfile(self.weboob, contact)
self.ui.scrollArea.setWidget(widget)
else:
self.ui.scrollArea.setWidget(None)
@Slot()
def sendQuery(self):
self.newprofiles_process = QtDo(self.weboob, None, fb=self.next)
self.newprofiles_process.do('send_query', self.current.id, backends=[self.current.backend])
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qhavedate/status.py 0000664 0000000 0000000 00000010767 13443173721 0030667 0 ustar 00root root 0000000 0000000 # -*- 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 Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with weboob. If not, see %s — %s
' % (backend.name, backend.DESCRIPTION))
self.body = QLabel()
minfo = self.weboob.repositories.get_module_info(backend.NAME)
icon_path = self.weboob.repositories.get_module_icon_path(minfo)
if icon_path:
self.icon = QLabel()
img = QImage(icon_path)
self.icon.setPixmap(QPixmap.fromImage(img))
head.addWidget(self.icon)
head.addWidget(self.title)
head.addStretch()
self.layout().addWidget(headw)
if backend.has_caps(CapAccount):
self.body.setText(u'Waiting...')
self.layout().addWidget(self.body)
self.timer = self.weboob.repeat(60, self.updateStats)
def deinit(self):
if self.timer is not None:
self.weboob.stop(self.timer)
def updateStats(self):
self.process = QtDo(self.weboob, self.updateStats_cb, self.updateStats_eb, self.updateStats_fb)
self.process.body = u''
self.process.in_p = False
self.process.do('get_account_status', backends=self.backend)
def updateStats_fb(self):
if self.process.in_p:
self.process.body += u"
%s
' % value self.process.in_p = False else: if not self.process.in_p: self.process.body += u""
self.process.in_p = True
else:
self.process.body += u" blah: 229,90
"
self.process.body += u'%s: %s' % (field.label, field.value)
def updateStats_eb(self, backend, err, backtrace):
self.body.setText(u'Unable to connect: %s' % to_unicode(err))
self.title.setText(u'%s' % self.title.text())
class AccountsStatus(QScrollArea):
def __init__(self, weboob, parent=None):
super(AccountsStatus, self).__init__(parent)
self.weboob = weboob
self.setFrameShadow(self.Plain)
self.setFrameShape(self.NoFrame)
self.setWidgetResizable(True)
widget = QWidget(self)
widget.setLayout(QVBoxLayout())
widget.show()
self.setWidget(widget)
def load(self):
while self.widget().layout().count() > 0:
item = self.widget().layout().takeAt(0)
if item.widget():
item.widget().deinit()
item.widget().hide()
item.widget().deleteLater()
for backend in self.weboob.iter_backends():
account = Account(self.weboob, backend)
self.widget().layout().addWidget(account)
self.widget().layout().addStretch()
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qhavedate/ui/ 0000775 0000000 0000000 00000000000 13443173721 0027374 5 ustar 00root root 0000000 0000000 woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qhavedate/ui/Makefile 0000664 0000000 0000000 00000000265 13443173721 0031037 0 ustar 00root root 0000000 0000000 UI_FILES = $(wildcard *.ui)
UI_PY_FILES = $(UI_FILES:%.ui=%_ui.py)
PYUIC = pyuic5
all: $(UI_PY_FILES)
%_ui.py: %.ui
$(PYUIC) -o $@ $^
clean:
rm -f *.pyc
rm -f $(UI_PY_FILES)
woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qhavedate/ui/__init__.py 0000664 0000000 0000000 00000000000 13443173721 0031473 0 ustar 00root root 0000000 0000000 contact_thread.ui 0000664 0000000 0000000 00000011122 13443173721 0032633 0 ustar 00root root 0000000 0000000 woob-4d3ee01b1e4cfef44102fe710d4222023b7fd9cc-weboob/weboob/applications/qhavedate/ui