class ContactNotes(QWidget): """ Widget for storing notes about a contact """ def __init__(self, weboob, contact, parent=None): QWidget.__init__(self, 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) self.process = QtDo(self.weboob, self._getNotes_cb, self._getNotes_eb) self.process.do('get_notes', self.contact.id, backends=(self.contact.backend,)) self.connect(self.ui.saveButton, SIGNAL('clicked()'), self.saveNotes) def _getNotes_cb(self, backend, data): if not backend or not data: self.process = None self.ui.textEdit.setEnabled(True) self.ui.saveButton.setEnabled(True) return 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 = unicode(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) def saveNotes(self): text = unicode(self.ui.textEdit.toPlainText()) self.ui.saveButton.setEnabled(False) self.ui.textEdit.setEnabled(False) self.process = QtDo(self.weboob, self._saveNotes_cb, self._saveNotes_eb) self.process.do('save_notes', self.contact.id, text, backends=(self.contact.backend,)) def _saveNotes_cb(self, backend, data): self.ui.saveButton.setEnabled(True) self.ui.textEdit.setEnabled(True) pass def _saveNotes_eb(self, backend, error, backtrace): self.ui.saveButton.setEnabled(True) self.ui.textEdit.setEnabled(True) content = unicode(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)
def addHousing(self, backend, housing): if not backend: self.ui.queriesList.setEnabled(True) self.ui.bookmarksButton.setEnabled(True) self.process = None return if not housing: return item = HousingListWidgetItem(housing) item.setAttrs(self.storage) if housing.photos is NotLoaded: process = QtDo(self.weboob, lambda b, 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 b, 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)
def gotEvent(self, event): found = False for i in xrange(self.ui.typeBox.count()): s = self.ui.typeBox.itemData(i) if s == event.type: found = True if not found: print(event.type) self.ui.typeBox.addItem(event.type.capitalize(), event.type) if event.type == self.event_filter: self.ui.typeBox.setCurrentIndex(self.ui.typeBox.count()-1) if self.event_filter and self.event_filter != event.type: return if not event.contact: return contact = event.contact contact.backend = event.backend 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 name = '<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % (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 = 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)
class ContactNotes(QWidget): """ Widget for storing notes about a contact """ def __init__(self, weboob, contact, parent=None): QWidget.__init__(self, 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.connect(self.ui.saveButton, SIGNAL('clicked()'), 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 = unicode(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) def saveNotes(self): text = unicode(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 = unicode(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)
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( '<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % (contact.name, status_color, status, contact.backend)) item.setData(Qt.UserRole, contact) if contact.photos is NotLoaded: process = QtDo(self.weboob, lambda b, 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 = contact.photos.values()[0] process = QtDo(self.weboob, lambda b, p: self.setPhoto(contact, item)) process.do('fillobj', photo, ['thumbnail_data'], backends=contact.backend) self.photo_processes[contact.id] = process for i in xrange(self.ui.contactList.count()): if self.ui.contactList.item(i).data( Qt.UserRole).toPyObject().status > contact.status: self.ui.contactList.insertItem(i, item) return self.ui.contactList.addItem(item)
class MiniVideo(QFrame): def __init__(self, weboob, backend, video, parent=None): QFrame.__init__(self, parent) self.ui = Ui_MiniVideo() self.ui.setupUi(self) self.weboob = weboob self.backend = backend self.video = video self.ui.titleLabel.setText(video.title) self.ui.backendLabel.setText(backend.name) self.ui.durationLabel.setText(unicode(video.duration)) self.ui.authorLabel.setText(unicode(video.author)) self.ui.dateLabel.setText(video.date and unicode(video.date) or '') if video.rating_max: self.ui.ratingLabel.setText('%s / %s' % (video.rating, video.rating_max)) else: self.ui.ratingLabel.setText('%s' % video.rating) self.process_thumbnail = QtDo(self.weboob, self.gotThumbnail) self.process_thumbnail.do('fillobj', self.video, ['thumbnail'], backends=backend) def gotThumbnail(self, backend, video): if not backend: return if video.thumbnail and video.thumbnail.data: img = QImage.fromData(video.thumbnail.data) self.ui.imageLabel.setPixmap(QPixmap.fromImage(img)) def enterEvent(self, event): self.setFrameShadow(self.Sunken) QFrame.enterEvent(self, event) def leaveEvent(self, event): self.setFrameShadow(self.Raised) QFrame.leaveEvent(self, event) def mousePressEvent(self, event): QFrame.mousePressEvent(self, event) video = self.backend.get_video(self.video.id) if video: video_widget = Video(video, self) video_widget.show()
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 b, d: self.cb(cb, b, d)) self.process.do('iter_contacts', status, caps=ICapContact) def cb(self, cb, backend, contact): if contact: cb(contact) elif not backend: self.process = None cb(None)
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 b, d: self.cb(cb, b, d)) self.process.do('iter_contacts', status, caps=ICapContact) def cb(self, cb, backend, contact): if contact: cb(contact) elif not backend: self.process = None cb(None)
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('<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % (contact.name, status_color, status, contact.backend)) item.setData(Qt.UserRole, contact) if contact.photos is NotLoaded: process = QtDo(self.weboob, lambda b, 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 = contact.photos.values()[0] process = QtDo(self.weboob, lambda b, p: self.setPhoto(contact, item)) process.do('fillobj', photo, ['thumbnail_data'], backends=contact.backend) self.photo_processes[contact.id] = process for i in xrange(self.ui.contactList.count()): if self.ui.contactList.item(i).data(Qt.UserRole).toPyObject().status > contact.status: self.ui.contactList.insertItem(i, item) return self.ui.contactList.addItem(item)
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 MessagesManager(QWidget): def __init__(self, weboob, parent=None): QWidget.__init__(self, parent) self.ui = Ui_MessagesManager() self.ui.setupUi(self) self.weboob = weboob self.ui.backendsList.setCurrentRow(0) self.backend = None self.thread = None self.message = None self.ui.replyButton.setEnabled(False) self.ui.replyWidget.hide() self.connect(self.ui.backendsList, SIGNAL('itemSelectionChanged()'), self._backendChanged) self.connect(self.ui.threadsList, SIGNAL('itemSelectionChanged()'), self._threadChanged) self.connect(self.ui.messagesTree, SIGNAL('itemClicked(QTreeWidgetItem *, int)'), self._messageSelected) self.connect(self.ui.messagesTree, SIGNAL('itemActivated(QTreeWidgetItem *, int)'), self._messageSelected) self.connect(self.ui.profileButton, SIGNAL('clicked()'), self._profilePressed) self.connect(self.ui.replyButton, SIGNAL('clicked()'), self._replyPressed) self.connect(self.ui.sendButton, SIGNAL('clicked()'), self._sendPressed) def load(self): self.ui.backendsList.clear() self.ui.backendsList.addItem('(All)') for backend in self.weboob.iter_backends(): if not backend.has_caps(ICapMessages): continue item = QListWidgetItem(backend.name.capitalize()) item.setData(Qt.UserRole, backend) self.ui.backendsList.addItem(item) self.refreshThreads() def _backendChanged(self): selection = self.ui.backendsList.selectedItems() if not selection: self.backend = None return self.backend = selection[0].data(Qt.UserRole).toPyObject() self.refreshThreads() def refreshThreads(self): self.ui.messagesTree.clear() self.ui.threadsList.clear() self.hideReply() self.ui.profileButton.hide() self.ui.replyButton.setEnabled(False) self.ui.backendsList.setEnabled(False) self.ui.threadsList.setEnabled(False) self.process_threads = QtDo(self.weboob, self._gotThread) self.process_threads.do('iter_threads', backends=self.backend, caps=ICapMessages) def _gotThread(self, backend, thread): if not backend: self.process_threads = None self.ui.backendsList.setEnabled(True) self.ui.threadsList.setEnabled(True) return item = QListWidgetItem(thread.title) item.setData(Qt.UserRole, (thread.backend, thread.id)) self.ui.threadsList.addItem(item) def _threadChanged(self): self.ui.messagesTree.clear() selection = self.ui.threadsList.selectedItems() if not selection: return t = selection[0].data(Qt.UserRole).toPyObject() self.refreshThreadMessages(*t) def refreshThreadMessages(self, backend, id): self.ui.messagesTree.clear() self.ui.messageBody.clear() self.ui.backendsList.setEnabled(False) self.ui.threadsList.setEnabled(False) self.ui.replyButton.setEnabled(False) self.ui.profileButton.hide() self.hideReply() self.process = QtDo(self.weboob, self._gotThreadMessages) self.process.do('get_thread', id, backends=backend) def _gotThreadMessages(self, backend, thread): if thread is None: self.ui.backendsList.setEnabled(True) self.ui.threadsList.setEnabled(True) self.process = None return self.thread = thread if thread.flags & thread.IS_THREADS: top = self.ui.messagesTree.invisibleRootItem() else: top = None self._insert_message(thread.root, top) self.showMessage(thread.root) self.ui.messagesTree.expandAll() def _insert_message(self, message, top): item = QTreeWidgetItem(None, [message.title or '', message.sender or 'Unknown', time.strftime('%Y-%m-%d %H:%M:%S', message.date.timetuple())]) item.setData(0, Qt.UserRole, message) if message.flags & message.IS_UNREAD: item.setForeground(0, QBrush(Qt.darkYellow)) item.setForeground(1, QBrush(Qt.darkYellow)) item.setForeground(2, QBrush(Qt.darkYellow)) if top is not None: # threads top.addChild(item) else: # discussion self.ui.messagesTree.invisibleRootItem().insertChild(0, item) if message.children is not None: for child in message.children: self._insert_message(child, top and item) def _messageSelected(self, item, column): message = item.data(0, Qt.UserRole).toPyObject() self.showMessage(message, item) def showMessage(self, message, item=None): backend = self.weboob.get_backend(message.thread.backend) if backend.has_caps(ICapMessagesPost): self.ui.replyButton.setEnabled(True) self.message = message if message.title.startswith('Re:'): self.ui.titleEdit.setText(message.title) else: self.ui.titleEdit.setText('Re: %s' % message.title) if message.flags & message.IS_HTML: content = message.content else: content = message.content.replace('&', '&').replace('<', '<').replace('>', '>').replace('\n', '<br />') extra = u'' if message.flags & message.IS_NOT_RECEIVED: extra += u'<b>Status</b>: <font color=#ff0000>Unread</font><br />' elif message.flags & message.IS_RECEIVED: extra += u'<b>Status</b>: <font color=#00ff00>Read</font><br />' elif message.flags & message.IS_UNREAD: extra += u'<b>Status</b>: <font color=#0000ff>New</font><br />' self.ui.messageBody.setText("<h1>%s</h1>" "<b>Date</b>: %s<br />" "<b>From</b>: %s<br />" "%s" "<p>%s</p>" % (message.title, str(message.date), message.sender, extra, content)) if item and message.flags & message.IS_UNREAD: backend.set_message_read(message) message.flags &= ~message.IS_UNREAD item.setForeground(0, QBrush()) item.setForeground(1, QBrush()) item.setForeground(2, QBrush()) if message.thread.flags & message.thread.IS_DISCUSSION: self.ui.profileButton.show() else: self.ui.profileButton.hide() def _profilePressed(self): print self.thread.id self.emit(SIGNAL('display_contact'), self.thread.id) def displayReply(self): self.ui.replyButton.setText(self.tr('Cancel')) self.ui.replyWidget.show() def hideReply(self): self.ui.replyButton.setText(self.tr('Reply')) self.ui.replyWidget.hide() self.ui.replyEdit.clear() self.ui.titleEdit.clear() def _replyPressed(self): if self.ui.replyWidget.isVisible(): self.hideReply() else: self.displayReply() def _sendPressed(self): if not self.ui.replyWidget.isVisible(): return text = unicode(self.ui.replyEdit.toPlainText()) title = unicode(self.ui.titleEdit.text()) self.ui.backendsList.setEnabled(False) self.ui.threadsList.setEnabled(False) self.ui.messagesTree.setEnabled(False) self.ui.replyButton.setEnabled(False) self.ui.replyWidget.setEnabled(False) self.ui.sendButton.setText(self.tr('Sending...')) flags = 0 if self.ui.htmlBox.currentIndex() == 0: flags = Message.IS_HTML m = Message(thread=self.thread, id=0, title=title, sender=None, receivers=None, content=text, parent=self.message, flags=flags) self.process_reply = QtDo(self.weboob, self._postReply_cb, self._postReply_eb) self.process_reply.do('post_message', m, backends=self.thread.backend) def _postReply_cb(self, backend, ignored): if not backend: return self.ui.backendsList.setEnabled(True) self.ui.threadsList.setEnabled(True) self.ui.messagesTree.setEnabled(True) self.ui.replyButton.setEnabled(True) self.ui.replyWidget.setEnabled(True) self.ui.sendButton.setEnabled(True) self.ui.sendButton.setText(self.tr('Send')) self.hideReply() self.process_reply = None self.refreshThreadMessages(backend.name, self.thread.id) def _postReply_eb(self, backend, error, backtrace): content = unicode(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.ui.backendsList.setEnabled(True) self.ui.threadsList.setEnabled(True) self.ui.messagesTree.setEnabled(True) self.ui.replyButton.setEnabled(True) self.ui.replyWidget.setEnabled(True) self.ui.sendButton.setText(self.tr('Send')) self.process_reply = None
class Account(QFrame): def __init__(self, weboob, backend, parent=None): QFrame.__init__(self, parent) self.setFrameShape(QFrame.StyledPanel) self.setFrameShadow(QFrame.Raised) self.weboob = weboob self.backend = backend self.setLayout(QVBoxLayout()) self.timer = None head = QHBoxLayout() headw = QWidget() headw.setLayout(head) self.title = QLabel(u'<h1>%s — %s</h1>' % (backend.name, backend.DESCRIPTION)) self.body = QLabel() if backend.ICON: self.icon = QLabel() img = QImage(backend.ICON) self.icon.setPixmap(QPixmap.fromImage(img)) head.addWidget(self.icon) head.addWidget(self.title) head.addStretch() self.layout().addWidget(headw) if backend.has_caps(ICapAccount): self.body.setText(u'<i>Waiting...</i>') 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.process.body = u'' self.process.in_p = False self.process.do('get_account_status', backends=self.backend) def updateStats_cb(self, backend, field): if not field: if self.process.in_p: self.process.body += u"</p>" self.body.setText(self.process.body) self.process = None return if field.flags & StatusField.FIELD_HTML: value = u'%s' % field.value else: value = (u'%s' % field.value).replace('&', '&').replace('<', '<').replace('>', '>') if field.flags & StatusField.FIELD_TEXT: if self.process.in_p: self.process.body += u'</p>' self.process.body += u'<p>%s</p>' % value self.process.in_p = False else: if not self.process.in_p: self.process.body += u"<p>" self.process.in_p = True else: self.process.body += u"<br />" self.process.body += u'<b>%s</b>: %s' % (field.label, field.value) def updateStats_eb(self, backend, err, backtrace): self.body.setText(u'<b>Unable to connect:</b> %s' % to_unicode(err)) self.title.setText(u'<font color=#ff0000>%s</font>' % unicode(self.title.text()))
class MainWindow(QtMainWindow): def __init__(self, config, weboob, app, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.weboob = weboob self.app = app self.minis = [] self.current_info_widget = None # search history is a list of patterns which have been searched self.search_history = self.loadSearchHistory() self.updateCompletion() # action history is composed by the last action and the action list # An action is a function, a list of arguments and a description string self.action_history = {'last_action': None, 'action_list': []} self.connect(self.ui.backButton, SIGNAL("clicked()"), self.doBack) self.ui.backButton.hide() self.connect(self.ui.stopButton, SIGNAL("clicked()"), self.stopProcess) self.ui.stopButton.hide() self.connect(self.ui.searchEdit, SIGNAL("returnPressed()"), self.search) self.connect(self.ui.idEdit, SIGNAL("returnPressed()"), self.searchId) count = self.config.get('settings', 'maxresultsnumber') self.ui.countSpin.setValue(int(count)) self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.actionQuit, SIGNAL("triggered()"), self.close) self.loadBackendsList() if self.ui.backendEdit.count() == 0: self.backendsConfig() def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (CapRecipe, ), self) if bckndcfg.run(): self.loadBackendsList() def loadBackendsList(self): self.ui.backendEdit.clear() for i, backend in enumerate(self.weboob.iter_backends()): if i == 0: self.ui.backendEdit.addItem('All backends', '') self.ui.backendEdit.addItem(backend.name, backend.name) if backend.name == self.config.get('settings', 'backend'): self.ui.backendEdit.setCurrentIndex(i+1) if self.ui.backendEdit.count() == 0: self.ui.searchEdit.setEnabled(False) else: self.ui.searchEdit.setEnabled(True) def loadSearchHistory(self): ''' Return search string history list loaded from history file ''' result = [] history_path = os.path.join(self.weboob.workdir, 'qcookboob_history') if os.path.exists(history_path): f = codecs.open(history_path, 'r', 'utf-8') conf_hist = f.read() f.close() if conf_hist is not None and conf_hist.strip() != '': result = conf_hist.strip().split('\n') return result def saveSearchHistory(self): ''' Save search history in history file ''' if len(self.search_history) > 0: history_path = os.path.join(self.weboob.workdir, 'qcookboob_history') f = codecs.open(history_path, 'w', 'utf-8') f.write('\n'.join(self.search_history)) f.close() def updateCompletion(self): qc = QCompleter(QStringList(self.search_history), self) qc.setCaseSensitivity(Qt.CaseInsensitive) self.ui.searchEdit.setCompleter(qc) def getCount(self): num = self.ui.countSpin.value() if num == 0: return None else: return num def stopProcess(self): self.process.process.finish_event.set() def doAction(self, description, fun, args): ''' Call fun with args as arguments and save it in the action history ''' self.ui.currentActionLabel.setText(description) if self.action_history['last_action'] is not None: self.action_history['action_list'].append(self.action_history['last_action']) self.ui.backButton.setToolTip(self.action_history['last_action']['description']) self.ui.backButton.show() self.action_history['last_action'] = {'function': fun, 'args': args, 'description': description} return fun(*args) def doBack(self): ''' Go back in action history Basically call previous function and update history ''' if len(self.action_history['action_list']) > 0: todo = self.action_history['action_list'].pop() self.ui.currentActionLabel.setText(todo['description']) self.action_history['last_action'] = todo if len(self.action_history['action_list']) == 0: self.ui.backButton.hide() else: self.ui.backButton.setToolTip(self.action_history['action_list'][-1]['description']) return todo['function'](*todo['args']) def search(self): pattern = unicode(self.ui.searchEdit.text()) # arbitrary max number of completion word if len(self.search_history) > 50: self.search_history.pop(0) if pattern not in self.search_history: self.search_history.append(pattern) self.updateCompletion() self.searchRecipe() def searchRecipe(self): pattern = unicode(self.ui.searchEdit.text()) if not pattern: return self.doAction(u'Search recipe "%s"' % pattern, self.searchRecipeAction, [pattern]) def searchRecipeAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str(self.ui.backendEdit.itemData(self.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addRecipe) self.process.do(self.app._do_complete, self.getCount(), ('title'), 'iter_recipes', pattern, backends=backend_name, caps=CapRecipe) self.ui.stopButton.show() def addRecipe(self, backend, recipe): if not backend: self.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.ui.stopButton.hide() return minirecipe = MiniRecipe(self.weboob, backend, recipe, self) self.ui.list_content.layout().addWidget(minirecipe) self.minis.append(minirecipe) def displayRecipe(self, recipe, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget(self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wrecipe = Recipe(recipe, backend, self) self.ui.info_content.layout().addWidget(wrecipe) self.current_info_widget = wrecipe QApplication.restoreOverrideCursor() def searchId(self): QApplication.setOverrideCursor(Qt.WaitCursor) id = unicode(self.ui.idEdit.text()) if '@' in id: backend_name = id.split('@')[1] id = id.split('@')[0] else: backend_name = None for backend in self.weboob.iter_backends(): if (backend_name and backend.name == backend_name) or not backend_name: recipe = backend.get_recipe(id) if recipe: self.doAction('Details of recipe "%s"' % recipe.title, self.displayRecipe, [recipe, backend]) QApplication.restoreOverrideCursor() def closeEvent(self, ev): self.config.set('settings', 'backend', str(self.ui.backendEdit.itemData( self.ui.backendEdit.currentIndex()).toString())) self.saveSearchHistory() self.config.set('settings', 'maxresultsnumber', self.ui.countSpin.value()) self.config.save() ev.accept()
class MainWindow(QtMainWindow): def __init__(self, config, storage, weboob, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.storage = storage self.weboob = weboob self.process = None self.displayed_photo_idx = 0 self.process_photo = {} self.process_bookmarks = {} # search history is a list of patterns which have been searched self.search_history = self.loadSearchHistory() self.updateCompletion() self.ui.jobFrame.hide() self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.searchEdit, SIGNAL('returnPressed()'), self.doSearch) self.connect( self.ui.jobList, SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem*)'), self.jobSelected) self.connect(self.ui.searchButton, SIGNAL('clicked()'), self.doSearch) self.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.doAdvancedSearch) self.connect(self.ui.queriesTabWidget, SIGNAL('currentChanged(int)'), self.tabChange) self.connect( self.ui.jobListAdvancedSearch, SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem*)'), self.jobSelected) self.connect(self.ui.idEdit, SIGNAL('returnPressed()'), self.openJob) if self.weboob.count_backends() == 0: self.backendsConfig() def loadSearchHistory(self): ''' Return search string history list loaded from history file ''' result = [] history_path = os.path.join(self.weboob.workdir, 'qhandjoob_history') if os.path.exists(history_path): f = codecs.open(history_path, 'r', 'utf-8') conf_hist = f.read() f.close() if conf_hist is not None and conf_hist.strip() != '': result = conf_hist.strip().split('\n') return result def saveSearchHistory(self): ''' Save search history in history file ''' if len(self.search_history) > 0: history_path = os.path.join(self.weboob.workdir, 'qhandjoob_history') f = codecs.open(history_path, 'w', 'utf-8') f.write('\n'.join(self.search_history)) f.close() def updateCompletion(self): qc = QCompleter(QStringList(self.search_history), self) qc.setCaseSensitivity(Qt.CaseInsensitive) self.ui.searchEdit.setCompleter(qc) def tabChange(self, index): if index == 1: self.doAdvancedSearch() def doAdvancedSearch(self): QApplication.setOverrideCursor(Qt.WaitCursor) self.ui.jobListAdvancedSearch.clear() self.process = QtDo(self.weboob, self.addJobAdvancedSearch) self.process.do('advanced_search_job') def doSearch(self): QApplication.setOverrideCursor(Qt.WaitCursor) pattern = unicode(self.ui.searchEdit.text()) # arbitrary max number of completion word if pattern: if len(self.search_history) > 50: self.search_history.pop(0) if pattern not in self.search_history: self.search_history.append(pattern) self.updateCompletion() self.ui.jobList.clear() self.process = QtDo(self.weboob, self.addJobSearch) self.process.do('search_job', pattern) def addJobSearch(self, backend, job): item = self.addJob(backend, job) if item: self.ui.jobList.addItem(item) if not backend: QApplication.restoreOverrideCursor() def addJobAdvancedSearch(self, backend, job): item = self.addJob(backend, job) if item: self.ui.jobListAdvancedSearch.addItem(item) if not backend: QApplication.restoreOverrideCursor() def addJob(self, backend, job): if not backend: self.process = None return if not job: return item = JobListWidgetItem(job) item.setAttrs(self.storage) return item def closeEvent(self, event): self.saveSearchHistory() QtMainWindow.closeEvent(self, event) def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (ICapJob, ), self) if bckndcfg.run(): pass def jobSelected(self, item, prev): QApplication.setOverrideCursor(Qt.WaitCursor) if item is not None: job = item.job self.ui.queriesTabWidget.setEnabled(False) self.process = QtDo(self.weboob, self.gotJob) self.process.do('fillobj', job, backends=job.backend) else: job = None self.setJob(job) if prev: prev.setAttrs(self.storage) def openJob(self): QApplication.setOverrideCursor(Qt.WaitCursor) url = unicode(self.ui.idEdit.text()) if not url: return for backend in self.weboob.iter_backends(): job = backend.get_job_advert(url) if job: self.process = QtDo(self.weboob, self.gotJob) self.process.do('fillobj', job, backends=job.backend) break self.setJob(job) self.ui.idEdit.clear() QApplication.restoreOverrideCursor() def gotJob(self, backend, job): if not backend: self.ui.queriesTabWidget.setEnabled(True) self.process = None return self.setJob(job) def setJob(self, job): if job: self.ui.descriptionEdit.setText("%s" % job.description) self.ui.titleLabel.setText("<h1>%s</h1>" % 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("<a href='%s'>%s</a>" % (job.url, job.url)) self.ui.jobFrame.show() else: self.ui.jobFrame.hide() QApplication.restoreOverrideCursor()
class ContactProfile(QWidget): def __init__(self, weboob, contact, parent=None): QWidget.__init__(self, parent) self.ui = Ui_Profile() self.ui.setupUi(self) self.connect(self.ui.previousButton, SIGNAL('clicked()'), self.previousClicked) self.connect(self.ui.nextButton, SIGNAL('clicked()'), self.nextClicked) self.weboob = weboob self.contact = contact self.loaded_profile = False self.displayed_photo_idx = 0 self.process_photo = {} missing_fields = self.gotProfile(self.weboob.get_backend(contact.backend), 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.process_contact.default_eb(backend, error, backtrace) self.ui.frame_photo.hide() self.ui.descriptionEdit.setText('<h1>Unable to show profile</h1><p>%s</p>' % error) def gotProfile(self, backend, contact): if not backend: return [] missing_fields = set() self.display_photo() self.ui.nicknameLabel.setText('<h1>%s</h1>' % 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('<font color="#%06X">%s</font>' % (status_color, contact.status_msg)) self.ui.contactUrlLabel.setText('<b>URL:</b> <a href="%s">%s</a>' % (contact.url, contact.url)) if contact.summary is NotLoaded: self.ui.descriptionEdit.setText('<h1>Description</h1><p><i>Receiving...</i></p>') missing_fields.add('summary') else: self.ui.descriptionEdit.setText('<h1>Description</h1><p>%s</p>' % contact.summary.replace('\n', '<br />')) if not contact.profile: missing_fields.add('profile') elif not self.loaded_profile: self.loaded_profile = True for head in contact.profile: 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: self.process_node(sub, value) elif isinstance(node.value, list): value = QLabel('<br />'.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 # 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'<b>%s:</b> ' % node.label) widget.layout().addRow(label, value) elif isinstance(widget.layout(), QVBoxLayout): widget.layout().addWidget(QLabel(u'<h3>%s</h3>' % node.label)) widget.layout().addWidget(value) else: logging.warning('Not supported widget: %r' % widget) def previousClicked(self): self.displayed_photo_idx = (self.displayed_photo_idx - 1) % len(self.contact.photos) self.display_photo() def nextClicked(self): 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): self.displayed_photo_idx = len(self.contact.photos) - 1 if self.displayed_photo_idx < 0: self.ui.photoUrlLabel.setText('') return photo = 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 b,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 = '<a href="%s">%s</a>' % (photo.url, photo.url) if photo.hidden: text += '<br /><font color=#ff0000><i>(Hidden photo)</i></font>' self.ui.photoUrlLabel.setText(text)
class EventsWidget(QWidget): def __init__(self, weboob, parent=None): QWidget.__init__(self, parent) self.ui = Ui_Events() self.ui.setupUi(self) self.weboob = weboob self.photo_processes = {} self.event_filter = None self.connect(self.ui.eventsList, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), self.eventDoubleClicked) self.connect(self.ui.typeBox, SIGNAL('currentIndexChanged(int)'), self.typeChanged) self.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.refreshEventsList) self.ui.eventsList.setItemDelegate(HTMLDelegate()) self.ui.eventsList.sortByColumn(1, Qt.DescendingOrder) def load(self): self.refreshEventsList() def typeChanged(self, i): if self.ui.refreshButton.isEnabled(): self.refreshEventsList() def refreshEventsList(self): self.ui.eventsList.clear() self.ui.refreshButton.setEnabled(False) if self.ui.typeBox.currentIndex() >= 0: # XXX strangely, in gotEvent() in the loop to check if there is already the # event type to try to introduce it in list, itemData() returns the right value. # But, I don't know why, here, it will ALWAYS return None... # So the filter does not work currently. self.events_filter = self.ui.typeBox.itemData(self.ui.typeBox.currentIndex()) else: self.event_filter = None self.ui.typeBox.setEnabled(False) self.ui.typeBox.clear() self.ui.typeBox.addItem('All', None) def finished(): self.ui.refreshButton.setEnabled(True) self.ui.typeBox.setEnabled(True) self.process = QtDo(self.weboob, self.gotEvent, fb=finished) self.process.do('iter_events') 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.itervalues(): if photo.thumbnail_data: img = QImage.fromData(photo.thumbnail_data) break if img: item.setIcon(0, QIcon(QPixmap.fromImage(img))) self.ui.eventsList.resizeColumnToContents(0) return True return False def gotEvent(self, event): found = False for i in xrange(self.ui.typeBox.count()): s = self.ui.typeBox.itemData(i) if s == event.type: found = True if not found: print(event.type) self.ui.typeBox.addItem(event.type.capitalize(), event.type) if event.type == self.event_filter: self.ui.typeBox.setCurrentIndex(self.ui.typeBox.count()-1) if self.event_filter and self.event_filter != event.type: return if not event.contact: return contact = event.contact contact.backend = event.backend 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 name = '<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % (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 = 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) def eventDoubleClicked(self, item, col): event = item.data(0, Qt.UserRole).toPyObject() self.emit(SIGNAL('display_contact'), event.contact)
class MainWindow(QtMainWindow): def __init__(self, config, storage, weboob, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.storage = storage self.weboob = weboob 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.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.queriesList, SIGNAL('currentIndexChanged(int)'), self.queryChanged) self.connect(self.ui.addQueryButton, SIGNAL('clicked()'), self.addQuery) self.connect(self.ui.editQueryButton, SIGNAL('clicked()'), self.editQuery) self.connect(self.ui.removeQueryButton, SIGNAL('clicked()'), self.removeQuery) self.connect(self.ui.bookmarksButton, SIGNAL('clicked()'), self.displayBookmarks) self.connect(self.ui.housingsList, SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem*)'), self.housingSelected) self.connect(self.ui.previousButton, SIGNAL('clicked()'), self.previousClicked) self.connect(self.ui.nextButton, SIGNAL('clicked()'), self.nextClicked) self.connect(self.ui.bookmark, SIGNAL('stateChanged(int)'), 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) def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (ICapHousing,), self) if bckndcfg.run(): pass def reloadQueriesList(self, select_name=None): self.disconnect(self.ui.queriesList, SIGNAL('currentIndexChanged(int)'), self.queryChanged) self.ui.queriesList.clear() for name in self.config.get('queries', default={}).iterkeys(): self.ui.queriesList.addItem(name) if name == select_name: self.ui.queriesList.setCurrentIndex(len(self.ui.queriesList)-1) self.connect(self.ui.queriesList, SIGNAL('currentIndexChanged(int)'), self.queryChanged) if select_name is not None: self.queryChanged() def removeQuery(self): name = unicode(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() def editQuery(self): name = unicode(self.ui.queriesList.itemText(self.ui.queriesList.currentIndex())) self.addQuery(name) 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 = unicode(querydlg.ui.nameEdit.text()) query = {} query['type'] = querydlg.ui.typeBox.currentIndex() query['cities'] = [] for i in xrange(len(querydlg.ui.citiesList)): item = querydlg.ui.citiesList.item(i) city = item.data(Qt.UserRole).toPyObject() 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) def queryChanged(self, i=None): self.refreshHousingsList() def refreshHousingsList(self): name = unicode(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 = int(q.get('type', 0)) 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) self.process.do('search_housings', query) 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) self.process_bookmarks[id].do('get_housing', _id, backends=backend_name) def addHousing(self, backend, housing): if not backend: self.ui.queriesList.setEnabled(True) self.ui.bookmarksButton.setEnabled(True) self.process = None return if not housing: return item = HousingListWidgetItem(housing) item.setAttrs(self.storage) if housing.photos is NotLoaded: process = QtDo(self.weboob, lambda b, 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 b, 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) 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('<h1>%s</h1>' % housing.title) self.ui.areaLabel.setText(u'%s m²' % housing.area) self.ui.costLabel.setText(u'%s %s' % (housing.cost, 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) if housing.text: self.ui.descriptionEdit.setText(housing.text.replace('\n', '<br/>')) else: self.ui.descriptionEdit.setText(nottext) 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.iteritems(): label = QLabel(value) label.setTextInteractionFlags(Qt.TextSelectableByMouse|Qt.LinksAccessibleByMouse) self.ui.detailsFrame.layout().addRow('<b>%s:</b>' % key, label) def gotHousing(self, backend, housing): if not backend: self.ui.queriesFrame.setEnabled(True) self.process = None return self.setHousing(housing, nottext='') 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 = unicode(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() 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() 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 b,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 = '<a href="%s">%s</a>' % (photo.url, photo.url) self.ui.photoUrlLabel.setText(text)
class Account(QFrame): def __init__(self, weboob, backend, parent=None): QFrame.__init__(self, parent) self.setFrameShape(QFrame.StyledPanel) self.setFrameShadow(QFrame.Raised) self.weboob = weboob self.backend = backend self.setLayout(QVBoxLayout()) self.timer = None head = QHBoxLayout() headw = QWidget() headw.setLayout(head) self.title = QLabel(u'<h1>%s — %s</h1>' % (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'<i>Waiting...</i>') 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"</p>" self.body.setText(self.process.body) self.process = None def updateStats_cb(self, field): if field.flags & StatusField.FIELD_HTML: value = u'%s' % field.value else: value = (u'%s' % field.value).replace('&', '&').replace('<', '<').replace('>', '>') if field.flags & StatusField.FIELD_TEXT: if self.process.in_p: self.process.body += u'</p>' self.process.body += u'<p>%s</p>' % value self.process.in_p = False else: if not self.process.in_p: self.process.body += u"<p>" self.process.in_p = True else: self.process.body += u"<br />" self.process.body += u'<b>%s</b>: %s' % (field.label, field.value) def updateStats_eb(self, backend, err, backtrace): self.body.setText(u'<b>Unable to connect:</b> %s' % to_unicode(err)) self.title.setText(u'<font color=#ff0000>%s</font>' % unicode(self.title.text()))
class ContactThread(QWidget): """ The thread of the selected contact. """ def __init__(self, weboob, contact, support_reply, parent=None): QWidget.__init__(self, 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.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.refreshMessages) if support_reply: self.connect(self.ui.sendButton, SIGNAL('clicked()'), self.postReply) else: self.ui.frame.hide() self.refreshMessages() def refreshMessages(self, fillobj=False): if self.process_msg: return self.ui.refreshButton.setEnabled(False) self.process_msg = QtDo(self.weboob, self.gotThread, self.gotError) 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, backend, thread): if not thread: #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 return 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...')) self.connect(button, SIGNAL('clicked()'), lambda: self._load_button_pressed(button)) if pos >= 0: self.ui.scrollAreaContent.layout().insertWidget(pos, button) else: self.ui.scrollAreaContent.layout().addWidget(button) def _load_button_pressed(self, button): self.ui.scrollAreaContent.layout().removeWidget(button) button.hide() button.deleteLater() self.refreshMessages(fillobj=True) def postReply(self): text = unicode(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, self._postReply_cb, self._postReply_eb) self.process_reply.do('post_message', m, backends=self.contact.backend) def _postReply_cb(self, backend, ignored): if not backend: return 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 = unicode( 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 SearchWidget(QWidget): def __init__(self, weboob, parent=None): QWidget.__init__(self, parent) self.ui = Ui_Search() self.ui.setupUi(self) self.weboob = weboob self.contacts = [] self.accounts = [] self.current = None self.connect(self.ui.nextButton, SIGNAL('clicked()'), self.next) self.connect(self.ui.queryButton, SIGNAL('clicked()'), self.sendQuery) def load(self): while self.ui.statusFrame.layout().count() > 0: item = self.ui.statusFrame.layout().takeAt(0) if item.widget(): item.widget().deinit() item.widget().hide() item.widget().deleteLater() self.accounts = [] for backend in self.weboob.iter_backends(): account = Account(self.weboob, backend) account.title.setText(u'<h2>%s</h2>' % 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, backend, contact): if not backend: return self.contacts.insert(0, contact) self.ui.queueLabel.setText('%d' % len(self.contacts)) if self.current is None: self.next() 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) def sendQuery(self): self.newprofiles_process = QtDo(self.weboob, self.querySent) self.newprofiles_process.do('send_query', self.current.id, backends=[self.current.backend]) def querySent(self, backend, query): if backend is None: self.next()
class ContactsWidget(QWidget): def __init__(self, weboob, parent=None): QWidget.__init__(self, 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.connect(self.ui.groupBox, SIGNAL('currentIndexChanged(int)'), self.groupChanged) self.connect(self.ui.contactList, SIGNAL('itemClicked(QListWidgetItem*)'), self.contactChanged) self.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.refreshContactList) self.connect(self.ui.urlButton, SIGNAL('clicked()'), self.urlClicked) def load(self): self.refreshContactList() self.ui.backendsList.clear() for backend in self.weboob.iter_backends(): self.ui.backendsList.addItem(backend.name) def groupChanged(self, i): self.refreshContactList() def refreshContactList(self): self.ui.contactList.clear() self.ui.refreshButton.setEnabled(False) i = self.ui.groupBox.currentIndex() group = self.ui.groupBox.itemData(i).toPyObject() 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.itervalues(): 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( '<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % (contact.name, status_color, status, contact.backend)) item.setData(Qt.UserRole, contact) if contact.photos is NotLoaded: process = QtDo(self.weboob, lambda b, 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 = contact.photos.values()[0] process = QtDo(self.weboob, lambda b, p: self.setPhoto(contact, item)) process.do('fillobj', photo, ['thumbnail_data'], backends=contact.backend) self.photo_processes[contact.id] = process for i in xrange(self.ui.contactList.count()): if self.ui.contactList.item(i).data( Qt.UserRole).toPyObject().status > contact.status: self.ui.contactList.insertItem(i, item) return self.ui.contactList.addItem(item) def contactChanged(self, current): if not current: return contact = current.data(Qt.UserRole).toPyObject() 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(ICapMessages): self.ui.tabWidget.addTab( ContactThread(self.weboob, self.contact, backend.has_caps(ICapMessagesPost)), self.tr('Messages')) if backend.has_caps(ICapChat): 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')) def urlClicked(self): url = unicode(self.ui.urlEdit.text()) if not url: return self.retrieveContact(url) def retrieveContact(self, url): backend_name = unicode(self.ui.backendsList.currentText()) self.ui.urlButton.setEnabled(False) self.url_process = QtDo(self.weboob, self.retrieveContact_cb, self.retrieveContact_eb) self.url_process.do('get_contact', url, backends=backend_name) def retrieveContact_cb(self, backend, contact): if not backend: self.url_process = None self.ui.urlButton.setEnabled(True) return self.ui.urlEdit.clear() self.setContact(contact) def retrieveContact_eb(self, backend, error, backtrace): content = unicode( 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)
class ContactProfile(QWidget): def __init__(self, weboob, contact, parent=None): QWidget.__init__(self, parent) self.ui = Ui_Profile() self.ui.setupUi(self) self.connect(self.ui.previousButton, SIGNAL('clicked()'), self.previousClicked) self.connect(self.ui.nextButton, SIGNAL('clicked()'), self.nextClicked) self.weboob = weboob self.contact = contact self.loaded_profile = False self.displayed_photo_idx = 0 self.process_photo = {} missing_fields = self.gotProfile( self.weboob.get_backend(contact.backend), 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( '<h1>Unable to show profile</h1><p>%s</p>' % to_unicode(error)) def gotProfile(self, backend, contact): if not backend: return [] missing_fields = set() self.display_photo() self.ui.nicknameLabel.setText('<h1>%s</h1>' % 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('<font color="#%06X">%s</font>' % (status_color, contact.status_msg)) self.ui.contactUrlLabel.setText('<b>URL:</b> <a href="%s">%s</a>' % (contact.url, contact.url)) if contact.summary is NotLoaded: self.ui.descriptionEdit.setText( '<h1>Description</h1><p><i>Receiving...</i></p>') missing_fields.add('summary') else: self.ui.descriptionEdit.setText( '<h1>Description</h1><p>%s</p>' % contact.summary.replace('\n', '<br />')) if not contact.profile: missing_fields.add('profile') elif not self.loaded_profile: self.loaded_profile = True for head in contact.profile.itervalues(): 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.itervalues(): self.process_node(sub, value) elif isinstance(node.value, list): value = QLabel('<br />'.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'<b>%s:</b> ' % node.label) widget.layout().addRow(label, value) elif isinstance(widget.layout(), QVBoxLayout): widget.layout().addWidget(QLabel(u'<h3>%s</h3>' % node.label)) widget.layout().addWidget(value) else: logging.warning('Not supported widget: %r' % widget) 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() 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): self.displayed_photo_idx = len(self.contact.photos) - 1 if self.displayed_photo_idx < 0: self.ui.photoUrlLabel.setText('') return photo = 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 b, 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 = '<a href="%s">%s</a>' % (photo.url, photo.url) if photo.hidden: text += '<br /><font color=#ff0000><i>(Hidden photo)</i></font>' self.ui.photoUrlLabel.setText(text)
class Result(QFrame): def __init__(self, weboob, app, parent=None): QFrame.__init__(self, parent) self.ui = Ui_Result() self.ui.setupUi(self) self.parent = parent self.weboob = weboob self.app = app self.minis = [] self.current_info_widget = None # action history is composed by the last action and the action list # An action is a function, a list of arguments and a description string self.action_history = {'last_action': None, 'action_list': []} self.connect(self.ui.backButton, SIGNAL("clicked()"), self.doBack) self.ui.backButton.hide() def doAction(self, description, fun, args): ''' Call fun with args as arguments and save it in the action history ''' self.ui.currentActionLabel.setText(description) if self.action_history['last_action'] is not None: self.action_history['action_list'].append( self.action_history['last_action']) self.ui.backButton.setToolTip( self.action_history['last_action']['description']) self.ui.backButton.show() self.action_history['last_action'] = { 'function': fun, 'args': args, 'description': description } return fun(*args) def doBack(self): ''' Go back in action history Basically call previous function and update history ''' if len(self.action_history['action_list']) > 0: todo = self.action_history['action_list'].pop() self.ui.currentActionLabel.setText(todo['description']) self.action_history['last_action'] = todo if len(self.action_history['action_list']) == 0: self.ui.backButton.hide() else: self.ui.backButton.setToolTip( self.action_history['action_list'][-1]['description']) return todo['function'](*todo['args']) def castingAction(self, backend_name, id, role): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) self.process = QtDo(self.weboob, self.addPerson) self.process.do('iter_movie_persons', id, role, backends=backend_name, caps=ICapCinema) self.parent.ui.stopButton.show() def filmographyAction(self, backend_name, id, role): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) self.process = QtDo(self.weboob, self.addMovie) self.process.do('iter_person_movies', id, role, backends=backend_name, caps=ICapCinema) self.parent.ui.stopButton.show() def search(self, tosearch, pattern, lang): if tosearch == 'person': self.searchPerson(pattern) elif tosearch == 'movie': self.searchMovie(pattern) elif tosearch == 'torrent': self.searchTorrent(pattern) elif tosearch == 'subtitle': self.searchSubtitle(lang, pattern) def searchMovie(self, pattern): if not pattern: return self.doAction(u'Search movie "%s"' % pattern, self.searchMovieAction, [pattern]) def searchMovieAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addMovie) #self.process.do('iter_movies', pattern, backends=backend_name, caps=ICapCinema) self.process.do(self.app._do_complete, self.parent.getCount(), ('original_title'), 'iter_movies', pattern, backends=backend_name, caps=ICapCinema) self.parent.ui.stopButton.show() def stopProcess(self): self.process.process.finish_event.set() def addMovie(self, backend, movie): if not backend: self.parent.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.parent.ui.stopButton.hide() return minimovie = MiniMovie(self.weboob, backend, movie, self) self.ui.list_content.layout().addWidget(minimovie) self.minis.append(minimovie) def displayMovie(self, movie, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wmovie = Movie(movie, backend, self) self.ui.info_content.layout().addWidget(wmovie) self.current_info_widget = wmovie QApplication.restoreOverrideCursor() def searchPerson(self, pattern): if not pattern: return self.doAction(u'Search person "%s"' % pattern, self.searchPersonAction, [pattern]) def searchPersonAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addPerson) #self.process.do('iter_persons', pattern, backends=backend_name, caps=ICapCinema) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_persons', pattern, backends=backend_name, caps=ICapCinema) self.parent.ui.stopButton.show() def addPerson(self, backend, person): if not backend: self.parent.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.parent.ui.stopButton.hide() return miniperson = MiniPerson(self.weboob, backend, person, self) self.ui.list_content.layout().addWidget(miniperson) self.minis.append(miniperson) def displayPerson(self, person, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wperson = Person(person, backend, self) self.ui.info_content.layout().addWidget(wperson) self.current_info_widget = wperson QApplication.restoreOverrideCursor() def searchTorrent(self, pattern): if not pattern: return self.doAction(u'Search torrent "%s"' % pattern, self.searchTorrentAction, [pattern]) def searchTorrentAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addTorrent) #self.process.do('iter_torrents', pattern, backends=backend_name, caps=ICapTorrent) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_torrents', pattern, backends=backend_name, caps=ICapTorrent) self.parent.ui.stopButton.show() def addTorrent(self, backend, torrent): if not backend: self.parent.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.parent.ui.stopButton.hide() return minitorrent = MiniTorrent(self.weboob, backend, torrent, self) self.ui.list_content.layout().addWidget(minitorrent) self.minis.append(minitorrent) def displayTorrent(self, torrent, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wtorrent = Torrent(torrent, backend, self) self.ui.info_content.layout().addWidget(wtorrent) self.current_info_widget = wtorrent def searchSubtitle(self, lang, pattern): if not pattern: return self.doAction(u'Search subtitle "%s" (lang:%s)' % (pattern, lang), self.searchSubtitleAction, [lang, pattern]) def searchSubtitleAction(self, lang, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addSubtitle) #self.process.do('iter_subtitles', lang, pattern, backends=backend_name, caps=ICapSubtitle) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_subtitles', lang, pattern, backends=backend_name, caps=ICapSubtitle) self.parent.ui.stopButton.show() def addSubtitle(self, backend, subtitle): if not backend: self.parent.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.parent.ui.stopButton.hide() return minisubtitle = MiniSubtitle(self.weboob, backend, subtitle, self) self.ui.list_content.layout().addWidget(minisubtitle) self.minis.append(minisubtitle) def displaySubtitle(self, subtitle, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wsubtitle = Subtitle(subtitle, backend, self) self.ui.info_content.layout().addWidget(wsubtitle) self.current_info_widget = wsubtitle def searchId(self, id, stype): QApplication.setOverrideCursor(Qt.WaitCursor) title_field = 'name' if stype == 'movie': cap = ICapCinema title_field = 'original_title' elif stype == 'person': cap = ICapCinema elif stype == 'torrent': cap = ICapTorrent elif stype == 'subtitle': cap = ICapSubtitle if '@' in id: backend_name = id.split('@')[1] id = id.split('@')[0] else: backend_name = None for backend in self.weboob.iter_backends(): if backend.has_caps(cap) and ( (backend_name and backend.name == backend_name) or not backend_name): exec('object = backend.get_%s(id)' % (stype)) if object: func_display = 'self.display' + stype[0].upper( ) + stype[1:] exec( "self.doAction('Details of %s \"%%s\"' %% object.%s, %s, [object, backend])" % (stype, title_field, func_display)) QApplication.restoreOverrideCursor()
class MainWindow(QtMainWindow): def __init__(self, config, weboob, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.weboob = weboob self.backend = None self.connect(self.ui.idEdit, SIGNAL("returnPressed()"), self.loadPage) self.connect(self.ui.loadButton, SIGNAL("clicked()"), self.loadPage) self.connect(self.ui.tabWidget, SIGNAL("currentChanged(int)"), self._currentTabChanged) self.connect(self.ui.saveButton, SIGNAL("clicked()"), self.savePage) self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.contentEdit, SIGNAL("textChanged()"), self._textChanged) self.connect(self.ui.loadHistoryButton, SIGNAL("clicked()"), self.loadHistory) if hasattr(self.ui.descriptionEdit, "setPlaceholderText"): self.ui.descriptionEdit.setPlaceholderText("Edit summary") if self.weboob.count_backends() == 0: self.backendsConfig() else: self.loadBackends() def backendsConfig(self): """ Opens backends configuration dialog when 'Backends' is clicked """ bckndcfg = BackendCfg(self.weboob, (ICapContent, ), self) if bckndcfg.run(): self.loadBackends() def loadBackends(self): """ Fills the backends comboBox with available backends """ self.ui.backendBox.clear() for backend in self.weboob.iter_backends(): self.ui.backendBox.insertItem(0, backend.name) def _currentTabChanged(self): """ Loads history or preview when the corresponding tabs are shown """ if self.ui.tabWidget.currentIndex() == 1: if self.backend is not None: self.loadPreview() elif self.ui.tabWidget.currentIndex() == 2: if self.backend is not None: self.loadHistory() def _textChanged(self): """ The text in the content QPlainTextEdit has changed """ if self.backend: self.ui.saveButton.setEnabled(True) self.ui.saveButton.setText('Save') def loadPage(self): """ Loads a page's source into the 'content' QPlainTextEdit """ _id = unicode(self.ui.idEdit.text()) if not _id: return self.ui.loadButton.setEnabled(False) self.ui.loadButton.setText('Loading...') self.ui.contentEdit.setReadOnly(True) backend = str(self.ui.backendBox.currentText()) self.process = QtDo(self.weboob, self._loadedPage, self._errorLoadPage) self.process.do('get_content', _id, backends=(backend, )) def _loadedPage(self, backend, data): """ Callback for loadPage """ if not backend: # Loading is finished self.process = None if self.backend: self.ui.contentEdit.setReadOnly(False) self.ui.loadButton.setEnabled(True) self.ui.loadButton.setText('Load') return if not data: self.content = None self.backend = None QMessageBox.critical( self, self.tr('Unable to open page'), 'Unable to open page "%s" on %s: it does not exist.' % (self.ui.idEdit.text(), self.ui.backendBox.currentText()), QMessageBox.Ok) return self.content = data self.ui.contentEdit.setPlainText(self.content.content) self.setWindowTitle("QWebcontentedit - %s@%s" % (self.content.id, backend.name)) self.backend = backend def _errorLoadPage(self, backend, error, backtrace): """ Error callback for loadPage """ content = unicode( self.tr('Unable to load page:\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 page'), content, QMessageBox.Ok) self.ui.loadButton.setEnabled(True) self.ui.loadButton.setText("Load") def savePage(self): """ Saves the current page to the remote site """ if self.backend is None: return new_content = unicode(self.ui.contentEdit.toPlainText()) minor = self.ui.minorBox.isChecked() if new_content != self.content.content: self.ui.saveButton.setEnabled(False) self.ui.saveButton.setText('Saving...') self.ui.contentEdit.setReadOnly(True) self.content.content = new_content message = unicode(self.ui.descriptionEdit.text()) self.process = QtDo(self.weboob, self._savedPage, self._errorSavePage) self.process.do('push_content', self.content, message, minor=minor, backends=self.backend) def _savedPage(self, backend, data): """ Callback for savePage's QtDo """ if not backend: # saving has finished self.process = None self.ui.saveButton.setText('Saved') self.ui.contentEdit.setReadOnly(False) return self.ui.descriptionEdit.clear() def _errorSavePage(self, backend, error, backtrace): """ """ content = unicode( self.tr('Unable to save page:\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 page'), content, QMessageBox.Ok) self.ui.saveButton.setEnabled(True) self.ui.saveButton.setText("Save") def loadPreview(self): """ Loads the current page's preview into the preview QTextEdit """ tmp_content = deepcopy(self.content) tmp_content.content = unicode(self.ui.contentEdit.toPlainText()) self.ui.previewEdit.setHtml( self.backend.get_content_preview(tmp_content)) def loadHistory(self): """ Loads the page's log into the 'History' tab """ if self.backend is None: return self.ui.loadHistoryButton.setEnabled(False) self.ui.loadHistoryButton.setText("Loading...") self.ui.historyTable.clear() self.ui.historyTable.setRowCount(0) self.ui.historyTable.setHorizontalHeaderLabels( ["Revision", "Time", "Author", "Summary"]) self.ui.historyTable.setColumnWidth(3, 1000) self.process = QtDo(self.weboob, self._gotRevision, self._errorHistory) self.process.do('iter_revisions', self.content.id, max_results=self.ui.nbRevBox.value(), backends=(self.backend, )) def _gotRevision(self, backend, revision): """ Callback for loadHistory's QtDo """ if not backend: # The last revision has been processed self.process = None self.ui.loadHistoryButton.setEnabled(True) self.ui.loadHistoryButton.setText("Reload") return # we set the flags to Qt.ItemIsEnabled so that the items # are not modifiable (they are modifiable by default) item_revision = QTableWidgetItem(revision.id) item_revision.setFlags(Qt.ItemIsEnabled) item_time = QTableWidgetItem( revision.timestamp.strftime('%Y-%m-%d %H:%M:%S')) item_time.setFlags(Qt.ItemIsEnabled) item_author = QTableWidgetItem(revision.author) item_author.setFlags(Qt.ItemIsEnabled) item_summary = QTableWidgetItem(revision.comment) item_summary.setFlags(Qt.ItemIsEnabled) row = self.ui.historyTable.currentRow() + 1 self.ui.historyTable.insertRow(row) self.ui.historyTable.setItem(row, 0, item_revision) self.ui.historyTable.setItem(row, 1, item_time) self.ui.historyTable.setItem(row, 2, item_author) self.ui.historyTable.setItem(row, 3, item_summary) self.ui.historyTable.setCurrentCell(row, 0) def _errorHistory(self, backend, error, backtrace): """ Loading the history has failed """ content = unicode( self.tr('Unable to load history:\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 history'), content, QMessageBox.Ok) self.ui.loadHistoryButton.setEnabled(True) self.ui.loadHistoryButton.setText("Reload")
class Result(QFrame): def __init__(self, weboob, app, parent=None): QFrame.__init__(self, parent) self.ui = Ui_Result() self.ui.setupUi(self) self.parent = parent self.weboob = weboob self.app = app self.minis = [] self.current_info_widget = None # action history is composed by the last action and the action list # An action is a function, a list of arguments and a description string self.action_history = {'last_action': None, 'action_list': []} self.connect(self.ui.backButton, SIGNAL("clicked()"), self.doBack) self.ui.backButton.hide() def doAction(self, description, fun, args): ''' Call fun with args as arguments and save it in the action history ''' self.ui.currentActionLabel.setText(description) if self.action_history['last_action'] is not None: self.action_history['action_list'].append( self.action_history['last_action']) self.ui.backButton.setToolTip( self.action_history['last_action']['description']) self.ui.backButton.show() self.action_history['last_action'] = { 'function': fun, 'args': args, 'description': description } return fun(*args) def doBack(self): ''' Go back in action history Basically call previous function and update history ''' if len(self.action_history['action_list']) > 0: todo = self.action_history['action_list'].pop() self.ui.currentActionLabel.setText(todo['description']) self.action_history['last_action'] = todo if len(self.action_history['action_list']) == 0: self.ui.backButton.hide() else: self.ui.backButton.setToolTip( self.action_history['action_list'][-1]['description']) return todo['function'](*todo['args']) def processFinished(self): self.parent.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.parent.ui.stopButton.hide() def searchRecipe(self, pattern): if not pattern: return self.doAction(u'Search recipe "%s"' % pattern, self.searchRecipeAction, [pattern]) def searchRecipeAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addRecipe, fb=self.processFinished) self.process.do(self.app._do_complete, self.parent.getCount(), ('title'), 'iter_recipes', pattern, backends=backend_name, caps=CapRecipe) self.parent.ui.stopButton.show() def addRecipe(self, recipe): minirecipe = MiniRecipe(self.weboob, self.weboob[recipe.backend], recipe, self) self.ui.list_content.layout().insertWidget( self.ui.list_content.layout().count() - 1, minirecipe) self.minis.append(minirecipe) def displayRecipe(self, recipe, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wrecipe = Recipe(recipe, backend, self) self.ui.info_content.layout().addWidget(wrecipe) self.current_info_widget = wrecipe QApplication.restoreOverrideCursor() def searchId(self, id): QApplication.setOverrideCursor(Qt.WaitCursor) if '@' in id: backend_name = id.split('@')[1] id = id.split('@')[0] else: backend_name = None for backend in self.weboob.iter_backends(): if (backend_name and backend.name == backend_name) or not backend_name: recipe = backend.get_recipe(id) if recipe: self.doAction('Details of recipe "%s"' % recipe.title, self.displayRecipe, [recipe, backend]) QApplication.restoreOverrideCursor()
class Result(QFrame): def __init__(self, weboob, app, parent=None): QFrame.__init__(self, parent) self.ui = Ui_Result() self.ui.setupUi(self) self.parent = parent self.weboob = weboob self.app = app self.minis = [] self.current_info_widget = None # action history is composed by the last action and the action list # An action is a function, a list of arguments and a description string self.action_history = {'last_action': None, 'action_list': []} self.connect(self.ui.backButton, SIGNAL("clicked()"), self.doBack) self.ui.backButton.hide() def doAction(self, description, fun, args): ''' Call fun with args as arguments and save it in the action history ''' self.ui.currentActionLabel.setText(description) if self.action_history['last_action'] is not None: self.action_history['action_list'].append(self.action_history['last_action']) self.ui.backButton.setToolTip(self.action_history['last_action']['description']) self.ui.backButton.show() self.action_history['last_action'] = {'function': fun, 'args': args, 'description': description} return fun(*args) def doBack(self): ''' Go back in action history Basically call previous function and update history ''' if len(self.action_history['action_list']) > 0: todo = self.action_history['action_list'].pop() self.ui.currentActionLabel.setText(todo['description']) self.action_history['last_action'] = todo if len(self.action_history['action_list']) == 0: self.ui.backButton.hide() else: self.ui.backButton.setToolTip(self.action_history['action_list'][-1]['description']) return todo['function'](*todo['args']) def processFinished(self): self.parent.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.parent.ui.stopButton.hide() def searchRecipe(self,pattern): if not pattern: return self.doAction(u'Search recipe "%s"' % pattern, self.searchRecipeAction, [pattern]) def searchRecipeAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str(self.parent.ui.backendEdit.itemData(self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addRecipe, fb=self.processFinished) self.process.do(self.app._do_complete, self.parent.getCount(), ('title'), 'iter_recipes', pattern, backends=backend_name, caps=CapRecipe) self.parent.ui.stopButton.show() def addRecipe(self, recipe): minirecipe = MiniRecipe(self.weboob, self.weboob[recipe.backend], recipe, self) self.ui.list_content.layout().insertWidget(self.ui.list_content.layout().count()-1,minirecipe) self.minis.append(minirecipe) def displayRecipe(self, recipe, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget(self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wrecipe = Recipe(recipe, backend, self) self.ui.info_content.layout().addWidget(wrecipe) self.current_info_widget = wrecipe QApplication.restoreOverrideCursor() def searchId(self, id): QApplication.setOverrideCursor(Qt.WaitCursor) if '@' in id: backend_name = id.split('@')[1] id = id.split('@')[0] else: backend_name = None for backend in self.weboob.iter_backends(): if (backend_name and backend.name == backend_name) or not backend_name: recipe = backend.get_recipe(id) if recipe: self.doAction('Details of recipe "%s"' % recipe.title, self.displayRecipe, [recipe, backend]) QApplication.restoreOverrideCursor()
class MainWindow(QtMainWindow): def __init__(self, config, weboob, app, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.weboob = weboob self.minivideos = [] self.app = app self.ui.sortbyEdit.setCurrentIndex(int(self.config.get('settings', 'sortby'))) self.ui.nsfwCheckBox.setChecked(int(self.config.get('settings', 'nsfw'))) self.ui.sfwCheckBox.setChecked(int(self.config.get('settings', 'sfw'))) self.connect(self.ui.searchEdit, SIGNAL("returnPressed()"), self.search) self.connect(self.ui.urlEdit, SIGNAL("returnPressed()"), self.openURL) self.connect(self.ui.nsfwCheckBox, SIGNAL("stateChanged(int)"), self.nsfwChanged) self.connect(self.ui.sfwCheckBox, SIGNAL("stateChanged(int)"), self.sfwChanged) self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.loadBackendsList() if self.ui.backendEdit.count() == 0: self.backendsConfig() def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (CapVideo,), self) if bckndcfg.run(): self.loadBackendsList() def loadBackendsList(self): self.ui.backendEdit.clear() for i, backend in enumerate(self.weboob.iter_backends()): if i == 0: self.ui.backendEdit.addItem('All backends', '') self.ui.backendEdit.addItem(backend.name, backend.name) if backend.name == self.config.get('settings', 'backend'): self.ui.backendEdit.setCurrentIndex(i+1) if self.ui.backendEdit.count() == 0: self.ui.searchEdit.setEnabled(False) self.ui.urlEdit.setEnabled(False) else: self.ui.searchEdit.setEnabled(True) self.ui.urlEdit.setEnabled(True) def nsfwChanged(self, state): self.config.set('settings', 'nsfw', int(self.ui.nsfwCheckBox.isChecked())) self.updateVideosDisplay() def sfwChanged(self, state): self.config.set('settings', 'sfw', int(self.ui.sfwCheckBox.isChecked())) self.updateVideosDisplay() def updateVideosDisplay(self): for minivideo in self.minivideos: if (minivideo.video.nsfw and self.ui.nsfwCheckBox.isChecked() or not minivideo.video.nsfw and self.ui.sfwCheckBox.isChecked()): minivideo.show() else: minivideo.hide() def search(self): pattern = unicode(self.ui.searchEdit.text()) if not pattern: return for minivideo in self.minivideos: self.ui.scrollAreaContent.layout().removeWidget(minivideo) minivideo.hide() minivideo.deleteLater() self.minivideos = [] self.ui.searchEdit.setEnabled(False) backend_name = str(self.ui.backendEdit.itemData(self.ui.backendEdit.currentIndex()).toString()) def finished(): self.ui.searchEdit.setEnabled(True) self.process = None self.process = QtDo(self.weboob, self.addVideo, fb=finished) self.process.do(self.app._do_complete, 20, (), 'search_videos', pattern, self.ui.sortbyEdit.currentIndex(), nsfw=True, backends=backend_name) def addVideo(self, video): minivideo = MiniVideo(self.weboob, self.weboob[video.backend], video) self.ui.scrollAreaContent.layout().addWidget(minivideo) self.minivideos.append(minivideo) if (video.nsfw and not self.ui.nsfwCheckBox.isChecked() or not video.nsfw and not self.ui.sfwCheckBox.isChecked()): minivideo.hide() def openURL(self): url = unicode(self.ui.urlEdit.text()) if not url: return for backend in self.weboob.iter_backends(): video = backend.get_video(url) if video: video_widget = Video(video, self) video_widget.show() self.ui.urlEdit.clear() def closeEvent(self, ev): self.config.set('settings', 'backend', str(self.ui.backendEdit.itemData(self.ui.backendEdit.currentIndex()).toString())) self.config.set('settings', 'sortby', self.ui.sortbyEdit.currentIndex()) self.config.save() ev.accept()
class ContactsWidget(QWidget): def __init__(self, weboob, parent=None): QWidget.__init__(self, 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('Onlines', MetaGroup(self.weboob, 'online', self.tr('Online'))) self.ui.groupBox.addItem('Offlines', MetaGroup(self.weboob, 'offline', self.tr('Offline'))) self.ui.groupBox.setCurrentIndex(1) self.connect(self.ui.groupBox, SIGNAL('currentIndexChanged(int)'), self.groupChanged) self.connect(self.ui.contactList, SIGNAL('itemClicked(QListWidgetItem*)'), self.contactChanged) self.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.refreshContactList) self.connect(self.ui.urlButton, SIGNAL('clicked()'), self.urlClicked) def load(self): self.refreshContactList() self.ui.backendsList.clear() for backend in self.weboob.iter_backends(): self.ui.backendsList.addItem(backend.name) def groupChanged(self, i): self.refreshContactList() def refreshContactList(self): self.ui.contactList.clear() self.ui.refreshButton.setEnabled(False) i = self.ui.groupBox.currentIndex() group = self.ui.groupBox.itemData(i).toPyObject() 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.itervalues(): 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('<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % (contact.name, status_color, status, contact.backend)) item.setData(Qt.UserRole, contact) if contact.photos is NotLoaded: process = QtDo(self.weboob, lambda b, 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 = contact.photos.values()[0] process = QtDo(self.weboob, lambda b, p: self.setPhoto(contact, item)) process.do('fillobj', photo, ['thumbnail_data'], backends=contact.backend) self.photo_processes[contact.id] = process for i in xrange(self.ui.contactList.count()): if self.ui.contactList.item(i).data(Qt.UserRole).toPyObject().status > contact.status: self.ui.contactList.insertItem(i, item) return self.ui.contactList.addItem(item) def contactChanged(self, current): if not current: return contact = current.data(Qt.UserRole).toPyObject() self.setContact(contact) def setContact(self, contact): if not contact or contact == self.contact: return 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(ICapMessages): self.ui.tabWidget.addTab(ContactThread(self.weboob, self.contact, backend.has_caps(ICapMessagesPost)), self.tr('Messages')) if backend.has_caps(ICapChat): self.ui.tabWidget.addTab(QWidget(), self.tr('Chat')) self.ui.tabWidget.addTab(QWidget(), self.tr('Calendar')) self.ui.tabWidget.addTab(QWidget(), self.tr('Notes')) def urlClicked(self): url = unicode(self.ui.urlEdit.text()) if not url: return backend_name = unicode(self.ui.backendsList.currentText()) self.ui.urlButton.setEnabled(False) self.url_process = QtDo(self.weboob, self.urlClicked_cb, self.urlClicked_eb) self.url_process.do('get_contact', url, backends=backend_name) def urlClicked_cb(self, backend, contact): if not backend: self.url_process = None self.ui.urlButton.setEnabled(True) return self.ui.urlEdit.clear() self.setContact(contact) def urlClicked_eb(self, backend, error, backtrace): content = unicode(self.tr('Unable to get contact:\n%s\n')) % error if logging.root.level == logging.DEBUG: content += '\n%s\n' % backtrace QMessageBox.critical(self, self.tr('Error while getting contact'), content, QMessageBox.Ok)
class Result(QFrame): def __init__(self, weboob, app, parent=None): QFrame.__init__(self, parent) self.ui = Ui_Result() self.ui.setupUi(self) self.parent = parent self.weboob = weboob self.app = app self.minis = [] self.current_info_widget = None # action history is composed by the last action and the action list # An action is a function, a list of arguments and a description string self.action_history = {'last_action': None, 'action_list': []} self.connect(self.ui.backButton, SIGNAL("clicked()"), self.doBack) self.ui.backButton.hide() def doAction(self, description, fun, args): ''' Call fun with args as arguments and save it in the action history ''' self.ui.currentActionLabel.setText(description) if self.action_history['last_action'] is not None: self.action_history['action_list'].append( self.action_history['last_action']) self.ui.backButton.setToolTip( self.action_history['last_action']['description']) self.ui.backButton.show() self.action_history['last_action'] = { 'function': fun, 'args': args, 'description': description } return fun(*args) def doBack(self): ''' Go back in action history Basically call previous function and update history ''' if len(self.action_history['action_list']) > 0: todo = self.action_history['action_list'].pop() self.ui.currentActionLabel.setText(todo['description']) self.action_history['last_action'] = todo if len(self.action_history['action_list']) == 0: self.ui.backButton.hide() else: self.ui.backButton.setToolTip( self.action_history['action_list'][-1]['description']) return todo['function'](*todo['args']) def castingAction(self, backend_name, id, role): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) self.process = QtDo(self.weboob, self.addPerson, fb=self.processFinished) self.process.do('iter_movie_persons', id, role, backends=backend_name, caps=CapCinema) self.parent.ui.stopButton.show() def moviesInCommonAction(self, backend_name, id1, id2): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) for a_backend in self.weboob.iter_backends(): if (backend_name and a_backend.name == backend_name): backend = a_backend person1 = backend.get_person(id1) person2 = backend.get_person(id2) lid1 = [] for p in backend.iter_person_movies_ids(id1): lid1.append(p) lid2 = [] for p in backend.iter_person_movies_ids(id2): lid2.append(p) inter = list(set(lid1) & set(lid2)) chrono_list = [] for common in inter: movie = backend.get_movie(common) movie.backend = backend_name role1 = movie.get_roles_by_person_id(person1.id) role2 = movie.get_roles_by_person_id(person2.id) if (movie.release_date != NotAvailable): year = movie.release_date.year else: year = '????' movie.short_description = '(%s) %s as %s ; %s as %s' % ( year, person1.name, ', '.join(role1), person2.name, ', '.join(role2)) i = 0 while (i < len(chrono_list) and movie.release_date != NotAvailable and (chrono_list[i].release_date == NotAvailable or year > chrono_list[i].release_date.year)): i += 1 chrono_list.insert(i, movie) for movie in chrono_list: self.addMovie(movie) self.processFinished() def personsInCommonAction(self, backend_name, id1, id2): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) for a_backend in self.weboob.iter_backends(): if (backend_name and a_backend.name == backend_name): backend = a_backend movie1 = backend.get_movie(id1) movie2 = backend.get_movie(id2) lid1 = [] for p in backend.iter_movie_persons_ids(id1): lid1.append(p) lid2 = [] for p in backend.iter_movie_persons_ids(id2): lid2.append(p) inter = list(set(lid1) & set(lid2)) for common in inter: person = backend.get_person(common) person.backend = backend_name role1 = movie1.get_roles_by_person_id(person.id) role2 = movie2.get_roles_by_person_id(person.id) person.short_description = '%s in %s ; %s in %s' % ( ', '.join(role1), movie1.original_title, ', '.join(role2), movie2.original_title) self.addPerson(person) self.processFinished() def filmographyAction(self, backend_name, id, role): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) self.process = QtDo(self.weboob, self.addMovie, fb=self.processFinished) self.process.do('iter_person_movies', id, role, backends=backend_name, caps=CapCinema) self.parent.ui.stopButton.show() def search(self, tosearch, pattern, lang): if tosearch == 'person': self.searchPerson(pattern) elif tosearch == 'movie': self.searchMovie(pattern) elif tosearch == 'torrent': self.searchTorrent(pattern) elif tosearch == 'subtitle': self.searchSubtitle(lang, pattern) def searchMovie(self, pattern): if not pattern: return self.doAction(u'Search movie "%s"' % pattern, self.searchMovieAction, [pattern]) def searchMovieAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addMovie, fb=self.processFinished) #self.process.do('iter_movies', pattern, backends=backend_name, caps=CapCinema) self.process.do(self.app._do_complete, self.parent.getCount(), ('original_title'), 'iter_movies', pattern, backends=backend_name, caps=CapCinema) self.parent.ui.stopButton.show() def stopProcess(self): self.process.process.finish_event.set() def addMovie(self, movie): minimovie = MiniMovie(self.weboob, self.weboob[movie.backend], movie, self) self.ui.list_content.layout().insertWidget( self.ui.list_content.layout().count() - 1, minimovie) self.minis.append(minimovie) def displayMovie(self, movie, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wmovie = Movie(movie, backend, self) self.ui.info_content.layout().addWidget(wmovie) self.current_info_widget = wmovie QApplication.restoreOverrideCursor() def searchPerson(self, pattern): if not pattern: return self.doAction(u'Search person "%s"' % pattern, self.searchPersonAction, [pattern]) def searchPersonAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addPerson, fb=self.processFinished) #self.process.do('iter_persons', pattern, backends=backend_name, caps=CapCinema) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_persons', pattern, backends=backend_name, caps=CapCinema) self.parent.ui.stopButton.show() def addPerson(self, person): miniperson = MiniPerson(self.weboob, self.weboob[person.backend], person, self) self.ui.list_content.layout().insertWidget( self.ui.list_content.layout().count() - 1, miniperson) self.minis.append(miniperson) def displayPerson(self, person, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wperson = Person(person, backend, self) self.ui.info_content.layout().addWidget(wperson) self.current_info_widget = wperson QApplication.restoreOverrideCursor() def searchTorrent(self, pattern): if not pattern: return self.doAction(u'Search torrent "%s"' % pattern, self.searchTorrentAction, [pattern]) def searchTorrentAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addTorrent, fb=self.processFinished) #self.process.do('iter_torrents', pattern, backends=backend_name, caps=CapTorrent) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_torrents', pattern, backends=backend_name, caps=CapTorrent) self.parent.ui.stopButton.show() def processFinished(self): self.parent.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.parent.ui.stopButton.hide() def addTorrent(self, torrent): minitorrent = MiniTorrent(self.weboob, self.weboob[torrent.backend], torrent, self) self.ui.list_content.layout().insertWidget( self.ui.list_content.layout().count() - 1, minitorrent) self.minis.append(minitorrent) def displayTorrent(self, torrent, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wtorrent = Torrent(torrent, backend, self) self.ui.info_content.layout().addWidget(wtorrent) self.current_info_widget = wtorrent def searchSubtitle(self, lang, pattern): if not pattern: return self.doAction(u'Search subtitle "%s" (lang:%s)' % (pattern, lang), self.searchSubtitleAction, [lang, pattern]) def searchSubtitleAction(self, lang, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.parent.ui.backendEdit.itemData( self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addSubtitle, fb=self.processFinished) #self.process.do('iter_subtitles', lang, pattern, backends=backend_name, caps=CapSubtitle) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_subtitles', lang, pattern, backends=backend_name, caps=CapSubtitle) self.parent.ui.stopButton.show() def addSubtitle(self, subtitle): minisubtitle = MiniSubtitle(self.weboob, self.weboob[subtitle.backend], subtitle, self) self.ui.list_content.layout().insertWidget( self.ui.list_content.layout().count() - 1, minisubtitle) self.minis.append(minisubtitle) def displaySubtitle(self, subtitle, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wsubtitle = Subtitle(subtitle, backend, self) self.ui.info_content.layout().addWidget(wsubtitle) self.current_info_widget = wsubtitle def searchId(self, id, stype): QApplication.setOverrideCursor(Qt.WaitCursor) title_field = 'name' if stype == 'movie': cap = CapCinema title_field = 'original_title' elif stype == 'person': cap = CapCinema elif stype == 'torrent': cap = CapTorrent elif stype == 'subtitle': cap = CapSubtitle if '@' in id: backend_name = id.split('@')[1] id = id.split('@')[0] else: backend_name = None for backend in self.weboob.iter_backends(): if backend.has_caps(cap) and ( (backend_name and backend.name == backend_name) or not backend_name): exec('object = backend.get_%s(id)' % (stype)) if object: func_display = 'self.display' + stype[0].upper( ) + stype[1:] exec( "self.doAction('Details of %s \"%%s\"' %% object.%s, %s, [object, backend])" % (stype, title_field, func_display)) QApplication.restoreOverrideCursor()
class ContactThread(QWidget): """ The thread of the selected contact. """ def __init__(self, weboob, contact, support_reply, parent=None): QWidget.__init__(self, 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.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.refreshMessages) if support_reply: self.connect(self.ui.sendButton, SIGNAL('clicked()'), self.postReply) else: self.ui.frame.hide() self.refreshMessages() def refreshMessages(self, fillobj=False): if self.process_msg: return self.ui.refreshButton.setEnabled(False) self.process_msg = QtDo(self.weboob, self.gotThread, self.gotError) 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, backend, thread): if not thread: #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 return 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...')) self.connect(button, SIGNAL('clicked()'), lambda: self._load_button_pressed(button)) if pos >= 0: self.ui.scrollAreaContent.layout().insertWidget(pos, button) else: self.ui.scrollAreaContent.layout().addWidget(button) def _load_button_pressed(self, button): self.ui.scrollAreaContent.layout().removeWidget(button) button.hide() button.deleteLater() self.refreshMessages(fillobj=True) def postReply(self): text = unicode(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, self._postReply_cb, self._postReply_eb) self.process_reply.do('post_message', m, backends=self.contact.backend) def _postReply_cb(self, backend, ignored): if not backend: return 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 = unicode(self.tr('Unable to send message:\n%s\n')) % error if logging.root.level == logging.DEBUG: content += '\n%s\n' % backtrace QMessageBox.critical(self, self.tr('Error while posting reply'), content, QMessageBox.Ok) self.process_reply = None
class MainWindow(QtMainWindow): def __init__(self, config, weboob, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.weboob = weboob self.backend = None self.connect(self.ui.idEdit, SIGNAL("returnPressed()"), self.loadPage) self.connect(self.ui.loadButton, SIGNAL("clicked()"), self.loadPage) self.connect(self.ui.tabWidget, SIGNAL("currentChanged(int)"), self._currentTabChanged) self.connect(self.ui.saveButton, SIGNAL("clicked()"), self.savePage) self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.contentEdit, SIGNAL("textChanged()"), self._textChanged) self.connect(self.ui.loadHistoryButton, SIGNAL("clicked()"), self.loadHistory) if hasattr(self.ui.descriptionEdit, "setPlaceholderText"): self.ui.descriptionEdit.setPlaceholderText("Edit summary") if self.weboob.count_backends() == 0: self.backendsConfig() else: self.loadBackends() def backendsConfig(self): """ Opens backends configuration dialog when 'Backends' is clicked """ bckndcfg = BackendCfg(self.weboob, (ICapContent,), self) if bckndcfg.run(): self.loadBackends() def loadBackends(self): """ Fills the backends comboBox with available backends """ self.ui.backendBox.clear() for backend in self.weboob.iter_backends(): self.ui.backendBox.insertItem(0, backend.name) def _currentTabChanged(self): """ Loads history or preview when the corresponding tabs are shown """ if self.ui.tabWidget.currentIndex() == 1: if self.backend is not None: self.loadPreview() elif self.ui.tabWidget.currentIndex() == 2: if self.backend is not None: self.loadHistory() def _textChanged(self): """ The text in the content QPlainTextEdit has changed """ if self.backend: self.ui.saveButton.setEnabled(True) self.ui.saveButton.setText('Save') def loadPage(self): """ Loads a page's source into the 'content' QPlainTextEdit """ _id = unicode(self.ui.idEdit.text()) if not _id: return self.ui.loadButton.setEnabled(False) self.ui.loadButton.setText('Loading...') self.ui.contentEdit.setReadOnly(True) backend = str(self.ui.backendBox.currentText()) self.process = QtDo(self.weboob, self._loadedPage, self._errorLoadPage) self.process.do('get_content', _id, backends=(backend,)) def _loadedPage(self, backend, data): """ Callback for loadPage """ if not backend: # Loading is finished self.process = None if self.backend: self.ui.contentEdit.setReadOnly(False) self.ui.loadButton.setEnabled(True) self.ui.loadButton.setText('Load') return if not data: self.content = None self.backend = None QMessageBox.critical(self, self.tr('Unable to open page'), 'Unable to open page "%s" on %s: it does not exist.' % (self.ui.idEdit.text(), self.ui.backendBox.currentText()), QMessageBox.Ok) return self.content = data self.ui.contentEdit.setPlainText(self.content.content) self.setWindowTitle("QWebcontentedit - %s@%s" %(self.content.id, backend.name)) self.backend = backend def _errorLoadPage(self, backend, error, backtrace): """ Error callback for loadPage """ content = unicode(self.tr('Unable to load page:\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 page'), content, QMessageBox.Ok) self.ui.loadButton.setEnabled(True) self.ui.loadButton.setText("Load") def savePage(self): """ Saves the current page to the remote site """ if self.backend is None: return new_content = unicode(self.ui.contentEdit.toPlainText()) minor = self.ui.minorBox.isChecked() if new_content != self.content.content: self.ui.saveButton.setEnabled(False) self.ui.saveButton.setText('Saving...') self.ui.contentEdit.setReadOnly(True) self.content.content = new_content message = unicode(self.ui.descriptionEdit.text()) self.process = QtDo(self.weboob, self._savedPage, self._errorSavePage) self.process.do('push_content', self.content, message, minor=minor, backends=self.backend) def _savedPage(self, backend, data): """ Callback for savePage's QtDo """ if not backend: # saving has finished self.process = None self.ui.saveButton.setText('Saved') self.ui.contentEdit.setReadOnly(False) return self.ui.descriptionEdit.clear() def _errorSavePage(self, backend, error, backtrace): """ """ content = unicode(self.tr('Unable to save page:\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 page'), content, QMessageBox.Ok) self.ui.saveButton.setEnabled(True) self.ui.saveButton.setText("Save") def loadPreview(self): """ Loads the current page's preview into the preview QTextEdit """ tmp_content = deepcopy(self.content) tmp_content.content = unicode(self.ui.contentEdit.toPlainText()) self.ui.previewEdit.setHtml(self.backend.get_content_preview(tmp_content)) def loadHistory(self): """ Loads the page's log into the 'History' tab """ if self.backend is None: return self.ui.loadHistoryButton.setEnabled(False) self.ui.loadHistoryButton.setText("Loading...") self.ui.historyTable.clear() self.ui.historyTable.setRowCount(0) self.ui.historyTable.setHorizontalHeaderLabels(["Revision", "Time", "Author", "Summary"]) self.ui.historyTable.setColumnWidth(3, 1000) self.process = QtDo(self.weboob, self._gotRevision, self._errorHistory) self.process.do('iter_revisions', self.content.id, max_results=self.ui.nbRevBox.value(), backends=(self.backend,)) def _gotRevision(self, backend, revision): """ Callback for loadHistory's QtDo """ if not backend: # The last revision has been processed self.process = None self.ui.loadHistoryButton.setEnabled(True) self.ui.loadHistoryButton.setText("Reload") return # we set the flags to Qt.ItemIsEnabled so that the items # are not modifiable (they are modifiable by default) item_revision = QTableWidgetItem(revision.id) item_revision.setFlags(Qt.ItemIsEnabled) item_time = QTableWidgetItem(revision.timestamp.strftime('%Y-%m-%d %H:%M:%S')) item_time.setFlags(Qt.ItemIsEnabled) item_author = QTableWidgetItem(revision.author) item_author.setFlags(Qt.ItemIsEnabled) item_summary = QTableWidgetItem(revision.comment) item_summary.setFlags(Qt.ItemIsEnabled) row = self.ui.historyTable.currentRow() + 1 self.ui.historyTable.insertRow(row) self.ui.historyTable.setItem(row, 0, item_revision) self.ui.historyTable.setItem(row, 1, item_time) self.ui.historyTable.setItem(row, 2, item_author) self.ui.historyTable.setItem(row, 3, item_summary) self.ui.historyTable.setCurrentCell(row, 0) def _errorHistory(self, backend, error, backtrace): """ Loading the history has failed """ content = unicode(self.tr('Unable to load history:\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 history'), content, QMessageBox.Ok) self.ui.loadHistoryButton.setEnabled(True) self.ui.loadHistoryButton.setText("Reload")
class MainWindow(QtMainWindow): def __init__(self, config, storage, weboob, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.storage = storage self.weboob = weboob self.process = None self.displayed_photo_idx = 0 self.process_photo = {} self.process_bookmarks = {} # search history is a list of patterns which have been searched self.search_history = self.loadSearchHistory() self.updateCompletion() self.ui.jobFrame.hide() self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.searchEdit, SIGNAL('returnPressed()'), self.doSearch) self.connect(self.ui.jobList, SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem*)'), self.jobSelected) self.connect(self.ui.searchButton, SIGNAL('clicked()'), self.doSearch) self.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.doAdvancedSearch) self.connect(self.ui.queriesTabWidget, SIGNAL('currentChanged(int)'), self.tabChange) self.connect(self.ui.jobListAdvancedSearch, SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem*)'), self.jobSelected) self.connect(self.ui.idEdit, SIGNAL('returnPressed()'), self.openJob) if self.weboob.count_backends() == 0: self.backendsConfig() def loadSearchHistory(self): ''' Return search string history list loaded from history file ''' result = [] history_path = os.path.join(self.weboob.workdir, 'qhandjoob_history') if os.path.exists(history_path): f = codecs.open(history_path, 'r', 'utf-8') conf_hist = f.read() f.close() if conf_hist is not None and conf_hist.strip() != '': result = conf_hist.strip().split('\n') return result def saveSearchHistory(self): ''' Save search history in history file ''' if len(self.search_history) > 0: history_path = os.path.join(self.weboob.workdir, 'qhandjoob_history') f = codecs.open(history_path, 'w', 'utf-8') f.write('\n'.join(self.search_history)) f.close() def updateCompletion(self): qc = QCompleter(QStringList(self.search_history), self) qc.setCaseSensitivity(Qt.CaseInsensitive) self.ui.searchEdit.setCompleter(qc) def tabChange(self, index): if index == 1: self.doAdvancedSearch() def doAdvancedSearch(self): QApplication.setOverrideCursor(Qt.WaitCursor) self.ui.jobListAdvancedSearch.clear() self.process = QtDo(self.weboob, self.addJobAdvancedSearch) self.process.do('advanced_search_job') def doSearch(self): QApplication.setOverrideCursor(Qt.WaitCursor) pattern = unicode(self.ui.searchEdit.text()) # arbitrary max number of completion word if pattern: if len(self.search_history) > 50: self.search_history.pop(0) if pattern not in self.search_history: self.search_history.append(pattern) self.updateCompletion() self.ui.jobList.clear() self.process = QtDo(self.weboob, self.addJobSearch) self.process.do('search_job', pattern) def addJobSearch(self, backend, job): item = self.addJob(backend, job) if item: self.ui.jobList.addItem(item) if not backend: QApplication.restoreOverrideCursor() def addJobAdvancedSearch(self, backend, job): item = self.addJob(backend, job) if item: self.ui.jobListAdvancedSearch.addItem(item) if not backend: QApplication.restoreOverrideCursor() def addJob(self, backend, job): if not backend: self.process = None return if not job: return item = JobListWidgetItem(job) item.setAttrs(self.storage) return item def closeEvent(self, event): self.saveSearchHistory() QtMainWindow.closeEvent(self, event) def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (ICapJob,), self) if bckndcfg.run(): pass def jobSelected(self, item, prev): QApplication.setOverrideCursor(Qt.WaitCursor) if item is not None: job = item.job self.ui.queriesTabWidget.setEnabled(False) self.process = QtDo(self.weboob, self.gotJob) self.process.do('fillobj', job, backends=job.backend) else: job = None self.setJob(job) if prev: prev.setAttrs(self.storage) def openJob(self): QApplication.setOverrideCursor(Qt.WaitCursor) url = unicode(self.ui.idEdit.text()) if not url: return for backend in self.weboob.iter_backends(): job = backend.get_job_advert(url) if job: self.process = QtDo(self.weboob, self.gotJob) self.process.do('fillobj', job, backends=job.backend) break self.setJob(job) self.ui.idEdit.clear() QApplication.restoreOverrideCursor() def gotJob(self, backend, job): if not backend: self.ui.queriesTabWidget.setEnabled(True) self.process = None return self.setJob(job) def setJob(self, job): if job: self.ui.descriptionEdit.setText("%s" % job.description) self.ui.titleLabel.setText("<h1>%s</h1>" % 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("<a href='%s'>%s</a>" % (job.url, job.url)) self.ui.jobFrame.show() else: self.ui.jobFrame.hide() QApplication.restoreOverrideCursor()
class MainWindow(QtMainWindow): def __init__(self, config, weboob, app, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.weboob = weboob self.app = app self.minis = [] self.current_info_widget = None # search history is a list of patterns which have been searched self.search_history = self.loadSearchHistory() self.updateCompletion() # action history is composed by the last action and the action list # An action is a function, a list of arguments and a description string self.action_history = {'last_action': None, 'action_list': []} self.connect(self.ui.backButton, SIGNAL("clicked()"), self.doBack) self.ui.backButton.hide() self.connect(self.ui.stopButton, SIGNAL("clicked()"), self.stopProcess) self.ui.stopButton.hide() self.connect(self.ui.searchEdit, SIGNAL("returnPressed()"), self.search) self.connect(self.ui.idEdit, SIGNAL("returnPressed()"), self.searchId) count = self.config.get('settings', 'maxresultsnumber') self.ui.countSpin.setValue(int(count)) self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.actionQuit, SIGNAL("triggered()"), self.close) self.loadBackendsList() if self.ui.backendEdit.count() == 0: self.backendsConfig() def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (ICapRecipe, ), self) if bckndcfg.run(): self.loadBackendsList() def loadBackendsList(self): self.ui.backendEdit.clear() for i, backend in enumerate(self.weboob.iter_backends()): if i == 0: self.ui.backendEdit.addItem('All backends', '') self.ui.backendEdit.addItem(backend.name, backend.name) if backend.name == self.config.get('settings', 'backend'): self.ui.backendEdit.setCurrentIndex(i + 1) if self.ui.backendEdit.count() == 0: self.ui.searchEdit.setEnabled(False) else: self.ui.searchEdit.setEnabled(True) def loadSearchHistory(self): ''' Return search string history list loaded from history file ''' result = [] history_path = os.path.join(self.weboob.workdir, 'qcookboob_history') if os.path.exists(history_path): f = codecs.open(history_path, 'r', 'utf-8') conf_hist = f.read() f.close() if conf_hist is not None and conf_hist.strip() != '': result = conf_hist.strip().split('\n') return result def saveSearchHistory(self): ''' Save search history in history file ''' if len(self.search_history) > 0: history_path = os.path.join(self.weboob.workdir, 'qcookboob_history') f = codecs.open(history_path, 'w', 'utf-8') f.write('\n'.join(self.search_history)) f.close() def updateCompletion(self): qc = QCompleter(QStringList(self.search_history), self) qc.setCaseSensitivity(Qt.CaseInsensitive) self.ui.searchEdit.setCompleter(qc) def getCount(self): num = self.ui.countSpin.value() if num == 0: return None else: return num def stopProcess(self): self.process.process.finish_event.set() def doAction(self, description, fun, args): ''' Call fun with args as arguments and save it in the action history ''' self.ui.currentActionLabel.setText(description) if self.action_history['last_action'] is not None: self.action_history['action_list'].append( self.action_history['last_action']) self.ui.backButton.setToolTip( self.action_history['last_action']['description']) self.ui.backButton.show() self.action_history['last_action'] = { 'function': fun, 'args': args, 'description': description } return fun(*args) def doBack(self): ''' Go back in action history Basically call previous function and update history ''' if len(self.action_history['action_list']) > 0: todo = self.action_history['action_list'].pop() self.ui.currentActionLabel.setText(todo['description']) self.action_history['last_action'] = todo if len(self.action_history['action_list']) == 0: self.ui.backButton.hide() else: self.ui.backButton.setToolTip( self.action_history['action_list'][-1]['description']) return todo['function'](*todo['args']) def search(self): pattern = unicode(self.ui.searchEdit.text()) # arbitrary max number of completion word if len(self.search_history) > 50: self.search_history.pop(0) if pattern not in self.search_history: self.search_history.append(pattern) self.updateCompletion() self.searchRecipe() def searchRecipe(self): pattern = unicode(self.ui.searchEdit.text()) if not pattern: return self.doAction(u'Search recipe "%s"' % pattern, self.searchRecipeAction, [pattern]) def searchRecipeAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str( self.ui.backendEdit.itemData( self.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addRecipe) self.process.do(self.app._do_complete, self.getCount(), ('title'), 'iter_recipes', pattern, backends=backend_name, caps=ICapRecipe) self.ui.stopButton.show() def addRecipe(self, backend, recipe): if not backend: self.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.ui.stopButton.hide() return minirecipe = MiniRecipe(self.weboob, backend, recipe, self) self.ui.list_content.layout().addWidget(minirecipe) self.minis.append(minirecipe) def displayRecipe(self, recipe, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget( self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wrecipe = Recipe(recipe, backend, self) self.ui.info_content.layout().addWidget(wrecipe) self.current_info_widget = wrecipe QApplication.restoreOverrideCursor() def searchId(self): QApplication.setOverrideCursor(Qt.WaitCursor) id = unicode(self.ui.idEdit.text()) if '@' in id: backend_name = id.split('@')[1] id = id.split('@')[0] else: backend_name = None for backend in self.weboob.iter_backends(): if (backend_name and backend.name == backend_name) or not backend_name: recipe = backend.get_recipe(id) if recipe: self.doAction('Details of recipe "%s"' % recipe.title, self.displayRecipe, [recipe, backend]) QApplication.restoreOverrideCursor() def closeEvent(self, ev): self.config.set( 'settings', 'backend', str( self.ui.backendEdit.itemData( self.ui.backendEdit.currentIndex()).toString())) self.saveSearchHistory() self.config.set('settings', 'maxresultsnumber', self.ui.countSpin.value()) self.config.save() ev.accept()
class EventsWidget(QWidget): def __init__(self, weboob, parent=None): QWidget.__init__(self, parent) self.ui = Ui_Events() self.ui.setupUi(self) self.weboob = weboob self.photo_processes = {} self.event_filter = None self.connect(self.ui.eventsList, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), self.eventDoubleClicked) self.connect(self.ui.typeBox, SIGNAL('currentIndexChanged(int)'), self.typeChanged) self.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.refreshEventsList) self.ui.eventsList.setItemDelegate(HTMLDelegate()) self.ui.eventsList.sortByColumn(1, Qt.DescendingOrder) def load(self): self.refreshEventsList() def typeChanged(self, i): if self.ui.refreshButton.isEnabled(): self.refreshEventsList() def refreshEventsList(self): self.ui.eventsList.clear() self.ui.refreshButton.setEnabled(False) if self.ui.typeBox.currentIndex() >= 0: # XXX strangely, in gotEvent() in the loop to check if there is already the # event type to try to introduce it in list, itemData() returns the right value. # But, I don't know why, here, it will ALWAYS return None... # So the filter does not work currently. self.events_filter = self.ui.typeBox.itemData( self.ui.typeBox.currentIndex()) else: self.event_filter = None self.ui.typeBox.setEnabled(False) self.ui.typeBox.clear() self.ui.typeBox.addItem('All', None) self.process = QtDo(self.weboob, self.gotEvent) self.process.do('iter_events') 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.itervalues(): if photo.thumbnail_data: img = QImage.fromData(photo.thumbnail_data) break if img: item.setIcon(0, QIcon(QPixmap.fromImage(img))) self.ui.eventsList.resizeColumnToContents(0) return True return False def gotEvent(self, backend, event): if not backend: self.ui.refreshButton.setEnabled(True) self.ui.typeBox.setEnabled(True) return found = False for i in xrange(self.ui.typeBox.count()): s = self.ui.typeBox.itemData(i) if s == event.type: found = True if not found: print event.type self.ui.typeBox.addItem(event.type.capitalize(), event.type) if event.type == self.event_filter: self.ui.typeBox.setCurrentIndex(self.ui.typeBox.count() - 1) if self.event_filter and self.event_filter != event.type: return contact = event.contact contact.backend = event.backend 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 name = '<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % ( 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 b, 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 = contact.photos.values()[0] process = QtDo(self.weboob, lambda b, 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) def eventDoubleClicked(self, item, col): event = item.data(0, Qt.UserRole).toPyObject() self.emit(SIGNAL('display_contact'), event.contact)
class QueryDialog(QDialog): def __init__(self, weboob, parent=None): QDialog.__init__(self, parent) self.ui = Ui_QueryDialog() self.ui.setupUi(self) self.weboob = weboob self.ui.resultsList.setItemDelegate(HTMLDelegate()) self.ui.citiesList.setItemDelegate(HTMLDelegate()) self.search_process = None self.connect(self.ui.cityEdit, SIGNAL('returnPressed()'), self.searchCity) self.connect(self.ui.resultsList, SIGNAL('itemDoubleClicked(QListWidgetItem*)'), self.insertCity) self.connect(self.ui.citiesList, SIGNAL('itemDoubleClicked(QListWidgetItem*)'), self.removeCity) self.connect(self.ui.buttonBox, SIGNAL('accepted()'), self.okButton) if hasattr(self.ui.cityEdit, "setPlaceholderText"): self.ui.cityEdit.setPlaceholderText("Press enter to search city") def keyPressEvent(self, event): """ Disable handler <Enter> and <Escape> to prevent closing the window. """ event.ignore() def selectComboValue(self, box, value): for i in xrange(box.count()): if box.itemText(i) == str(value): box.setCurrentIndex(i) break def searchCity(self): pattern = unicode(self.ui.cityEdit.text()) self.ui.resultsList.clear() self.ui.cityEdit.clear() self.ui.cityEdit.setEnabled(False) self.search_process = QtDo(self.weboob, self.addResult, fb=self.addResultEnd) self.search_process.do('search_city', pattern) def addResultEnd(self): self.search_process = None self.ui.cityEdit.setEnabled(True) def addResult(self, city): if not city: return item = self.buildCityItem(city) self.ui.resultsList.addItem(item) self.ui.resultsList.sortItems() def buildCityItem(self, city): item = QListWidgetItem() item.setText('<b>%s</b> (%s)' % (city.name, city.backend)) item.setData(Qt.UserRole, city) return item def insertCity(self, i): item = QListWidgetItem() item.setText(i.text()) item.setData(Qt.UserRole, i.data(Qt.UserRole)) self.ui.citiesList.addItem(item) def removeCity(self, item): self.ui.citiesList.removeItemWidget(item) def okButton(self): if not self.ui.nameEdit.text(): QMessageBox.critical(self, self.tr('Error'), self.tr('Please enter a name to your query.'), QMessageBox.Ok) return if self.ui.citiesList.count() == 0: QMessageBox.critical(self, self.tr('Error'), self.tr('Please add at least one city.'), QMessageBox.Ok) return self.accept()
class MainWindow(QtMainWindow): def __init__(self, config, storage, weboob, parent=None): QtMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.config = config self.storage = storage self.weboob = weboob self.process = None self.displayed_photo_idx = 0 self.process_photo = {} self.process_bookmarks = {} self.ui.jobFrame.hide() self.connect(self.ui.actionBackends, SIGNAL("triggered()"), self.backendsConfig) self.connect(self.ui.searchEdit, SIGNAL('returnPressed()'), self.doSearch) self.connect(self.ui.jobList, SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem*)'), self.jobSelected) self.connect(self.ui.searchButton, SIGNAL('clicked()'), self.doSearch) if self.weboob.count_backends() == 0: self.backendsConfig() def doSearch(self): pattern = unicode(self.ui.searchEdit.text()) self.ui.jobList.clear() self.process = QtDo(self.weboob, self.addJob) self.process.do('search_job', pattern) def addJob(self, backend, job): if not backend: self.process = None return if not job: return item = JobListWidgetItem(job) item.setAttrs(self.storage) self.ui.jobList.addItem(item) def closeEvent(self, event): QtMainWindow.closeEvent(self, event) def backendsConfig(self): bckndcfg = BackendCfg(self.weboob, (ICapJob,), self) if bckndcfg.run(): pass def jobSelected(self, item, prev): if item is not None: job = item.job self.ui.queriesFrame.setEnabled(False) self.process = QtDo(self.weboob, self.gotJob) self.process.do('fillobj', job, backends=job.backend) else: job = None self.setJob(job) if prev: prev.setAttrs(self.storage) def gotJob(self, backend, job): if not backend: self.ui.queriesFrame.setEnabled(True) self.process = None return self.setJob(job) def setJob(self, job): if job: self.ui.descriptionEdit.setText("%s" % job.description) self.ui.titleLabel.setText("<h1>%s</h1>" % job.title) self.ui.backendLabel.setText("%s" % job.backend) 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("<a href='%s'>%s</a>" % (job.url, job.url)) self.ui.jobFrame.show() else: self.ui.jobFrame.hide()
def gotEvent(self, backend, event): if not backend: self.ui.refreshButton.setEnabled(True) self.ui.typeBox.setEnabled(True) return found = False for i in xrange(self.ui.typeBox.count()): s = self.ui.typeBox.itemData(i) if s == event.type: found = True if not found: print event.type self.ui.typeBox.addItem(event.type.capitalize(), event.type) if event.type == self.event_filter: self.ui.typeBox.setCurrentIndex(self.ui.typeBox.count() - 1) if self.event_filter and self.event_filter != event.type: return contact = event.contact contact.backend = event.backend 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 name = '<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % ( 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 b, 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 = contact.photos.values()[0] process = QtDo(self.weboob, lambda b, 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)
class Result(QFrame): def __init__(self, weboob, app, parent=None): QFrame.__init__(self, parent) self.ui = Ui_Result() self.ui.setupUi(self) self.parent = parent self.weboob = weboob self.app = app self.minis = [] self.current_info_widget = None # action history is composed by the last action and the action list # An action is a function, a list of arguments and a description string self.action_history = {'last_action': None, 'action_list': []} self.connect(self.ui.backButton, SIGNAL("clicked()"), self.doBack) self.ui.backButton.hide() def doAction(self, description, fun, args): ''' Call fun with args as arguments and save it in the action history ''' self.ui.currentActionLabel.setText(description) if self.action_history['last_action'] is not None: self.action_history['action_list'].append(self.action_history['last_action']) self.ui.backButton.setToolTip(self.action_history['last_action']['description']) self.ui.backButton.show() self.action_history['last_action'] = {'function': fun, 'args': args, 'description': description} return fun(*args) def doBack(self): ''' Go back in action history Basically call previous function and update history ''' if len(self.action_history['action_list']) > 0: todo = self.action_history['action_list'].pop() self.ui.currentActionLabel.setText(todo['description']) self.action_history['last_action'] = todo if len(self.action_history['action_list']) == 0: self.ui.backButton.hide() else: self.ui.backButton.setToolTip(self.action_history['action_list'][-1]['description']) return todo['function'](*todo['args']) def castingAction(self, backend_name, id, role): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) self.process = QtDo(self.weboob, self.addPerson, fb=self.processFinished) self.process.do('iter_movie_persons', id, role, backends=backend_name, caps=CapCinema) self.parent.ui.stopButton.show() def filmographyAction(self, backend_name, id, role): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) self.process = QtDo(self.weboob, self.addMovie, fb=self.processFinished) self.process.do('iter_person_movies', id, role, backends=backend_name, caps=CapCinema) self.parent.ui.stopButton.show() def search(self, tosearch, pattern, lang): if tosearch == 'person': self.searchPerson(pattern) elif tosearch == 'movie': self.searchMovie(pattern) elif tosearch == 'torrent': self.searchTorrent(pattern) elif tosearch == 'subtitle': self.searchSubtitle(lang, pattern) def searchMovie(self, pattern): if not pattern: return self.doAction(u'Search movie "%s"' % pattern, self.searchMovieAction, [pattern]) def searchMovieAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str(self.parent.ui.backendEdit.itemData(self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addMovie, fb=self.processFinished) #self.process.do('iter_movies', pattern, backends=backend_name, caps=CapCinema) self.process.do(self.app._do_complete, self.parent.getCount(), ('original_title'), 'iter_movies', pattern, backends=backend_name, caps=CapCinema) self.parent.ui.stopButton.show() def stopProcess(self): self.process.process.finish_event.set() def addMovie(self, movie): minimovie = MiniMovie(self.weboob, self.weboob[movie.backend], movie, self) self.ui.list_content.layout().addWidget(minimovie) self.minis.append(minimovie) def displayMovie(self, movie, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget(self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wmovie = Movie(movie, backend, self) self.ui.info_content.layout().addWidget(wmovie) self.current_info_widget = wmovie QApplication.restoreOverrideCursor() def searchPerson(self, pattern): if not pattern: return self.doAction(u'Search person "%s"' % pattern, self.searchPersonAction, [pattern]) def searchPersonAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str(self.parent.ui.backendEdit.itemData(self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addPerson, fb=self.processFinished) #self.process.do('iter_persons', pattern, backends=backend_name, caps=CapCinema) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_persons', pattern, backends=backend_name, caps=CapCinema) self.parent.ui.stopButton.show() def addPerson(self, person): miniperson = MiniPerson(self.weboob, self.weboob[person.backend], person, self) self.ui.list_content.layout().addWidget(miniperson) self.minis.append(miniperson) def displayPerson(self, person, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget(self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wperson = Person(person, backend, self) self.ui.info_content.layout().addWidget(wperson) self.current_info_widget = wperson QApplication.restoreOverrideCursor() def searchTorrent(self, pattern): if not pattern: return self.doAction(u'Search torrent "%s"' % pattern, self.searchTorrentAction, [pattern]) def searchTorrentAction(self, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str(self.parent.ui.backendEdit.itemData(self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addTorrent, fb=self.processFinished) #self.process.do('iter_torrents', pattern, backends=backend_name, caps=CapTorrent) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_torrents', pattern, backends=backend_name, caps=CapTorrent) self.parent.ui.stopButton.show() def processFinished(self): self.parent.ui.searchEdit.setEnabled(True) QApplication.restoreOverrideCursor() self.process = None self.parent.ui.stopButton.hide() def addTorrent(self, torrent): minitorrent = MiniTorrent(self.weboob, self.weboob[torrent.backend], torrent, self) self.ui.list_content.layout().addWidget(minitorrent) self.minis.append(minitorrent) def displayTorrent(self, torrent, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget(self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wtorrent = Torrent(torrent, backend, self) self.ui.info_content.layout().addWidget(wtorrent) self.current_info_widget = wtorrent def searchSubtitle(self, lang, pattern): if not pattern: return self.doAction(u'Search subtitle "%s" (lang:%s)' % (pattern, lang), self.searchSubtitleAction, [lang, pattern]) def searchSubtitleAction(self, lang, pattern): self.ui.stackedWidget.setCurrentWidget(self.ui.list_page) for mini in self.minis: self.ui.list_content.layout().removeWidget(mini) mini.hide() mini.deleteLater() self.minis = [] self.parent.ui.searchEdit.setEnabled(False) QApplication.setOverrideCursor(Qt.WaitCursor) backend_name = str(self.parent.ui.backendEdit.itemData(self.parent.ui.backendEdit.currentIndex()).toString()) self.process = QtDo(self.weboob, self.addSubtitle, fb=self.processFinished) #self.process.do('iter_subtitles', lang, pattern, backends=backend_name, caps=CapSubtitle) self.process.do(self.app._do_complete, self.parent.getCount(), ('name'), 'iter_subtitles', lang, pattern, backends=backend_name, caps=CapSubtitle) self.parent.ui.stopButton.show() def addSubtitle(self, subtitle): minisubtitle = MiniSubtitle(self.weboob, self.weboob[subtitle.backend], subtitle, self) self.ui.list_content.layout().addWidget(minisubtitle) self.minis.append(minisubtitle) def displaySubtitle(self, subtitle, backend): self.ui.stackedWidget.setCurrentWidget(self.ui.info_page) if self.current_info_widget is not None: self.ui.info_content.layout().removeWidget(self.current_info_widget) self.current_info_widget.hide() self.current_info_widget.deleteLater() wsubtitle = Subtitle(subtitle, backend, self) self.ui.info_content.layout().addWidget(wsubtitle) self.current_info_widget = wsubtitle def searchId(self, id, stype): QApplication.setOverrideCursor(Qt.WaitCursor) title_field = 'name' if stype == 'movie': cap = CapCinema title_field = 'original_title' elif stype == 'person': cap = CapCinema elif stype == 'torrent': cap = CapTorrent elif stype == 'subtitle': cap = CapSubtitle if '@' in id: backend_name = id.split('@')[1] id = id.split('@')[0] else: backend_name = None for backend in self.weboob.iter_backends(): if backend.has_caps(cap) and ((backend_name and backend.name == backend_name) or not backend_name): exec('object = backend.get_%s(id)' % (stype)) if object: func_display = 'self.display' + stype[0].upper() + stype[1:] exec("self.doAction('Details of %s \"%%s\"' %% object.%s, %s, [object, backend])" % (stype, title_field, func_display)) QApplication.restoreOverrideCursor()
class SearchWidget(QWidget): def __init__(self, weboob, parent=None): QWidget.__init__(self, parent) self.ui = Ui_Search() self.ui.setupUi(self) self.weboob = weboob self.contacts = [] self.accounts = [] self.current = None self.connect(self.ui.nextButton, SIGNAL('clicked()'), self.next) self.connect(self.ui.queryButton, SIGNAL('clicked()'), self.sendQuery) def load(self): while self.ui.statusFrame.layout().count() > 0: item = self.ui.statusFrame.layout().takeAt(0) if item.widget(): item.widget().deinit() item.widget().hide() item.widget().deleteLater() self.accounts = [] for backend in self.weboob.iter_backends(): account = Account(self.weboob, backend) account.title.setText(u'<h2>%s</h2>' % 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: self.next() 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) 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])