changeset 268:79970bf6af93

browser_side: added class RoomAndContactsChooser: - unified UI for all the MUC menu items callbacks to join a room, invite people and start a game
author souliane <souliane@mailoo.org>
date Sun, 17 Nov 2013 17:57:14 +0100
parents a76243c02074
children 9eb9c7d41bdc
files browser_side/dialog.py browser_side/menu.py libervia.tac public/libervia.css
diffstat 4 files changed, 201 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/browser_side/dialog.py	Sun Nov 17 17:53:37 2013 +0100
+++ b/browser_side/dialog.py	Sun Nov 17 17:57:14 2013 +0100
@@ -20,6 +20,7 @@
 """
 
 from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas.ui.Grid import Grid
 from pyjamas.ui.HorizontalPanel import HorizontalPanel
 from pyjamas.ui.PopupPanel import PopupPanel
 from pyjamas.ui.DialogBox import DialogBox
@@ -28,30 +29,79 @@
 from pyjamas.ui.TextBox import TextBox
 from pyjamas.ui.Label import Label
 from pyjamas.ui.HTML import HTML
-from pyjamas.ui.Frame import Frame
+from pyjamas.ui.RadioButton import RadioButton
 from pyjamas.ui import HasAlignment
 from pyjamas.ui.KeyboardListener import KEY_ESCAPE, KEY_ENTER
 from pyjamas.ui.MouseListener import MouseWheelHandler
-from pyjamas import DOM
 from pyjamas import Window
+from browser_side import panels
+from sat.tools.frontends.misc import DEFAULT_MUC
 
 # List here the patterns that are not allowed in contact group names
 FORBIDDEN_PATTERNS_IN_GROUP = ()
 
 
-class ContactsChooser(DialogBox):
+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):
+        Grid.__init__(self, 2, 2, Width='100%')
+        self.host = host
+
+        self.exist_radio = RadioButton("room", "Select discussion room:")
+        self.rooms_list = ListBox(Width='100%')
+        self.setRooms()
+        self.add(self.exist_radio, 0, 0)
+        self.add(self.rooms_list, 0, 1)
+
+        self.new_radio = RadioButton("room", "New discussion room:")
+        self.new_radio.setChecked(True)
+        self.box = TextBox(Width='100%')
+        self.box.setText(self.GENERATE_MUC if default_room == "" else default_room)
+        self.add(self.new_radio, 1, 0)
+        self.add(self.box, 1, 1)
+
+        self.rooms_list.addFocusListener(self)
+        self.box.addFocusListener(self)
 
-    def __init__(self, host, callback, nb_contact=None, text='Please select contacts'):
+    def onFocus(self, sender):
+        if sender == self.rooms_list:
+            self.exist_radio.setChecked(True)
+        elif sender == self.box:
+            if self.box.getText() == self.GENERATE_MUC:
+                self.box.setText("")
+            self.new_radio.setChecked(True)
+
+    def onLostFocus(self, sender):
+        if sender == self.box:
+            if self.box.getText() == "":
+                self.box.setText(self.GENERATE_MUC)
+
+    def setRooms(self, room_data):
+        for room in self.host.room_list:
+            self.rooms_list.addItem(room.bare)
+
+    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"""
+
+    def __init__(self, host, nb_contact=None, ok_button=None):
         """
-        ContactsChooser allow to select one or several connected contacts
         @param host: SatWebFrontend instance
-        @param callback: method to call when contacts have been choosed
         @param nb_contact: number of contacts that have to be selected, None for no limit
         If a tuple is given instead of an integer, nb_contact[0] is the minimal and
         nb_contact[1] is the maximal number of contacts to be chosen.
         """
         self.host = host
-        self.callback = callback
         if isinstance(nb_contact, tuple):
             if len(nb_contact) == 0:
                 nb_contact = None
@@ -64,48 +114,108 @@
         else:
             print "Need to select between %d and %d contacts" % nb_contact
         self.nb_contact = nb_contact
-        DialogBox.__init__(self, centered=True)
-        content = VerticalPanel()
-        content.setWidth('100%')
+        self.ok_button = ok_button
+        VerticalPanel.__init__(self, Width='100%')
         self.contacts_list = ListBox()
-        self.contacts_list.setVisibleItemCount(10)
         self.contacts_list.setMultipleSelect(True)
-        self.contacts_list.setWidth("100%")
-        self.contacts_list.setStyleName('contactsChooser')
+        self.contacts_list.setWidth("95%")
+        self.contacts_list.addStyleName('contactsChooser')
         self.contacts_list.addChangeListener(self.onChange)
