diff src/browser/sat_browser/dialog.py @ 637:7113d40533d6 frontends_multi_profiles

merged souliane changes
author Goffi <goffi@goffi.org>
date Mon, 23 Feb 2015 18:47:27 +0100
parents ba2555c29c84
children 63697f082e8a
line wrap: on
line diff
--- 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 = "<use random name>"
 
     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)