# HG changeset patch # User Goffi # Date 1424713647 -3600 # Node ID 7113d40533d65eb377bb9abfccdfa55c0c1aef9a # Parent 86ae737da6f362915eb89381f6c8c1e5931abf1d# Parent 66a547539185e9c991c96e7e96c861e2aa9d02c2 merged souliane changes diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/libervia_main.py --- a/src/browser/libervia_main.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/libervia_main.py Mon Feb 23 18:47:27 2015 +0100 @@ -60,7 +60,9 @@ except ImportError: pass -unicode = lambda s: str(s) + +unicode = str # FIXME: pyjamas workaround + MAX_MBLOG_CACHE = 500 # Max microblog entries kept in memories @@ -80,7 +82,6 @@ self.uni_box = None # FIXME: to be removed self.status_panel = HTML('
') self.panel = panels.MainPanel(self) - self.discuss_panel = self.panel.discuss_panel self.tab_panel = self.panel.tab_panel self.tab_panel.addTabListener(self) self._register_box = None @@ -213,7 +214,8 @@ @return: the URL to the avatar (str) """ assert isinstance(jid_, jid.JID) - avatar_hash = self.contact_lists[C.PROF_KEY_NONE].getCache(jid_, 'avatar') + contact_list = self.contact_list # pyjamas issue: need a temporary variable to call a property's method + avatar_hash = contact_list.getCache(jid_, 'avatar') if avatar_hash is None: # we have no value for avatar_hash, so we request the vcard self.bridge.getCard(unicode(jid_), profile=C.PROF_KEY_NONE) @@ -239,25 +241,6 @@ lib_wid.refresh() self.resize() - def addTab(self, label, wid=None, select=False): - """Create a new tab and eventually add a widget to it. - - @param label (unicode): label of the tab - @param wid (LiberviaWidget): optional widget to add - @param select (bool): True to select the added tab - @return: WidgetsPanel - """ - widgets_panel = base_widget.WidgetsPanel(self) - self.tab_panel.add(widgets_panel, label) - tab_index = self.tab_panel.getWidgetCount() - 1 - if wid is not None: - self.addWidget(wid, tab_index) - if select: - self.tab_panel.selectTab(tab_index) - if wid is not None: - self.setSelected(wid) - return widgets_panel - def addWidget(self, wid, tab_index=None): """ Add a widget at the bottom of the current or specified tab @@ -376,7 +359,6 @@ def addContactList(self, dummy): contact_list = ContactList(self) - self.contact_lists[C.PROF_KEY_NONE] = contact_list self.panel.addContactList(contact_list) return contact_list @@ -611,7 +593,8 @@ kwargs['on_new_widget'] = None kwargs['on_existing_widget'] = C.WIDGET_RECREATE wid = self.widgets.getOrCreateWidget(class_, target, *args, **kwargs) - self.addTab(new_tab, wid) + self.tab_panel.addWidgetsTab(new_tab) + self.addWidget(wid) return wid kwargs['on_existing_widget'] = C.WIDGET_RAISE @@ -844,7 +827,8 @@ msg = HTML('The contact %s want to add you in his/her contact list, do you accept ?' % html_tools.html_sanitize(entity)) def ok_cb(ignore): - self.bridge.call('subscription', None, "subscribed", entity, '', _dialog.getSelectedGroups()) + self.bridge.call('subscription', None, "subscribed", entity) + self.bridge.updateContact(entity, '', _dialog.getSelectedGroups()) def cancel_cb(ignore): self.bridge.call('subscription', None, "unsubscribed", entity, '', '') @@ -970,6 +954,20 @@ self.warning_popup = panels.WarningPopup() self.warning_popup.showWarning(type_, msg) + def showDialog(self, message, title="", type_="info", answer_cb=None, answer_data=None): + if type_ == 'info': + popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) + elif type_ == 'error': + popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) + elif type_ == 'yes/no': + popup = dialog.ConfirmDialog(lambda answer: answer_cb(answer, answer_data), + text=unicode(message), title=unicode(title)) + popup.cancel_button.setText(_("No")) + else: + popup = dialog.InfoDialog(unicode(title), unicode(message), callback=answer_cb) + log.error(_('unmanaged dialog type: %s'), type_) + popup.show() + if __name__ == '__main__': app = SatWebFrontend() diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/base_widget.py --- a/src/browser/sat_browser/base_widget.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/base_widget.py Mon Feb 23 18:47:27 2015 +0100 @@ -21,7 +21,9 @@ from sat.core.log import getLogger log = getLogger(__name__) from sat.core import exceptions +from sat.core.i18n import _ from sat_frontends.quick_frontend import quick_widgets + from pyjamas.ui.SimplePanel import SimplePanel from pyjamas.ui.AbsolutePanel import AbsolutePanel from pyjamas.ui.VerticalPanel import VerticalPanel @@ -586,10 +588,17 @@ class WidgetsPanel(ScrollPanelWrapper): def __init__(self, host, locked=False): + """ + + @param host (SatWebFrontend): host instance + @param locked (bool): If True, the tab containing self will not be + removed when there are no more widget inside self. If False, the + tab will be removed with self's last widget. + """ ScrollPanelWrapper.__init__(self) self.setSize('100%', '100%') self.host = host - self.locked = locked # if True: tab will not be removed when there are no more widgets inside + self.locked = locked self.selected = None self.flextable = FlexTable() self.flextable.setSize('100%', '100%') @@ -760,18 +769,18 @@ def onDragEnter(self, event): #if self == LiberviaDragWidget.current: # return - self.addStyleName('dragover') + self.parent.addStyleName('dragover') DOM.eventPreventDefault(event) def onDragLeave(self, event): - self.removeStyleName('dragover') + self.parent.removeStyleName('dragover') def onDragOver(self, event): DOM.eventPreventDefault(event) def onDrop(self, event): DOM.eventPreventDefault(event) - self.removeStyleName('dragover') + self.parent.removeStyleName('dragover') if self._getIndex() == self.tab_panel.tabBar.getSelectedTab(): # the widget come from the DragTab, so nothing to do, we let it there return @@ -806,16 +815,32 @@ widgets_panel.addWidget(_new_panel) -class MainTabPanel(TabPanel): +class MainTabPanel(TabPanel, ClickHandler): def __init__(self, host): TabPanel.__init__(self) + ClickHandler.__init__(self) self.host = host - self.tabBar.setVisible(False) self.setStyleName('liberviaTabPanel') self.addStyleName('mainTabPanel') Window.addWindowResizeListener(self) + self.tabBar.addTab(u'✚', True) + + def onTabSelected(self, sender, tabIndex): + if tabIndex < self.getWidgetCount(): + TabPanel.onTabSelected(self, sender, tabIndex) + return + # user clicked the "+" tab + default_label = _(u'new tab') + try: + label = Window.prompt(_(u'Name of the new tab'), default_label) + if not label: + label = default_label + except: # this happens when the user prevents the page to open the prompt dialog + label = default_label + self.addWidgetsTab(label, select=True) + def getCurrentPanel(self): """ Get the panel of the currently selected tab @@ -836,20 +861,34 @@ self.setWidth("%s%s" % (ideal_width, "px")) self.setHeight("%s%s" % (ideal_height, "px")) - def add(self, widget, text=''): - tab = DropTab(self, text) - TabPanel.add(self, widget, tab, False) - if self.getWidgetCount() > 1: - self.tabBar.setVisible(True) - self.host.resize() + def addTab(self, widget, label, select=False): + """Create a new tab for the given widget. + + @param widget (Widget): widget to associate to the tab + @param label (unicode): label of the tab + @param select (bool): True to select the added tab + """ + TabPanel.add(self, widget, DropTab(self, label), False) + if select: + self.selectTab(self.getWidgetCount() - 1) + + def addWidgetsTab(self, label, select=False, locked=False): + """Create a new tab for containing LiberviaWidgets. + + @param label (unicode): label of the tab + @param select (bool): True to select the added tab + @param locked (bool): If True, the tab will not be removed when there + are no more widget inside. If False, the tab will be removed with + the last widget. + @return: WidgetsPanel + """ + widgets_panel = WidgetsPanel(self, locked=locked) + self.addTab(widgets_panel, label, select) + return widgets_panel def onWidgetPanelRemove(self, panel): """ Called when a child WidgetsPanel is empty and need to be removed """ + widget_index = self.getWidgetIndex(panel) self.remove(panel) widgets_count = self.getWidgetCount() - if widgets_count == 1: - self.tabBar.setVisible(False) - self.host.resize() - self.selectTab(0) - else: - self.selectTab(widgets_count - 1) + self.selectTab(widget_index if widget_index < widgets_count else widgets_count - 1) diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/blog.py --- a/src/browser/sat_browser/blog.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/blog.py Mon Feb 23 18:47:27 2015 +0100 @@ -166,7 +166,7 @@ is_publisher = self.author == self._blog_panel.host.whoami.bare if is_publisher: self.update_label = addIcon(u"✍", "Edit this message") - if is_publisher or str(self.node).endswith(self._blog_panel.host.whoami.bare): + if is_publisher or str(self.node).endswith(unicode(self._blog_panel.host.whoami.bare)): self.delete_label = addIcon(u"✗", "Delete this message") def updateAvatar(self, new_avatar): @@ -374,7 +374,10 @@ self.vpanel = VerticalPanel() self.vpanel.setStyleName('microblogPanel') self.setWidget(self.vpanel) - host.addListerner('avatar', self.onAvatarUpdate) + + # FIXME: workaround for a pyjamas issue: calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword) + self.avatarListener = self.onAvatarUpdate + host.addListener('avatar', self.avatarListener, [C.PROF_KEY_NONE]) def __str__(self): return u"Blog Widget [target: {}, profile: {}]".format(self.target, self.profile) @@ -385,17 +388,16 @@ def onDelete(self): quick_widgets.QuickWidget.onDelete(self) - self.host.removeListener('avatar', self.onAvatarUpdate) + self.host.removeListener('avatar', self.avatarListener) - def onAvatarUpdate(self, jid_, hash_, profile): + def onAvatarUpdate(self, jid_, hash_): """Called on avatar update events @param jid_: jid of the entity with updated avatar @param hash_: hash of the avatar - @param profile: should be C.PROF_KEY_NONE """ - whoami = self.host.profiles[self.profile].whoami.bare - if self.isJidAccepted(jid_) or jid_.bare == whoami.bare: + whoami = self.host.profiles[self.profile].whoami + if self.isJidAccepted(jid_) or jid_.bare == whoami.bare: self.updateValue('avatar', jid_, hash_) def refresh(self): @@ -567,7 +569,7 @@ assert isinstance(sender, jid.JID) # FIXME temporary if (mblog_entry.type == "comment" or self.isJidAccepted(sender) - or (groups == None and sender == self.host.profiles[self.profile].whoami.bare) + or (groups is None and sender == self.host.profiles[self.profile].whoami.bare) or (groups and groups.intersection(self.accepted_groups))): self.addEntry(mblog_entry) @@ -580,7 +582,7 @@ _entry = MicroblogEntry(self, data) if _entry.type == "comment": comments_hash = (_entry.service, _entry.node) - if not comments_hash in self.comments: + if comments_hash not in self.comments: # The comments node is not known in this panel return None parent = self.comments[comments_hash] diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/chat.py --- a/src/browser/sat_browser/chat.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/chat.py Mon Feb 23 18:47:27 2015 +0100 @@ -49,6 +49,9 @@ import plugin_xep_0085 +unicode = str # FIXME: pyjamas workaround + + class ChatText(HTMLPanel): def __init__(self, nick, mymess, msg, extra): @@ -88,7 +91,7 @@ host.plugins['otr'].infoTextCallback(target, cb) header_info = header_info_cb if (type_ == C.CHAT_ONE2ONE and 'otr' in host.plugins) else None - base_widget.LiberviaWidget.__init__(self, host, title=target.bare, info=header_info, selectable=True) + base_widget.LiberviaWidget.__init__(self, host, title=unicode(target.bare), info=header_info, selectable=True) self._body = AbsolutePanel() self._body.setStyleName('chatPanel_body') chat_area = HorizontalPanel() @@ -206,7 +209,7 @@ def onQuit(self): base_widget.LiberviaWidget.onQuit(self) if self.type == C.CHAT_GROUP: - self.host.bridge.call('mucLeave', None, self.target.bare) + self.host.bridge.call('mucLeave', None, unicode(self.target.bare)) def setUserNick(self, nick): """Set the nick of the user, usefull for e.g. change the color of the user""" @@ -338,10 +341,10 @@ def refreshTitle(self): """Refresh the title of this Chat dialog""" + title = unicode(self.target.bare) if self._state: - self.setTitle(self.target.bare + " (" + self._state + ")") - else: - self.setTitle(self.target.bare) + title += " (%s)".format(self._state) + self.setTitle(title) def setConnected(self, jid_s, resource, availability, priority, statuses): """Set connection status diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/contact_list.py --- a/src/browser/sat_browser/contact_list.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/contact_list.py Mon Feb 23 18:47:27 2015 +0100 @@ -358,7 +358,10 @@ self.add(self.scroll_panel) self.setStyleName('contactList') Window.addWindowResizeListener(self) - host.addListerner('avatar', self.onAvatarUpdate) + + # FIXME: workaround for a pyjamas issue: calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword) + self.avatarListener = self.onAvatarUpdate + host.addListener('avatar', self.avatarListener, [C.PROF_KEY_NONE]) @property def profile(self): @@ -366,7 +369,7 @@ def onDelete(self): QuickContactList.onDelete(self) - self.host.removeListener('avatar', self.onAvatarUpdate) + self.host.removeListener('avatar', self.avatarListener) def update(self): ### GROUPS ### @@ -477,10 +480,6 @@ # # case 2: update (or confirm) with the values of the resource which takes precedence # self._contacts_panel.setState(jid_s, "availability", availability) - # # update the connected contacts chooser live - # if hasattr(self.host, "room_contacts_chooser") and self.host.room_contacts_chooser is not None: - # self.host.room_contacts_chooser.resetContacts() - # self.updateVisibility([jid_s], self.getContactGroups(jid_s)) def setContactMessageWaiting(self, jid, waiting): @@ -563,12 +562,11 @@ """ self._contacts_panel.updateAvatar(jid_s, url) - def onAvatarUpdate(self, jid_, hash_, profile): + def onAvatarUpdate(self, jid_, hash_): """Called on avatar update events @param jid_: jid of the entity with updated avatar @param hash_: hash of the avatar - @param profile: should be C.PROF_KEY_NONE """ self._contacts_panel.updateAvatar(jid_, self.host.getAvatarURL(jid_)) diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/dialog.py --- a/src/browser/sat_browser/dialog.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/dialog.py Mon Feb 23 18:47:27 2015 +0100 @@ -19,7 +19,10 @@ from sat.core.log import getLogger log = getLogger(__name__) + +from constants import Const as C from sat_frontends.tools.misc import DEFAULT_MUC +from sat_frontends.tools import jid from pyjamas.ui.VerticalPanel import VerticalPanel from pyjamas.ui.Grid import Grid @@ -44,12 +47,19 @@ FORBIDDEN_PATTERNS_IN_GROUP = () +unicode = str # XXX: pyjama doesn't manage unicode + + class RoomChooser(Grid): """Select a room from the rooms you already joined, or create a new one""" GENERATE_MUC = "" def __init__(self, host, default_room=DEFAULT_MUC): + """ + + @param host (SatWebFrontend) + """ Grid.__init__(self, 2, 2, Width='100%') self.host = host @@ -70,7 +80,19 @@ self.exist_radio.setVisible(False) self.rooms_list.setVisible(False) - self.setRooms() + self.refreshOptions() + + @property + def room(self): + """Get the room that has been selected or entered by the user + + @return: jid.JID or None + """ + if self.exist_radio.getChecked(): + values = self.rooms_list.getSelectedValues() + return jid.JID(values[0]) if values else None + value = self.box.getText() + return None if value == self.GENERATE_MUC else jid.JID(value) def onFocus(self, sender): if sender == self.rooms_list: @@ -85,21 +107,17 @@ if self.box.getText() == "": self.box.setText(self.GENERATE_MUC) - def setRooms(self): - for room in self.host.room_list: + def refreshOptions(self): + """Refresh the already joined room list""" + contact_list = self.host.contact_list + muc_rooms = contact_list.getSpecials(C.CONTACT_SPECIAL_GROUP) + for room in muc_rooms: self.rooms_list.addItem(room.bare) - if len(self.host.room_list) > 0: + if len(muc_rooms) > 0: self.exist_radio.setVisible(True) self.rooms_list.setVisible(True) self.exist_radio.setChecked(True) - def getRoom(self): - if self.exist_radio.getChecked(): - values = self.rooms_list.getSelectedValues() - return "" if values == [] else values[0] - value = self.box.getText() - return "" if value == self.GENERATE_MUC else value - class ContactsChooser(VerticalPanel): """Select one or several connected contacts""" @@ -132,34 +150,41 @@ self.contacts_list.addStyleName('contactsChooser') self.contacts_list.addChangeListener(self.onChange) self.add(self.contacts_list) - self.setContacts() + self.refreshOptions() self.onChange() + @property + def contacts(self): + """Return the selected contacts. + + @return: list[jid.JID] + """ + return [jid.JID(contact) for contact in self.contacts_list.getSelectedValues(True)] + def onChange(self, sender=None): if self.ok_button is None: return if self.nb_contact: selected = len(self.contacts_list.getSelectedValues(True)) - if selected >= self.nb_contact[0] and selected <= self.nb_contact[1]: + if selected >= self.nb_contact[0] and selected <= self.nb_contact[1]: self.ok_button.setEnabled(True) else: self.ok_button.setEnabled(False) - def setContacts(self, selected=[]): - """Fill the list with the connected contacts - @param select: list of the contacts to select by default + def refreshOptions(self, keep_selected=False): + """Fill the list with the connected contacts. + + @param keep_selected (boolean): if True, keep the current selection """ + selection = self.contacts if keep_selected else [] self.contacts_list.clear() - contacts = self.host.contact_panel.getConnected(filter_muc=True) + contacts = self.host.contact_list.roster_entities_connected self.contacts_list.setVisibleItemCount(10 if len(contacts) > 5 else 5) self.contacts_list.addItem("") for contact in contacts: - if contact not in [room.bare for room in self.host.room_list]: - self.contacts_list.addItem(contact) - self.contacts_list.setItemTextSelection(selected) - - def getContacts(self): - return self.contacts_list.getSelectedValues(True) + self.contacts_list.addItem(contact) + if selection: + self.contacts_list.setItemTextSelection([unicode(contact) for contact in selection]) class RoomAndContactsChooser(DialogBox): @@ -198,60 +223,72 @@ self.setHTML(title) self.show() - # needed to update the contacts list when someone logged in/out - self.host.room_contacts_chooser = self + # FIXME: workaround for a pyjamas issue: calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword) + self.presenceListener = self.refreshContactList + # update the contacts list when someone logged in/out + self.host.addListener('presence', self.presenceListener, [C.PROF_KEY_NONE]) + + @property + def room(self): + """Get the room that has been selected or entered by the user - def getRoom(self, asSuffix=False): - room = self.room_panel.getRoom() - if asSuffix: - return room if room == "" else ": %s" % room - else: - return room + @return: jid.JID or None + """ + return self.room_panel.room - def getContacts(self, asSuffix=False): - contacts = self.contact_panel.getContacts() - if asSuffix: - return "" if contacts == [] else ": %s" % ", ".join(contacts) - else: - return contacts + @property + def contacts(self): + """Return the selected contacts. + + @return: list[jid.JID] + """ + return self.contact_panel.contacts def onStackChanged(self, sender, index, visible=None): if visible is None: visible = sender.getWidget(index).getVisible() if index == 0: - sender.setStackText(0, self.title_room + ("" if visible else self.getRoom(True))) + suffix = "" if (visible or not self.room) else ": %s" % self.room + sender.setStackText(0, self.title_room + suffix) elif index == 1: - sender.setStackText(1, self.title_invite + ("" if visible else self.getContacts(True))) + suffix = "" if (visible or not self.contacts) else ": %s" % ", ".join([unicode(contact) for contact in self.contacts]) + sender.setStackText(1, self.title_invite + suffix) - def resetContacts(self): - """Called when someone log in/out to update the list""" - self.contact_panel.setContacts(self.getContacts()) + def refreshContactList(self, *args): + """Called when someone log in/out to update the list. + + @param args: set by the event call but not used here + """ + self.contact_panel.refreshOptions(keep_selected=True) def onOK(self, sender): - room_jid = self.getRoom() - if room_jid != "" and "@" not in room_jid: + room = self.room # pyjamas issue: you need to use an intermediate variable to access a property's method + if room and not room.is_valid(): Window.alert('You must enter a room jid in the form room@chat.%s' % self.host._defaultDomain) return self.hide() - self.callback(room_jid, self.getContacts()) + self.callback(room, self.contacts) def onCancel(self, sender): self.hide() def hide(self): - self.host.room_contacts_chooser = None + self.host.removeListener('presence', self.presenceListener) DialogBox.hide(self, autoClosed=True) class GenericConfirmDialog(DialogBox): - def __init__(self, widgets, callback, title='Confirmation', prompt=None, **kwargs): + def __init__(self, widgets, callback, title='Confirmation', prompt_widgets=None, **kwargs): """ Dialog to confirm an action @param widgets (list[Widget]): widgets to attach - @param callback: method to call when a button is clicked + @param callback (callable): method to call when a button is pressed, + with the following arguments: + - result (bool): set to True if the dialog has been confirmed + - *args: a list of unicode (the values for the prompt_widgets) @param title: title of the dialog - @param prompt (TextBox, list[TextBox]): input widgets from which to retrieve + @param prompt_widgets (list[TextBox]): input widgets from which to retrieve the string value(s) to be passed to the callback when OK button is pressed. If None, OK button will return "True". Cancel button always returns "False". """ @@ -261,16 +298,14 @@ if added_style: self.addStyleName(added_style) - if prompt is None: - prompt = [] - elif isinstance(prompt, TextBox): - prompt = [prompt] + if prompt_widgets is None: + prompt_widgets = [] content = VerticalPanel() content.setWidth('100%') for wid in widgets: content.add(wid) - if wid in prompt: + if wid in prompt_widgets: wid.setWidth('100%') button_panel = HorizontalPanel() button_panel.addStyleName("marginAuto") @@ -281,11 +316,12 @@ content.add(button_panel) self.setHTML(title) self.setWidget(content) - self.prompt = prompt + self.prompt_widgets = prompt_widgets def onConfirm(self, sender): self.hide() - result = [box.getText() for box in self.prompt] if self.prompt else [True] + result = [True] + result.extend([box.getText() for box in self.prompt_widgets]) self.callback(*result) def onCancel(self, sender): @@ -294,8 +330,8 @@ def show(self): DialogBox.show(self) - if self.prompt: - self.prompt[0].setFocus(True) + if self.prompt_widgets: + self.prompt_widgets[0].setFocus(True) class ConfirmDialog(GenericConfirmDialog): @@ -328,7 +364,7 @@ _body.add(main_widget) _body.setCellWidth(main_widget, '100%') _body.setCellHeight(main_widget, '100%') - if not 'NO_CLOSE' in options: + if 'NO_CLOSE' not in options: _close_button = Button("Close", self.onClose) _body.add(_close_button) _body.setCellHorizontalAlignment(_close_button, HasAlignment.ALIGN_CENTER) @@ -357,19 +393,18 @@ def __init__(self, callback, textes=None, values=None, title='User input', **kwargs): """Prompt the user for one or more input(s). - @param callback (callable): method to call when clicking OK - @param textes (str, list[str]): HTML textes to display before the inputs - @param values (str, list[str]): default values for each input - @param title (str): dialog title + @param callback (callable): method to call when a button is pressed, + with the following arguments: + - result (bool): set to True if the dialog has been confirmed + - *args: a list of unicode (the values entered by the user) + @param textes (list[unicode]): HTML textes to display before the inputs + @param values (list[unicode]): default values for each input + @param title (unicode): dialog title """ if textes is None: textes = [''] # display a single input without any description - elif not isinstance(textes, list): - textes = [textes] # allow to pass a single string instead of a list if values is None: values = [] - elif not isinstance(values, list): - values = [values] # allow to pass a single string instead of a list all_widgets = [] prompt_widgets = [] for count in xrange(len(textes)): @@ -388,7 +423,7 @@ def onEventPreview(self, event): if event.type in ["keydown", "keypress", "keyup"] and event.keyCode == KEY_ESCAPE: - #needed to prevent request cancellation in Firefox + # needed to prevent request cancellation in Firefox event.preventDefault() return PopupPanel.onEventPreview(self, event) diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/menu.py --- a/src/browser/sat_browser/menu.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/menu.py Mon Feb 23 18:47:27 2015 +0100 @@ -23,8 +23,6 @@ from sat.core.i18n import _ -from sat_frontends.tools import jid - from pyjamas.ui.SimplePanel import SimplePanel from pyjamas.ui.HTML import HTML from pyjamas.ui.Frame import Frame @@ -41,6 +39,9 @@ from base_menu import MenuCmd +unicode = str # FIXME: pyjamas workaround + + class MainMenuBar(base_menu.GenericMenuBar): """The main menu bar which is displayed on top of the document""" @@ -149,28 +150,31 @@ def invite(room_jid, contacts): for contact in contacts: - self.host.bridge.call('inviteMUC', None, contact, room_jid) + self.host.bridge.call('inviteMUC', None, unicode(contact), unicode(room_jid)) def join(room_jid, contacts): if self.host.whoami: nick = self.host.whoami.node - if room_jid not in [room.bare for room in self.host.room_list]: - self.host.bridge.call('joinMUC', lambda room_jid: invite(room_jid, contacts), room_jid, nick) + contact_list = self.host.contact_list + if room_jid not in contact_list.getSpecials(C.CONTACT_SPECIAL_GROUP): + self.host.bridge.call('joinMUC', lambda room_jid: invite(room_jid, contacts), unicode(room_jid), nick) else: - self.host.displayWidget(chat.Chat, room_jid, type_="group", new_tab=jid.JID(room_jid).bare) + self.host.displayWidget(chat.Chat, room_jid, type_="group", new_tab=room_jid) invite(room_jid, contacts) dialog.RoomAndContactsChooser(self.host, join, ok_button="Join", visible=(True, False)) def onCollectiveRadio(self): def callback(room_jid, contacts): - self.host.bridge.call('launchRadioCollective', None, contacts, room_jid) + contacts = [unicode(contact) for contact in contacts] + self.host.bridge.call('launchRadioCollective', None, contacts, unicode(room_jid)) dialog.RoomAndContactsChooser(self.host, callback, ok_button="Choose", title="Collective Radio", visible=(False, True)) #Game menu def onTarotGame(self): def onPlayersSelected(room_jid, other_players): - self.host.bridge.call('launchTarotGame', None, other_players, room_jid) + other_players = [unicode(contact) for contact in other_players] + self.host.bridge.call('launchTarotGame', None, other_players, unicode(room_jid)) dialog.RoomAndContactsChooser(self.host, onPlayersSelected, 3, title="Tarot", title_invite="Please select 3 other players", visible=(False, True)) def onXiangqiGame(self): diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/panels.py --- a/src/browser/sat_browser/panels.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/panels.py Mon Feb 23 18:47:27 2015 +0100 @@ -21,6 +21,7 @@ from sat.core.log import getLogger log = getLogger(__name__) +from sat.core.i18n import _ from sat_frontends.tools.strings import addURLToText from pyjamas.ui.AbsolutePanel import AbsolutePanel @@ -509,9 +510,7 @@ # tabs self.tab_panel = base_widget.MainTabPanel(host) - self.discuss_panel = base_widget.WidgetsPanel(self.host, locked=True) - self.tab_panel.add(self.discuss_panel, "Discussions") - self.tab_panel.selectTab(0) + self.tab_panel.addWidgetsTab(_(u"Discussions"), select=True, locked=True) self.header = AbsolutePanel() self.header.add(self.menu) diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/plugin_sec_otr.py --- a/src/browser/sat_browser/plugin_sec_otr.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/plugin_sec_otr.py Mon Feb 23 18:47:27 2015 +0100 @@ -264,20 +264,20 @@ title = (AUTH_OTHER_TITLE if act == "asked" else AUTH_US_TITLE).format(jid=self.peer) if type_ == 'question': if act == 'asked': - def cb(question, answer=None): - if question is False or not answer: # dialog cancelled or the answer is empty + def cb(result, question, answer=None): + if not result or not answer: # dialog cancelled or the answer is empty return self.smpAuthSecret(answer, question) text = (AUTH_INFO_TXT + "" + AUTH_QUEST_DEFINE_TXT + "" + AUTH_QUEST_DEFINE).format(eol=DIALOG_EOL) dialog.PromptDialog(cb, [text, AUTH_SECRET_INPUT.format(eol=DIALOG_EOL)], title=title, AddStyleName="maxWidthLimit").show() else: - def cb(answer): - if not answer: # dialog cancelled or the answer is empty + def cb(result, answer): + if not result or not answer: # dialog cancelled or the answer is empty self.smpAuthAbort('answered') return self.smpAuthSecret(answer) text = (AUTH_INFO_TXT + "" + AUTH_QUEST_ANSWER_TXT + "" + AUTH_QUEST_ANSWER).format(eol=DIALOG_EOL, question=data) - dialog.PromptDialog(cb, text + AUTH_SECRET_INPUT.format(eol=DIALOG_EOL), title=title, AddStyleName="maxWidthLimit").show() + dialog.PromptDialog(cb, [text + AUTH_SECRET_INPUT.format(eol=DIALOG_EOL)], title=title, AddStyleName="maxWidthLimit").show() elif type_ == 'trust': self.setCurrentTrust('smp' if data else '', act) elif type_ == 'abort': @@ -344,7 +344,7 @@ log.debug(u"getContextForUser [%s]" % other_jid) if not other_jid.resource: log.error("getContextForUser called with a bare jid") - running_sessions = [jid_.bareJID() for jid_ in self.contexts.keys() if self.contexts[jid_].state == otr.context.STATE_ENCRYPTED] + running_sessions = [jid_.bare for jid_ in self.contexts.keys() if self.contexts[jid_].state == otr.context.STATE_ENCRYPTED] if start or (other_jid in running_sessions): users_ml = DIALOG_USERS_ML.format(subject=D_("OTR issue in Libervia: getContextForUser called with a bare jid in an encrypted context")) text = RESOURCE_ISSUE.format(eol=DIALOG_EOL, jid=other_jid, users_ml=users_ml) @@ -485,7 +485,7 @@ return False # interrupt the main process def presenceReceivedTrigger(self, entity, show, priority, statuses): - if show == "unavailable": + if show == C.PRESENCE_UNAVAILABLE: self.endSession(entity, finish=True) return True @@ -542,7 +542,8 @@ try: other_jid = menu_data['jid'] - if other_jid.bare not in self.host.contact_panel.connected: + contact_list = self.host.contact_list + if contact_list.getCache(other_jid.bare, C.PRESENCE_SHOW) is None: dialog.InfoDialog(ACTION_NA_TITLE, ACTION_NA, AddStyleName="maxWidthLimit").show() return self.fixResource(other_jid, cb) diff -r 86ae737da6f3 -r 7113d40533d6 src/browser/sat_browser/richtext.py --- a/src/browser/sat_browser/richtext.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/browser/sat_browser/richtext.py Mon Feb 23 18:47:27 2015 +0100 @@ -442,7 +442,7 @@ setText() return True if recipients is None: - recipients = self.recipient.getContacts() + recipients = self.recipient.getItemsByKey() target = "" # we could eventually allow more in the future allowed = 1 @@ -487,7 +487,7 @@ def __sendMessage(self): """Send the message.""" - recipients = self.recipient.getContacts() + recipients = self.recipient.getItemsByKey() targets = [] for addr in recipients: for recipient in recipients[addr]: @@ -518,7 +518,7 @@ list_ = [] list_.append("@@") list_.extend("@%s" % group for group in parent.host.contact_panel.getGroups()) - list_.extend(contact for contact in parent.host.contact_panel.getContacts()) + list_.extend(contact for contact in parent.host.contact_list.roster_entities) list_manager.ListManager.__init__(self, parent, composition.RECIPIENT_TYPES, list_, {'y': y_offset}) self.registerPopupMenuPanel(entries=composition.RECIPIENT_TYPES, diff -r 86ae737da6f3 -r 7113d40533d6 src/common/constants.py --- a/src/common/constants.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/common/constants.py Mon Feb 23 18:47:27 2015 +0100 @@ -18,7 +18,7 @@ # along with this program. If not, see . from sat.core.i18n import D_ -from sat_frontends import constants +from sat_frontends.quick_frontend import constants import os.path diff -r 86ae737da6f3 -r 7113d40533d6 src/server/server.py --- a/src/server/server.py Mon Feb 23 18:44:58 2015 +0100 +++ b/src/server/server.py Mon Feb 23 18:47:27 2015 +0100 @@ -212,13 +212,11 @@ profile = ISATSession(self.session).profile self.sat_host.bridge.updateContact(entity, name, groups, profile) - def jsonrpc_subscription(self, sub_type, entity, name, groups): + def jsonrpc_subscription(self, sub_type, entity): """Confirm (or infirm) subscription, and setup user roster in case of subscription""" profile = ISATSession(self.session).profile self.sat_host.bridge.subscription(sub_type, entity, profile) - if sub_type == 'subscribed': - self.sat_host.bridge.updateContact(entity, name, groups, profile) def jsonrpc_getWaitingSub(self): """Return list of room already joined by user"""