-        content.add(self.contacts_list)
+        self.add(self.contacts_list)
+        self.setContacts()
+        self.onChange()
+
+    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]:
+                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
+        """
+        self.contacts_list.clear()
+        contacts = self.host.contact_panel.getConnected()
+        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)
+
+
+class RoomAndContactsChooser(DialogBox):
+    """Select a room and some users to invite in"""
+
+    def __init__(self, host, callback, nb_contact=None, ok_button="OK", title="Group discussions",
+                 title_room="Join room", title_invite="Invite contacts", visible=(True, True)):
+        DialogBox.__init__(self, centered=True)
+        self.host = host
+        self.callback = callback
+        self.title_room = title_room
+        self.title_invite = title_invite
+
         button_panel = HorizontalPanel()
         button_panel.addStyleName("marginAuto")
-        self.choose_button = Button("Choose", self.onChoose)
-        if nb_contact and nb_contact[0] > 0:
-            self.choose_button.setEnabled(False)
-        button_panel.add(self.choose_button)
+        ok_button = Button("OK", self.onOK)
+        button_panel.add(ok_button)
         button_panel.add(Button("Cancel", self.onCancel))
-        content.add(button_panel)
-        self.setHTML(text)
-        self.setWidget(content)
+
+        self.room_panel = RoomChooser(host, "" if visible == (False, True) else DEFAULT_MUC)
+        self.contact_panel = ContactsChooser(host, nb_contact, ok_button)
 
-    def onChange(self, sender):
-        if self.nb_contact:
-            selected = len(self.contacts_list.getSelectedValues())
-            if  selected >= self.nb_contact[0] and selected <= self.nb_contact[1]:
-                self.choose_button.setEnabled(True)
-            else:
-                self.choose_button.setEnabled(False)
+        self.stack_panel = panels.ToggleStackPanel(Width="100%")
+        self.stack_panel.add(self.room_panel, title_room, visible=visible[0])
+        self.stack_panel.add(self.contact_panel, title_invite, visible=visible[1])
+        self.stack_panel.addStackChangeListener(self)
+        main_panel = VerticalPanel()
+        main_panel.setStyleName("room-contact-chooser")
+        main_panel.add(self.stack_panel)
+        main_panel.add(button_panel)
 
-    def getContacts(self):
-        """
-        Actually ask to choose the contacts
-        """
-        self.contacts_list.clear()
-        for contact in self.host.contact_panel.getConnected():
-            if contact not in [room.bare for room in self.host.room_list]:
-                self.contacts_list.addItem(contact)
+        self.setWidget(main_panel)
+        self.setHTML(title)
         self.show()
 
-    def onChoose(self, sender):
+    def getRoom(self, asSuffix=False):
+        room = self.room_panel.getRoom()
+        if asSuffix:
+            return room if room == "" else ": %s" % room
+        else:
+            return room
+
+    def getContacts(self, asSuffix=False):
+        contacts = self.contact_panel.getContacts()
+        if asSuffix:
+            return "" if contacts == [] else ": %s" % ", ".join(contacts)
+        else:
+            return 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)))
+        elif index == 1:
+            sender.setStackText(1, self.title_invite + ("" if visible else self.getContacts(True)))
+            if visible:
+                # update the contacts list in case someone recently logged in/out
+                self.contact_panel.setContacts(self.getContacts())
+
+    def onOK(self, sender):
+        room_jid = self.getRoom()
+        if room_jid != "" and "@" not in room_jid:
+            Window.alert('You must enter a room jid in the form room@chat.%s' % self.host._defaultDomain)
         self.hide()
-        self.callback(self.contacts_list.getSelectedValues())
+        self.callback(room_jid, self.getContacts())
 
     def onCancel(self, sender):
         self.hide()
--- a/browser_side/menu.py	Sun Nov 17 17:53:37 2013 +0100
+++ b/browser_side/menu.py	Sun Nov 17 17:57:14 2013 +0100
@@ -227,7 +227,7 @@
             else:
                 self.host.bridge.call('addContact', None, edit.getText(), '', _dialog.getSelectedGroups() )
 
-        label = Label("new contact identifier (JID):")
+        label = Label("New contact identifier (JID):")
         edit.setText('@%s' % self.host._defaultDomain)
         edit.setWidth('100%')
         _dialog = dialog.GroupSelector([label, edit], self.host.contact_panel.getGroups(), [],
@@ -291,52 +291,32 @@
 
     #Group menu
     def onJoinRoom(self):
-        _dialog = None
-        _edit = None
 
-        def onOK(sender):
-            if not _edit.getText():
-                Window.alert('You must enter a room jid in the form room@chat.%s' % self.host._defaultDomain)
+        def invite(room_jid, contacts):
+            for contact in contacts:
+                self.host.bridge.call('inviteMUC', None, contact, room_jid)
+
+        def join(room_jid, contacts):
             if self.host.whoami:
                 nick = self.host.whoami.node
-                self.host.bridge.call('joinMUC', None, _edit.getText(), nick)
-            _dialog.hide()
-
-        def onCancel(sender):
-            _dialog.hide()
+                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)
+                else:
+                    self.host.getOrCreateLiberviaWidget(panels.ChatPanel, (room_jid, "group"), True, JID(room_jid).bare)
+                    invite(room_jid, contacts)
 
-        _main_panel = VerticalPanel()
-        _label = Label("Discussion room:")
-        _edit = TextBox()
-        _edit.setText('sat@chat.jabberfr.org')
-        hpanel = HorizontalPanel()
-        hpanel.add(_label)
-        hpanel.add(_edit)
-        _main_panel.add(hpanel)
-        button_panel = HorizontalPanel()
-        button_panel.addStyleName("marginAuto")
-        button_panel.add(Button("Join", onOK))
-        button_panel.add(Button("Cancel", onCancel))
-        _main_panel.add(button_panel)
-        _dialog = DialogBox(centered=True)
-        _dialog.setHTML('Group discussions')
-        _dialog.setWidget(_main_panel)
-        _dialog.show()
+        dialog.RoomAndContactsChooser(self.host, join, ok_button="Join", visible=(True, False))
 
     def onCollectiveRadio(self):
-        def onContactsSelected(contacts):
-            print("let's go :)")
-            self.host.bridge.call('launchRadioCollective', None, contacts)
-        dialog.ContactsChooser(self.host, onContactsSelected, None, text="Please select contacts to invite").getContacts() 
+        def callback(room_jid, contacts):
+            self.host.bridge.call('launchRadioCollective', None, contacts, room_jid)
+        dialog.RoomAndContactsChooser(self.host, callback, ok_button="Choose", visible=(False, True))
 
     #Game menu
-
     def onTarotGame(self):
-        #Window.alert("Tarot selected")
-        #self.host.tab_panel.add(EmptyPanel(self.host), "Tarot")
-        def onPlayersSelected(other_players):
-            self.host.bridge.call('launchTarotGame', None, other_players)
-        dialog.ContactsChooser(self.host, onPlayersSelected, 3, text="Please select 3 other players").getContacts()
+        def onPlayersSelected(room_jid, other_players):
+            self.host.bridge.call('launchTarotGame', None, other_players, room_jid)
+        dialog.RoomAndContactsChooser(self.host, onPlayersSelected, 3, title_invite="Please select 3 other players", visible=(False, True))
 
     def onXiangqiGame(self):
         Window.alert("A Xiangqi game is planed, but not available yet")
--- a/libervia.tac	Sun Nov 17 17:53:37 2013 +0100
+++ b/libervia.tac	Sun Nov 17 17:57:14 2013 +0100
@@ -358,10 +358,18 @@
         profile = ISATSession(self.session).profile
         return self.sat_host.bridge.getRoomsJoined(profile)
 
-    def jsonrpc_launchTarotGame(self, other_players):
-        """Create a room, invite the other players and start a Tarot game"""
+    def jsonrpc_launchTarotGame(self, other_players, room_jid=""):
+        """Create a room, invite the other players and start a Tarot game
+        @param room_jid: leave empty string to generate a unique room name
+        """
         profile = ISATSession(self.session).profile
-        self.sat_host.bridge.tarotGameLaunch(other_players, profile)
+        try:
+            if room_jid != "":
+                room_jid = JID(room_jid).userhost()
+        except:
+            warning('Invalid room jid')
+            return
+        self.sat_host.bridge.tarotGameLaunch(other_players, room_jid, profile)
 
     def jsonrpc_getTarotCardsPaths(self):
         """Give the path of all the tarot cards"""
@@ -384,10 +392,18 @@
         profile = ISATSession(self.session).profile
         self.sat_host.bridge.tarotGamePlayCards(player_nick, referee, cards, profile)
 
-    def jsonrpc_launchRadioCollective(self, invited):
-        """Create a room, invite people, and start a radio collective"""
+    def jsonrpc_launchRadioCollective(self, invited, room_jid=""):
+        """Create a room, invite people, and start a radio collective
+        @param room_jid: leave empty string to generate a unique room name
+        """
         profile = ISATSession(self.session).profile
-        self.sat_host.bridge.radiocolLaunch(invited, profile)
+        try:
+            if room_jid != "":
+                room_jid = JID(room_jid).userhost()
+        except:
+            warning('Invalid room jid')
+            return
+        self.sat_host.bridge.radiocolLaunch(invited, room_jid, profile)
 
     def jsonrpc_getEntityData(self, jid, keys):
         """Get cached data for an entit
--- a/public/libervia.css	Sun Nov 17 17:53:37 2013 +0100
+++ b/public/libervia.css	Sun Nov 17 17:57:14 2013 +0100
@@ -367,6 +367,7 @@
 
 .contactsChooser {
     text-align: center;
+    margin:auto;
 }
 
 .infoDialogBody {
@@ -1297,6 +1298,13 @@
 .contactGroupButtonCell {
 	vertical-align: baseline;
 	width: 55px;
+}
+
+/* Room and contacts chooser */
+
+.room-contact-chooser {
+	width:380px;
+}
 
 /* StackPanel */
 
@@ -1345,4 +1353,9 @@
     text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);    
     cursor: pointer;
 }
+
+/* Radio buttons */
+
+.gwt-RadioButton {
+	white-space: nowrap;
 }
\ No newline at end of file