Mercurial > libervia-backend
view frontends/src/primitivus/primitivus @ 1265:e3a9ea76de35 frontends_multi_profiles
quick_frontend, primitivus: multi-profiles refactoring part 1 (big commit, sorry :p):
This refactoring allow primitivus to manage correctly several profiles at once, with various other improvments:
- profile_manager can now plug several profiles at once, requesting password when needed. No more profile plug specific method is used anymore in backend, instead a "validated" key is used in actions
- Primitivus widget are now based on a common "PrimitivusWidget" classe which mainly manage the decoration so far
- all widgets are treated in the same way (contactList, Chat, Progress, etc), no more chat_wins specific behaviour
- widgets are created in a dedicated manager, with facilities to react on new widget creation or other events
- quick_frontend introduce a new QuickWidget class, which aims to be as generic and flexible as possible. It can manage several targets (jids or something else), and several profiles
- each widget class return a Hash according to its target. For example if given a target jid and a profile, a widget class return a hash like (target.bare, profile), the same widget will be used for all resources of the same jid
- better management of CHAT_GROUP mode for Chat widgets
- some code moved from Primitivus to QuickFrontend, the final goal is to have most non backend code in QuickFrontend, and just graphic code in subclasses
- no more (un)escapePrivate/PRIVATE_PREFIX
- contactList improved a lot: entities not in roster and special entities (private MUC conversations) are better managed
- resources can be displayed in Primitivus, and their status messages
- profiles are managed in QuickFrontend with dedicated managers
This is work in progress, other frontends are broken. Urwid SàText need to be updated. Most of features of Primitivus should work as before (or in a better way ;))
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 10 Dec 2014 19:00:09 +0100 |
parents | 82dabb442e2e |
children | faa1129559b8 |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- # Primitivus: a SAT frontend # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from sat.core.i18n import _, D_ from sat_frontends.primitivus.constants import Const as C from sat.core import log_config log_config.satConfigure(C.LOG_BACKEND_STANDARD, C) from sat.core import log as logging log = logging.getLogger(__name__) import urwid from urwid_satext import sat_widgets from urwid_satext.files_management import FileDialog from sat_frontends.quick_frontend.quick_app import QuickApp from sat_frontends.quick_frontend.quick_utils import getNewPath from sat_frontends.quick_frontend import quick_chat from sat_frontends.primitivus.profile_manager import ProfileManager from sat_frontends.primitivus.contact_list import ContactList from sat_frontends.primitivus.chat import Chat from sat_frontends.primitivus import xmlui from sat_frontends.primitivus.progress import Progress from sat_frontends.primitivus.notify import Notify from sat_frontends.primitivus.keys import action_key_map as a_key from sat_frontends.primitivus import config from sat_frontends.tools.misc import InputHistory from sat_frontends.tools import jid from os.path import join import signal class EditBar(sat_widgets.ModalEdit): """ The modal edit bar where you would enter messages and commands. """ def __init__(self, host): modes = {None: (C.MODE_NORMAL, u''), a_key['MODE_INSERTION']: (C.MODE_INSERTION, u'> '), a_key['MODE_COMMAND']: (C.MODE_COMMAND, u':')} #XXX: captions *MUST* be unicode super(EditBar, self).__init__(modes) self.host = host self.setCompletionMethod(self._text_completion) urwid.connect_signal(self, 'click', self.onTextEntered) def _text_completion(self, text, completion_data, mode): if mode == C.MODE_INSERTION: return self._nick_completion(text, completion_data) else: return text def _nick_completion(self, text, completion_data): """Completion method which complete pseudo in group chat for params, see AdvancedEdit""" contact = self.host.contact_list.getContact() ###Based on the fact that there is currently only one contact selectable at once if contact: chat = self.host.chat_wins[contact] if chat.type != "group": return text space = text.rfind(" ") start = text[space+1:] nicks = list(chat.occupants) nicks.sort() try: start_idx=nicks.index(completion_data['last_nick'])+1 if start_idx == len(nicks): start_idx = 0 except (KeyError,ValueError): start_idx = 0 for idx in range(start_idx,len(nicks)) + range(0,start_idx): if nicks[idx].lower().startswith(start.lower()): completion_data['last_nick'] = nicks[idx] return text[:space+1] + nicks[idx] + (': ' if space < 0 else '') return text def onTextEntered(self, editBar): """Called when text is entered in the main edit bar""" if self.mode == C.MODE_INSERTION: if isinstance(self.host.selected_widget, quick_chat.QuickChat): chat_widget = self.host.selected_widget self.host.sendMessage(chat_widget.target, editBar.get_edit_text(), mess_type = "groupchat" if chat_widget.type == 'group' else "chat", # TODO: put this in QuickChat errback=lambda failure: self.host.notify(_("Error while sending message ({})").format(failure)), profile_key=chat_widget.profile ) editBar.set_edit_text('') elif self.mode == C.MODE_COMMAND: self.commandHandler() def commandHandler(self): #TODO: separate class with auto documentation (with introspection) # and completion method tokens = self.get_edit_text().split(' ') command, args = tokens[0], tokens[1:] if command == 'quit': self.host.onExit() raise urwid.ExitMainLoop() elif command == 'messages': wid = sat_widgets.GenericList(logging.memoryGet()) self.host.selectWidget(wid) # elif command == 'presence': # values = [value for value in commonConst.PRESENCE.keys()] # values = [value if value else 'online' for value in values] # the empty value actually means 'online' # if args and args[0] in values: # presence = '' if args[0] == 'online' else args[0] # self.host.status_bar.onChange(user_data=sat_widgets.ClickableText(commonConst.PRESENCE[presence])) # else: # self.host.status_bar.onPresenceClick() # elif command == 'status': # if args: # self.host.status_bar.onChange(user_data=sat_widgets.AdvancedEdit(args[0])) # else: # self.host.status_bar.onStatusClick() elif command == 'history': widget = self.host.selected_widget if isinstance(widget, quick_chat.QuickChat): try: limit = int(args[0]) except (IndexError, ValueError): limit = 50 widget.clearHistory() if limit > 0: widget.historyPrint(size=limit, profile=widget.profile) elif command == 'search': widget = self.host.selected_widget if isinstance(widget, quick_chat.QuickChat): pattern = " ".join(args) if not pattern: self.host.notif_bar.addMessage(D_("Please specify the globbing pattern to search for")) widget.clearHistory() widget.printInfo(D_("Results for searching the globbing pattern: %s") % pattern, timestamp=0) widget.historyPrint(size=C.HISTORY_LIMIT_NONE, search=pattern, profile=widget.profile) widget.printInfo(D_("Type ':history <lines>' to reset the chat history")) else: return self.set_edit_text('') def _historyCb(self, text): self.set_edit_text(text) self.set_edit_pos(len(text)) def keypress(self, size, key): """Callback when a key is pressed. Send "composing" states and move the index of the temporary history stack.""" if key == a_key['MODAL_ESCAPE']: # first save the text to the current mode, then change to NORMAL self.host._updateInputHistory(self.get_edit_text(), mode=self.mode) self.host._updateInputHistory(mode=C.MODE_NORMAL) if self._mode == C.MODE_NORMAL and key in self._modes: self.host._updateInputHistory(mode=self._modes[key][0]) if key == a_key['HISTORY_PREV']: self.host._updateInputHistory(self.get_edit_text(), -1, self._historyCb, self.mode) return elif key == a_key['HISTORY_NEXT']: self.host._updateInputHistory(self.get_edit_text(), +1, self._historyCb, self.mode) return elif key == a_key['EDIT_ENTER']: self.host._updateInputHistory(self.get_edit_text(), mode=self.mode) else: if (self._mode == C.MODE_INSERTION and isinstance(self.host.selected_widget, quick_chat.QuickChat) and key not in sat_widgets.FOCUS_KEYS): self.host.bridge.chatStateComposing(self.host.selected_widget.target, self.host.selected_widget.profile) return super(EditBar, self).keypress(size, key) class PrimitivusTopWidget(sat_widgets.FocusPile): """Top most widget used in Primitivus""" _focus_inversed = True positions = ('menu', 'body', 'notif_bar', 'edit_bar') can_hide = ('menu', 'notif_bar') def __init__(self, body, menu, notif_bar, edit_bar): self._body = body self._menu = menu self._notif_bar = notif_bar self._edit_bar = edit_bar self._hidden = {'notif_bar'} self._focus_extra = False super(PrimitivusTopWidget, self).__init__([('pack', self._menu), self._body, ('pack', self._edit_bar)]) for position in self.positions: setattr(self, position, property(lambda: self, self.widgetGet(position=position), lambda pos, new_wid: self.widgetSet(new_wid, position=pos)) ) self.focus_position = len(self.contents)-1 def getVisiblePositions(self, keep=None): """Return positions that are not hidden in the right order @param keep: if not None, this position will be keep in the right order, even if it's hidden (can be useful to find its index) @return (list): list of visible positions """ return [pos for pos in self.positions if (keep and pos == keep) or pos not in self._hidden] def keypress(self, size, key): """Manage FOCUS keys that focus directly a main part (one of self.positions) To avoid key conflicts, a combinaison must be made with FOCUS_EXTRA then an other key """ if key == a_key['FOCUS_EXTRA']: self._focus_extra = True return if self._focus_extra: self._focus_extra = False if key in ('m', '1'): focus = 'menu' elif key in ('b', '2'): focus = 'body' elif key in ('n', '3'): focus = 'notif_bar' elif key in ('e', '4'): focus = 'edit_bar' else: return super(PrimitivusTopWidget, self).keypress(size, key) if focus in self._hidden: return self.focus_position = self.getVisiblePositions().index(focus) return return super(PrimitivusTopWidget, self).keypress(size, key) def widgetGet(self, position): if not position in self.positions: raise ValueError("Unknown position {}".format(position)) return getattr(self, "_{}".format(position)) def widgetSet(self, widget, position): if not position in self.positions: raise ValueError("Unknown position {}".format(position)) return setattr(self, "_{}".format(position), widget) def hideSwitch(self, position): if not position in self.can_hide: raise ValueError("Can't switch position {}".format(position)) hide = not position in self._hidden widget = self.widgetGet(position) idx = self.getVisiblePositions(position).index(position) if hide: del self.contents[idx] self._hidden.add(position) else: self.contents.insert(idx, (widget, ('pack', None))) self._hidden.remove(position) def show(self, position): if position in self._hidden: self.hideSwitch(position) def hide(self, position): if not position in self._hidden: self.hideSwitch(position) class PrimitivusApp(QuickApp, InputHistory): def __init__(self): QuickApp.__init__(self) ## main loop setup ## self.main_widget = ProfileManager(self) self.loop = urwid.MainLoop(self.main_widget, C.PALETTE, event_loop=urwid.GLibEventLoop(), input_filter=self.inputFilter, unhandled_input=self.keyHandler) ##misc setup## self.notif_bar = sat_widgets.NotificationBar() urwid.connect_signal(self.notif_bar, 'change', self.onNotification) self.progress_wid = self.widgets.getOrCreateWidget(Progress, None, on_new_widget=None) urwid.connect_signal(self.notif_bar.progress, 'click', lambda x: self.selectWidget(self.progress_wid)) self.__saved_overlay = None self.x_notify = Notify() # we already manage exit with a_key['APP_QUIT'], so we don't want C-c signal.signal(signal.SIGINT, signal.SIG_IGN) @property def mode(self): return self.editBar.mode @mode.setter def mode(self, value): self.editBar.mode = value def modeHint(self, value): """Change mode if make sens (i.e.: if there is nothing in the editBar)""" if not self.editBar.get_edit_text(): self.mode = value def debug(self): """convenient method to reset screen and launch (i)p(u)db""" log.info('Entered debug mode') try: import pudb pudb.set_trace() except ImportError: import os os.system('reset') try: import ipdb ipdb.set_trace() except ImportError: import pdb pdb.set_trace() def redraw(self): """redraw the screen""" try: self.loop.draw_screen() except AttributeError: pass def start(self): self.i = 0 self.loop.set_alarm_in(0,lambda a,b: self.postInit()) self.loop.run() def postInit(self): try: config.applyConfig(self) except Exception as e: log.error("configuration error: {}".format(e)) popup = sat_widgets.Alert(_("Configuration Error"), _("Something went wrong while reading the configuration, please check :messages"), ok_cb=self.removePopUp) if self.options.profile: self._early_popup = popup else: self.showPopUp(popup) super(PrimitivusApp, self).postInit(self.main_widget) def inputFilter(self, input_, raw): if self.__saved_overlay and input_ != a_key['OVERLAY_HIDE']: return for i in input_: if isinstance(i,tuple): if i[0] == 'mouse press': if i[1] == 4: #Mouse wheel up input_[input_.index(i)] = a_key['HISTORY_PREV'] if i[1] == 5: #Mouse wheel down input_[input_.index(i)] = a_key['HISTORY_NEXT'] return input_ def keyHandler(self, input_): if input_ == a_key['MENU_HIDE']: """User want to (un)hide the menu roller""" try: self.main_widget.hideSwitch('menu') except AttributeError: pass elif input_ == a_key['NOTIFICATION_NEXT']: """User wants to see next notification""" self.notif_bar.showNext() elif input_ == a_key['OVERLAY_HIDE']: """User wants to (un)hide overlay window""" if isinstance(self.loop.widget,urwid.Overlay): self.__saved_overlay = self.loop.widget self.loop.widget = self.main_widget else: if self.__saved_overlay: self.loop.widget = self.__saved_overlay self.__saved_overlay = None elif input_ == a_key['DEBUG'] and 'D' in self.bridge.getVersion(): #Debug only for dev versions self.debug() elif input_ == a_key['CONTACTS_HIDE']: #user wants to (un)hide the contact lists try: for wid, options in self.center_part.contents: if self.contact_lists_pile is wid: self.center_part.contents.remove((wid, options)) break else: self.center_part.contents.insert(0, (self.contact_lists_pile, ('weight', 2, False))) except AttributeError: #The main widget is not built (probably in Profile Manager) pass elif input_ == 'window resize': width,height = self.loop.screen_size if height<=5 and width<=35: if not 'save_main_widget' in dir(self): self.save_main_widget = self.loop.widget self.loop.widget = urwid.Filler(urwid.Text(_("Pleeeeasse, I can't even breathe !"))) else: if 'save_main_widget' in dir(self): self.loop.widget = self.save_main_widget del self.save_main_widget try: return self.menu_roller.checkShortcuts(input_) except AttributeError: return input_ def addMenus(self, menu, type_filter, menu_data=None): """Add cached menus to instance @param menu: sat_widgets.Menu instance @param type_filter: menu type like is sat.core.sat_main.importMenu @param menu_data: data to send with these menus """ def add_menu_cb(callback_id): self.launchAction(callback_id, menu_data, profile=self.current_profile) for id_, type_, path, path_i18n in self.bridge.getMenus("", C.NO_SECURITY_LIMIT ): if type_ != type_filter: continue if len(path) != 2: raise NotImplementedError("Menu with a path != 2 are not implemented yet") menu.addMenu(path_i18n[0], path_i18n[1], lambda dummy,id_=id_: add_menu_cb(id_)) def _buildMenuRoller(self): menu = sat_widgets.Menu(self.loop) general = _("General") menu.addMenu(general, _("Connect"), self.onConnectRequest) menu.addMenu(general, _("Disconnect"), self.onDisconnectRequest) menu.addMenu(general, _("Parameters"), self.onParam) menu.addMenu(general, _("About"), self.onAboutRequest) menu.addMenu(general, _("Exit"), self.onExitRequest, a_key['APP_QUIT']) contact = _("Contacts") menu.addMenu(contact) communication = _("Communication") menu.addMenu(communication, _("Join room"), self.onJoinRoomRequest, a_key['ROOM_JOIN']) #additionals menus #FIXME: do this in a more generic way (in quickapp) self.addMenus(menu, C.MENU_GLOBAL) menu_roller = sat_widgets.MenuRoller([(_('Main menu'), menu, C.MENU_ID_MAIN)]) return menu_roller def _buildMainWidget(self): self.contact_lists_pile = urwid.Pile([]) #self.center_part = urwid.Columns([('weight',2,self.contact_lists[profile]),('weight',8,Chat('',self))]) self.center_part = urwid.Columns([('weight', 2, self.contact_lists_pile), ('weight', 8, urwid.Filler(urwid.Text('')))]) self.editBar = EditBar(self) self.menu_roller = self._buildMenuRoller() self.main_widget = PrimitivusTopWidget(self.center_part, self.menu_roller, self.notif_bar, self.editBar) return self.main_widget def addContactList(self, profile): contact_list = ContactList(self, on_click=self.contactSelected, on_change=lambda w: self.redraw(), profile=profile) self.contact_lists_pile.contents.append((contact_list, ('weight', 1))) self.contact_lists[profile] = contact_list return contact_list def plugging_profiles(self): self.loop.widget = self._buildMainWidget() self.redraw() try: # if a popup arrived before main widget is build, we need to show it now self.showPopUp(self._early_popup) except AttributeError: pass else: del self._early_popup def removePopUp(self, widget=None): "Remove current pop-up, and if there is other in queue, show it" self.loop.widget = self.main_widget next_popup = self.notif_bar.getNextPopup() if next_popup: #we still have popup to show, we display it self.showPopUp(next_popup) def showPopUp(self, pop_up_widget, perc_width=40, perc_height=40, align='center', valign='middle'): "Show a pop-up window if possible, else put it in queue" if not isinstance(self.loop.widget, urwid.Overlay): display_widget = urwid.Overlay(pop_up_widget, self.main_widget, align, ('relative', perc_width), valign, ('relative', perc_height)) self.loop.widget = display_widget self.redraw() else: self.notif_bar.addPopUp(pop_up_widget) def notify(self, message): """"Notify message to user via notification bar""" self.notif_bar.addMessage(message) self.redraw() def newWidget(self, widget): """Display a widget if possible, else add it in the notification bar queue @param widget: BoxWidget """ self.selectWidget(widget) def selectWidget(self, widget): assert len(self.center_part.widget_list)<=2 wid_idx = len(self.center_part.widget_list)-1 self.center_part.widget_list[wid_idx] = widget try: self.menu_roller.removeMenu(C.MENU_ID_WIDGET) except KeyError: log.debug("No menu to delete") self.selected_widget = widget self.visible_widgets = set([widget]) # XXX: we can only have one widget visible at the time for now for contact_list in self.contact_lists.itervalues(): contact_list.unselectAll() for wid in self.visible_widgets: if isinstance(wid, Chat): contact_list = self.contact_lists[wid.profile] contact_list.select(wid.target) self.redraw() def removeWindow(self): """Remove window showed on the right column""" #TODO: to a better Window management than this crappy hack assert(len(self.center_part.widget_list)<=2) wid_idx = len(self.center_part.widget_list)-1 self.center_part.widget_list[wid_idx] = urwid.Filler(urwid.Text('')) self.center_part.focus_position = 0 self.redraw() def addProgress (self, id, message): """Follow a SàT progress bar @param id: SàT id of the progression @param message: message to show to identify the progression""" self.progress_wid.addProgress(id, message) def setProgress(self, percentage): """Set the progression shown in notification bar""" self.notif_bar.setProgress(percentage) def contactSelected(self, contact_list, entity): if entity.resource: # we have clicked on a private MUC conversation chat_widget = self.widgets.getOrCreateWidget(Chat, entity, on_new_widget=None, force_hash = Chat.getPrivateHash(contact_list.profile, entity), profile=contact_list.profile) else: chat_widget = self.widgets.getOrCreateWidget(Chat, entity, on_new_widget=None, profile=contact_list.profile) self.selectWidget(chat_widget) self.menu_roller.addMenu(_('Chat menu'), chat_widget.getMenu(), C.MENU_ID_WIDGET) def newMessageHandler(self, from_jid, to_jid, msg, type_, extra, profile): QuickApp.newMessageHandler(self, from_jid, to_jid, msg, type_, extra, profile) if not from_jid in self.contact_lists[profile] and from_jid.bare != self.profiles[profile].whoami.bare: #XXX: needed to show entities which haven't sent any # presence information and which are not in roster self.contact_lists[profile].setContact(from_jid) visible = False for widget in self.visible_widgets: if isinstance(widget, Chat) and widget.manageMessage(from_jid, type_): visible = True break if not visible: self.contact_lists[profile].setAlert(from_jid.bare if type_ == C.MESS_TYPE_GROUPCHAT else from_jid) def _dialogOkCb(self, widget, data): self.removePopUp() answer_cb = data[0] answer_data = [data[1]] if data[1] else [] answer_cb(True, *answer_data) def _dialogCancelCb(self, widget, data): self.removePopUp() answer_cb = data[0] answer_data = [data[1]] if data[1] else [] answer_cb(False, *answer_data) def showDialog(self, message, title="", type_="info", answer_cb = None, answer_data = None): if type_ == 'info': popup = sat_widgets.Alert(unicode(title), unicode(message), ok_cb=answer_cb or self.removePopUp) #FIXME: remove unicode here when DBus Bridge will no return dbus.String anymore elif type_ == 'error': popup = sat_widgets.Alert(unicode(title), unicode(message), ok_cb=answer_cb or self.removePopUp) #FIXME: remove unicode here when DBus Bridge will no return dbus.String anymore elif type_ == 'yes/no': popup = sat_widgets.ConfirmDialog(unicode(message), yes_cb=self._dialogOkCb, yes_value = (answer_cb, answer_data), no_cb=self._dialogCancelCb, no_value = (answer_cb, answer_data)) else: popup = sat_widgets.Alert(unicode(title), unicode(message), ok_cb=answer_cb or self.removePopUp) #FIXME: remove unicode here when DBus Bridge will no return dbus.String anymore log.error(_('unmanaged dialog type: %s'), type_) self.showPopUp(popup) def onNotification(self, notif_bar): """Called when a new notification has been received""" if not isinstance(self.main_widget, PrimitivusTopWidget): #if we are not in the main configuration, we ignore the notifications bar return if self.notif_bar.canHide(): #No notification left, we can hide the bar self.main_widget.hide('notif_bar') else: self.main_widget.show('notif_bar') def launchAction(self, callback_id, data=None, callback=None, profile=C.PROF_KEY_NONE): """ Launch a dynamic action @param callback_id: id of the action to launch @param data: data needed only for certain actions @param callback: if not None and 'validated' key is present, it will be called with the following parameters: - callback_id - data - profile @param profile: %(doc_profile)s """ if data is None: data = dict() def action_cb(data): if not data: # action was a one shot, nothing to do pass elif "xmlui" in data: ui = xmlui.create(self, xml_data=data['xmlui'], callback=callback, profile=profile) ui.show() elif 'validated' in data: pass # this key is managed below else: self.showPopUp(sat_widgets.Alert(_("Error"), _(u"Unmanaged action result"), ok_cb=self.removePopUp)) if callback and 'validated' in data: callback(callback_id, data, profile) def action_eb(failure): self.showPopUp(sat_widgets.Alert(failure.fullname, failure.message, ok_cb=self.removePopUp)) self.bridge.launchAction(callback_id, data, profile, callback=action_cb, errback=action_eb) def askConfirmationHandler(self, confirmation_id, confirmation_type, data, profile): answer_data={} def dir_selected_cb(path): dest_path = join(path, data['filename']) answer_data["dest_path"] = getNewPath(dest_path) self.addProgress(confirmation_id, dest_path) accept_cb(None) def accept_file_transfer_cb(widget): self.removePopUp() pop_up_widget = FileDialog(dir_selected_cb, refuse_cb, title=_(u"Where do you want to save the file ?"), style=['dir']) self.showPopUp(pop_up_widget) def accept_cb(widget): self.removePopUp() self.bridge.confirmationAnswer(confirmation_id, True, answer_data, profile) def refuse_cb(widget): self.removePopUp() self.bridge.confirmationAnswer(confirmation_id, False, answer_data, profile) if confirmation_type == "FILE_TRANSFER": pop_up_widget = sat_widgets.ConfirmDialog(_("The contact %(jid)s wants to send you the file %(filename)s\nDo you accept ?") % {'jid':data["from"], 'filename':data["filename"]}, no_cb=refuse_cb, yes_cb=accept_file_transfer_cb) self.showPopUp(pop_up_widget) elif confirmation_type == "YES/NO": pop_up_widget = sat_widgets.ConfirmDialog(data["message"], no_cb=refuse_cb, yes_cb=accept_cb) self.showPopUp(pop_up_widget) def actionResultHandler(self, type_, id, data, profile): # FIXME: to be removed if not id in self.current_action_ids: log.debug (_('unknown id, ignoring')) return if type_ == "SUPPRESS": self.current_action_ids.remove(id) elif type_ == "XMLUI": self.current_action_ids.remove(id) log.debug (_("XML user interface received")) misc = {} #FIXME FIXME FIXME: must clean all this crap ! title = _('Form') if data['type'] == 'registration': title = _('Registration') misc['target'] = data['target'] misc['action_back'] = self.bridge.gatewayRegister ui = xmlui.create(self, title=title, xml_data = data['xml'], misc = misc) if data['type'] == 'registration': ui.show('popup') else: ui.show('window') elif type_ == "ERROR": self.current_action_ids.remove(id) self.showPopUp(sat_widgets.Alert(_("Error"), unicode(data["message"]), ok_cb=self.removePopUp)) #FIXME: remove unicode here when DBus Bridge will no return dbus.String anymore elif type_ == "RESULT": self.current_action_ids.remove(id) if self.current_action_ids_cb.has_key(id): callback = self.current_action_ids_cb[id] del self.current_action_ids_cb[id] callback(data) elif type_ == "DICT_DICT": self.current_action_ids.remove(id) if self.current_action_ids_cb.has_key(id): callback = self.current_action_ids_cb[id] del self.current_action_ids_cb[id] callback(data) else: log.error (_("FIXME FIXME FIXME: type [%s] not implemented") % type_) raise NotImplementedError def roomJoinedHandler(self, room_jid_s, room_nicks, user_nick, profile): super(PrimitivusApp, self).roomJoinedHandler(room_jid_s, room_nicks, user_nick, profile) self.contact_lists[profile].setFocus(jid.JID(room_jid_s), True) ##DIALOGS CALLBACKS## def onJoinRoom(self, button, edit): self.removePopUp() room_jid = jid.JID(edit.get_edit_text()) if room_jid.is_valid(): self.bridge.joinMUC(room_jid, self.profiles[self.current_profile].whoami.node, {}, self.current_profile) else: message = _("'%s' is an invalid jid.JID !") % room_jid log.error (message) self.showPopUp(sat_widgets.Alert(_("Error"), message, ok_cb=self.removePopUp)) #MENU EVENTS# def onConnectRequest(self, menu): QuickApp.asyncConnect(self, self.current_profile) def onDisconnectRequest(self, menu): self.bridge.disconnect(self.current_profile) def onParam(self, menu): def success(params): ui = xmlui.create(self, xml_data=params) ui.show() def failure(error): self.showPopUp(sat_widgets.Alert(_("Error"), _("Can't get parameters (%s)") % error, ok_cb=self.removePopUp)) self.bridge.getParamsUI(app=C.APP_NAME, profile_key=self.current_profile, callback=success, errback=failure) def onExitRequest(self, menu): QuickApp.onExit(self) raise urwid.ExitMainLoop() def onJoinRoomRequest(self, menu): """User wants to join a MUC room""" pop_up_widget = sat_widgets.InputDialog(_("Entering a MUC room"), _("Please enter MUC's JID"), default_txt = 'room@muc_service.server.tld', cancel_cb=self.removePopUp, ok_cb=self.onJoinRoom) self.showPopUp(pop_up_widget) def onAboutRequest(self, menu): self.showPopUp(sat_widgets.Alert(_("About"), C.APP_NAME + " v" + self.bridge.getVersion(), ok_cb=self.removePopUp)) #MISC CALLBACKS# def setStatusOnline(self, online=True, show="", statuses={}, profile=C.PROF_KEY_NONE): if not online or not statuses: self.contact_lists[profile].status_bar.setPresenceStatus(show if online else 'unavailable', '') return try: self.contact_lists[profile].status_bar.setPresenceStatus(show, statuses['default']) except (KeyError, TypeError): pass sat = PrimitivusApp() sat.start()