changeset 33:e70521e6d803

browser side, misc stuffs - dropCell are now keep the dragover style if the mouse go on an other widget inside them - uniBox moved to panels.py - chatPanel now partially managed MUC Room - room joined open in a new tab (as Tarot games) - MainPanel & MainTabPanel are now dynamically sized in pixels - fixed stupid bug in json callbacks management
author Goffi <goffi@goffi.org>
date Sat, 14 May 2011 01:11:08 +0200
parents 6b8da70b0799
children ed935f763cc8
files browser_side/contact.py browser_side/panels.py libervia.py
diffstat 3 files changed, 339 insertions(+), 160 deletions(-) [+]
line wrap: on
line diff
--- a/browser_side/contact.py	Sat May 14 00:58:11 2011 +0200
+++ b/browser_side/contact.py	Sat May 14 01:11:08 2011 +0200
@@ -163,7 +163,7 @@
             self.connected[jid][resource] = (availability, priority, statuses)
 
     def getConnected(self):
-        """return a list of all jid  (bare jid) connected"""
+        """return a list of all jid (bare jid) connected"""
         return self.connected.keys()
 
     def isContactInGroup(self, group, contact_jid):
--- a/browser_side/panels.py	Sat May 14 00:58:11 2011 +0200
+++ b/browser_side/panels.py	Sat May 14 01:11:08 2011 +0200
@@ -21,24 +21,33 @@
 
 import pyjd # this is dummy in pyjs
 from pyjamas.ui.SimplePanel import SimplePanel
+from pyjamas.ui.FlowPanel import FlowPanel
+from pyjamas.ui.AbsolutePanel import AbsolutePanel
 from pyjamas.ui.VerticalPanel import VerticalPanel
 from pyjamas.ui.HorizontalPanel import HorizontalPanel
 from pyjamas.ui.ScrollPanel import ScrollPanel
 from pyjamas.ui.TabPanel import TabPanel
 from pyjamas.ui.HTMLPanel import HTMLPanel
+from pyjamas.ui.PopupPanel import PopupPanel
 from pyjamas.ui.Grid import Grid
+from pyjamas.ui.AutoComplete import AutoCompleteTextBox
 from pyjamas.ui.MenuBar import MenuBar
 from pyjamas.ui.MenuItem import MenuItem
 from pyjamas.ui.Label import Label
+from pyjamas.ui.HTML import HTML
 from pyjamas.ui.DropWidget import DropWidget
 from pyjamas.ui.ClickListener import ClickHandler
 from pyjamas.ui import HasAlignment
+from pyjamas.ui.KeyboardListener import KEY_ENTER
+from pyjamas.Timer import Timer
 from pyjamas import Window
 from pyjamas import DOM
+from __pyjamas__ import JS, doc
 
 from pyjamas.dnd import makeDraggable
 from pyjamas.ui.DragWidget import DragWidget, DragContainer
 from jid import JID
+from tools import html_sanitize
 from datetime import datetime
 from time import time
 from dialog import ContactsChooser
@@ -96,8 +105,13 @@
         DOM.eventPreventDefault(event)
 
     def onDragLeave(self, event):
-        print "drag leave"
-        self.removeStyleName('dragover')
+        print "\ndrag leave"
+        if event.clientX <= self.getAbsoluteLeft() or event.clientY <= self.getAbsoluteTop() or\
+           event.clientX >= self.getAbsoluteLeft() + self.getOffsetWidth()-1 or event.clientY >= self.getAbsoluteTop() + self.getOffsetHeight()-1:
+           #We check that we are inside widget's box, and we don't remove the style in this case because
+           #if the mouse is over a widget inside the DropWidget, if will leave the DropWidget, and we
+           #don't want that
+            self.removeStyleName('dragover')
 
     def onDragOver(self, event):
         DOM.eventPreventDefault(event)
@@ -150,9 +164,125 @@
         self.host = host
         _panel = HTMLPanel("&nbsp;")
         self.add(_panel)
-        self.setHeight('100%')
+        self.setHeight('50%')
         DropCell.__init__(self)
     
+class UniBoxPanel(SimplePanel):
+    """Panel containing the UniBox"""
+
+    def __init__(self, host):
+        SimplePanel.__init__(self)
+        self.setStyleName('uniBoxPanel')
+        self.unibox = UniBox(host)
+        self.unibox.setWidth('100%')
+        self.add(self.unibox)
+
+class UniBox(AutoCompleteTextBox):
+    """This text box is used as a main typing point, for message, microblog, etc"""
+
+    def __init__(self, host):
+        AutoCompleteTextBox.__init__(self)
+        self._popup = None
+        self._timer = Timer(notify=self._timeCb)
+        self.host = host
+
+    def addKey(self, key):
+        self.getCompletionItems().completions.append(key)
+
+    def showWarning(self, target_data):
+        type, target = target_data
+        if type == "PUBLIC":
+            msg = "This message will be PUBLIC and everybody will be able to see it, even people you don't know"
+            style = "targetPublic"
+        elif type == "GROUP":
+            msg = "This message will be published for all the people of the group <span class='warningTarget'>%s</span>" % (target or '')
+            style = "targetGroup"
+        elif type == "STATUS":
+            msg = "This will be your new status message"
+            style = "targetStatus"
+        elif type == "ONE2ONE":
+            msg = "This message will be sent to your contact <span class='warningTarget'>%s</span>" % target
+            style = "targetOne2One"
+        else:
+            print "WARNING: undetermined target for this message"
+            return
+        contents = HTML(msg)
+
+        self._popup = PopupPanel(autoHide=False, modal=False)
+        self._popup.target_data = target_data
+        self._popup.add(contents)
+        self._popup.setStyleName("warningPopup")
+        if style:
+            self._popup.addStyleName(style)
+
+        left = 0
+        top  = 0 #max(0, self.getAbsoluteTop() - contents.getOffsetHeight() - 2)   
+        self._popup.setPopupPosition(left, top)
+        self._popup.setPopupPosition(left, top)
+        self._popup.show()
+
+    def _timeCb(self, timer):
+        if self._popup:
+            self._popup.hide()
+            del self._popup
+            self._popup = None
+
+    def _getTarget(self, txt):
+        """Say who will receive the messsage
+        Return a tuple (target_type, target info)"""
+        type = None
+        target = None
+        if txt.startswith('@@: '):
+            type = "PUBLIC"
+        elif txt.startswith('@'):
+            type = "GROUP"
+            _end = txt.find(': ')
+            if _end == -1:
+                type = "STATUS"
+            else:
+                target = txt[1:_end] #only one target group is managed for the moment
+                if not target in self.host.contact_panel.getGroups():
+                    target = None
+        elif self.host.selected == None:
+            type = "STATUS"
+        elif isinstance(self.host.selected, ChatPanel):
+            type = "ONE2ONE"
+            target = str(self.host.selected.target)
+        else:
+            print self.host.selected
+            type = "UNKNOWN"
+        return (type, target)
+
+    def onKeyPress(self, sender, keycode, modifiers):
+        _txt = self.getText()
+        if not self._popup:
+            self.showWarning(self._getTarget(_txt))
+        else:
+            _target = self._getTarget(_txt)
+            if _target != self._popup.target_data:
+                self._timeCb(None) #we remove the popup
+                self.showWarning(_target)
+
+        self._timer.schedule(2000)
+
+        if keycode == KEY_ENTER and not self.visible:
+            if _txt:
+                if _txt.startswith('@'):
+                    self.host.bridge.call('sendMblog', None, self.getText())
+                elif self.host.selected == None:
+                    self.host.bridge.call('setStatus', None, _txt)
+                elif isinstance(self.host.selected, ChatPanel):
+                    _chat = self.host.selected
+                    mess_type = "groupchat" if _chat.type=='group' else "chat"
+                    self.host.bridge.call('sendMessage', None, str(_chat.target), _txt, '', mess_type)
+            self.setText('')
+            self._timeCb(None) #we remove the popup
+
+    def complete(self):
+        #self.visible=False #XXX: self.visible is not unset in pyjamas when ENTER is pressed and a completion is done
+        #XXX: fixed directly on pyjamas, if the patch is accepted, no need to walk around this
+        return AutoCompleteTextBox.complete(self)
+
 class MicroblogEntry(SimplePanel):
 
     def __init__(self, body, author, timestamp):
@@ -185,7 +315,7 @@
         self.vpanel = VerticalPanel()
         self.vpanel.add(HTMLPanel("<div class='%s'>%s</div>" % (','.join(_class),title)))
         self.vpanel.setWidth('100%')
-        self.setHeight('100%')
+        self.setHeight('50%')
         self.setStyleName('microblogPanel')
         self.add(self.vpanel)
         DropCell.__init__(self)
@@ -252,8 +382,34 @@
             "msg": msg}
             )
         self.setStyleName('chatText')
-    
-class ChatPanel(DropCell, ClickHandler, ScrollPanel):
+
+class Occupant(HTML):
+    """Occupant of a MUC room"""
+
+    def __init__(self, nick):
+        self.nick = nick
+        HTML.__init__(self, "<div class='occupant'>%s</div>" % html_sanitize(nick)) 
+
+class OccupantsList(AbsolutePanel):
+    """Panel user to show occupants of a room"""
+
+    def __init__(self):
+        AbsolutePanel.__init__(self)
+        self.setStyleName('occupantsList')
+        self.occupants = set()
+        #self.setHeight('100%')
+
+    def addOccupant(self, nick):
+       _occupant = Occupant(nick)
+       print "addOccupant: nick", nick
+       print _occupant
+       self.occupants.add(_occupant)
+       self.add(_occupant)
+
+
+
+
+class ChatPanel(DropCell, ClickHandler, AbsolutePanel):
 
     def __init__(self, host, target, type='one2one'):
         """Panel used for conversation (one 2 one or group chat)
@@ -261,6 +417,8 @@
         @param target: entity (JID) with who we have a conversation (contact's jid for one 2 one chat, or MUC room)
         @param type: one2one for simple conversation, group for MUC"""
         self.host = host
+        self.type = type
+        self.nick = None
         if not target:
             print "ERROR: Empty target !"
             return
@@ -268,13 +426,33 @@
         title="%s" % target.bare
         title.replace('<','&lt;').replace('>','&gt;')
         _class = ['mb_panel_header']
-        ScrollPanel.__init__(self)
-        self.content = VerticalPanel()
-        self.content.add(HTMLPanel("<div class='%s'>%s</div>" % (','.join(_class),title)))
-        self.content.setWidth('100%')
-        self.setHeight('100%')
+        AbsolutePanel.__init__(self)
+        self.header = HTMLPanel("<div class='%s'>%s</div>" % (','.join(_class),title))
+        self.body = AbsolutePanel()
+        self.body.setStyleName('chatPanel_body')
+        #self.body.setWidth('100%')
+        #self.body.setHeight('50%')
+        chat_area = HorizontalPanel()
+        chat_area.setStyleName('chatArea')
+        #chat_area.setHeight('50%')
+        if type == 'group':
+            self.occupants_list = OccupantsList()
+            chat_area.add(self.occupants_list)
+        self.body.add(chat_area)
+        self.content = AbsolutePanel()
+        self.content.setStyleName('chatContent')
+        #_scrollp.setHeight('50%')
+        #_scrollp.setWidth('100%')
+        chat_area.add(ScrollPanel(self.content, Size=("100%", "100%")))
+        self.add(self.header)
+        self.add(self.body)
+        #self.content.setWidth('100%')
+        #self.main_panel.setVerticalAlignment(HasAlignment.ALIGN_TOP)
+        #self.body.setVerticalAlignment(HasAlignment.ALIGN_TOP)
+        #chat_area.setVerticalAlignment(HasAlignment.ALIGN_TOP)
+        #self.setWidth('100%')
+        #self.setHeight('50%')
         self.setStyleName('chatPanel')
-        self.add(self.content)
         DropCell.__init__(self)
         ClickHandler.__init__(self)
         self.addClickListener(self)
@@ -285,21 +463,27 @@
     def setUserNick(self, nick):
         """Set the nick of the user, usefull for e.g. change the color of the user"""
         self.nick = nick
-    
+   
+    def setPresents(self, nicks):
+        """Set the users presents in this room
+        @param occupants: list of nicks (string)"""
+        for nick in nicks:
+            self.occupants_list.addOccupant(nick)
+
     def historyPrint(self, size=20):
         """Print the initial history"""
         def getHistoryCB(history):
             stamps=history.keys()
             stamps.sort()
-            for stamp in stamps: 
+            for stamp in stamps:
                 self.printMessage(history[stamp][0], history[stamp][1], stamp)
         self.host.bridge.call('getHistory', getHistoryCB, self.host.whoami.bare, str(self.target), 20)
     
     def printMessage(self, from_jid, msg, timestamp=None):
         """Print message in chat window. Must be implemented by child class"""
         _jid=JID(from_jid)
-        nick = _jid.node 
-        mymess = _jid.bare == self.host.whoami.bare #mymess = True if message comes from local user
+        nick = _jid.node if self.type=='one2one' else _jid.resource 
+        mymess = _jid.resource == self.nick if self.type == "group" else  _jid.bare == self.host.whoami.bare #mymess = True if message comes from local user
         """if msg.startswith('/me '):
             self.printInfo('* %s %s' % (nick, msg[4:]),type='me')
             return"""
@@ -313,12 +497,12 @@
         self._left = self.host.contact_panel
         self._right = Grid(1,3)
         self._right.setWidth('100%')
-        self._right.setHeight('100%')
+        self._right.setHeight('50%')
         self.add(self._left)
         self.setCellWidth(self._left, "15%")
         self.add(self._right)
         self.setCellWidth(self._right, "85%")
-        self.setHeight('100%')
+        self.setHeight('50%')
 
     def changePanel(self, idx, panel):
         self._right.setWidget(0,idx,panel)
@@ -326,47 +510,116 @@
 class MainTabPannel(TabPanel):
 
     def __init__(self, host):
+        TabPanel.__init__(self)
         self.host=host
-        TabPanel.__init__(self)
+        TabPanel()
         self.tabBar.setVisible(False)
+        self.addStyleName('mainTabPanel')
+        Window.addWindowResizeListener(self)
+
+    def onWindowResized(self, width, height):
+        print "onWindowResized"
+        tab_panel_elt = self.getElement()
+        _elts = doc().getElementsByClassName('gwt-TabBar')
+        if not _elts.length:
+            print ("ERROR: not TabBar found, it should exist !")
+            tab_bar_h = 0
+        else:
+            tab_bar_h = _elts.item(0).offsetHeight
+        ideal_height = Window.getClientHeight() - tab_panel_elt.offsetTop - tab_bar_h - 5
+        print "ideal_height =",ideal_height
+        self.setWidth("%s%s" % (width-5, "px"));
+        self.setHeight("%s%s" % (ideal_height, "px"));
 
     def add(self, widget, tabText=None, asHTML=False):
         TabPanel.add(self, widget, tabText, asHTML)
         if self.getWidgetCount()>1:
             self.tabBar.setVisible(True)
+            self.host.resize()
         
-class MainPanel(VerticalPanel):
+"""class MainTabPannel(FlowPanel):
+
+    def __init__(self, host):
+        FlowPanel.__init__(self)
+        self.host=host
+        self.tab_panel = TabPanel()
+        self.tab_panel.tabBar.setVisible(False)
+        self.addStyleName('mainTabPanel')
+        FlowPanel.add(self, self.tab_panel)
+        self.tab_panel.setWidth('100%')
+        self.tab_panel.setHeight('100%')
+        Window.addWindowResizeListener(self)
+
+    def onWindowResized(self, width, height):
+        print "onWindowResized"
+        tab_panel_elt = self.getElement()
+        _elts = doc().getElementsByClassName('gwt-TabBar')
+        if not _elts.length:
+            print ("ERROR: not TabBar found, it should exist !")
+            tab_bar_h = 0
+        else:
+            tab_bar_h = _elts.item(0).offsetHeight
+        ideal_height = Window.getClientHeight() - tab_panel_elt.offsetTop - tab_bar_h - 5
+        print "ideal_height =",ideal_height
+        self.setWidth("%s%s" % (width-5, "px"));
+        self.setHeight("%s%s" % (ideal_height, "px"));
+
+    def selectTab(self, idx):
+        self.tab_panel.selectTab(idx)
+
+    def add(self, widget, tabText=None, asHTML=False):
+        self.tab_panel.add(widget, tabText, asHTML)
+        if self.tab_panel.getWidgetCount()>1:
+            self.tab_panel.tabBar.setVisible(True)
+            self.host.resize()"""
+
+class MainPanel(AbsolutePanel):
 
     def __init__(self, host):
         self.host=host
-        VerticalPanel.__init__(self)
+        AbsolutePanel.__init__(self)
 
-        self.setHorizontalAlignment(HasAlignment.ALIGN_LEFT)
-        self.setVerticalAlignment(HasAlignment.ALIGN_TOP)
+        #self.setHorizontalAlignment(HasAlignment.ALIGN_LEFT)
+        #self.setVerticalAlignment(HasAlignment.ALIGN_TOP)
 
         menu = Menu(host)
-        uni_box = host.uni_box
+        unibox_panel = UniBoxPanel(host)
+        self.host.setUniBox(unibox_panel.unibox)
         status = host.status_panel
-        self.tab_panel = MainTabPannel(self)
-        self.tab_panel.setWidth('100%')
-        self.tab_panel.setHeight('100%')
+        self.tab_panel = MainTabPannel(host)
+        #self.tab_panel.setWidth('100%')
+        #self.tab_panel.setHeight('50%')
         self.discuss_panel = MainDiscussionPannel(self.host)
         self.discuss_panel.setWidth('100%')
-        self.discuss_panel.setHeight('100%')
+        self.discuss_panel.setHeight('50%')
         self.tab_panel.add(self.discuss_panel, "Discussions")
         self.tab_panel.selectTab(0)
 
         self.add(menu)
-        self.add(uni_box)
+        self.add(unibox_panel)
         self.add(status)
         self.add(self.tab_panel)
+        #self.tab_panel.onWindowResized(Window.getClientWidth(), Window.getClientHeight())
         
-        self.setCellHeight(menu, "5%")
+        """self.setCellHeight(menu, "5%")
         self.setCellHeight(uni_box, "5%")
         self.setCellVerticalAlignment(uni_box, HasAlignment.ALIGN_CENTER)
         self.setCellHorizontalAlignment(uni_box, HasAlignment.ALIGN_CENTER)
         self.setCellHeight(self.tab_panel, "90%")
-        self.setCellWidth(self.tab_panel, "100%")
+        self.setCellWidth(self.tab_panel, "100%")"""
 
         self.setWidth("100%")
-        self.setHeight("100%")
+        #self.setHeight("99%")
+        Window.addWindowResizeListener(self)
+
+    def onWindowResized(self, width, height):
+        print "resizing: %s %s" % (width, height)
+        #self.setWidth("%s%s" % (width, "px"));
+        _elts = doc().getElementsByClassName('gwt-TabBar')
+        if not _elts.length:
+            tab_bar_h = 0
+        else:
+            tab_bar_h = _elts.item(0).offsetHeight
+        ideal_height = Window.getClientHeight() - tab_bar_h
+        self.setHeight("%s%s" % (ideal_height, "px"));
+
--- a/libervia.py	Sat May 14 00:58:11 2011 +0200
+++ b/libervia.py	Sat May 14 01:11:08 2011 +0200
@@ -20,15 +20,10 @@
 """
 
 import pyjd # this is dummy in pyjs
-from pyjamas.ui.SimplePanel import SimplePanel
 from pyjamas.ui.RootPanel import RootPanel
-from pyjamas.ui.AutoComplete import AutoCompleteTextBox
-from pyjamas.ui.PopupPanel import PopupPanel
 from pyjamas.ui.HTML import HTML
-from pyjamas.Timer import Timer
 from pyjamas import Window
 from pyjamas.JSONService import JSONProxy
-from pyjamas.ui.KeyboardListener import KEY_ENTER
 from browser_side.register import RegisterPanel, RegisterBox
 from browser_side.contact import ContactPanel
 from browser_side.panels import MainPanel, EmptyPanel, MicroblogPanel, ChatPanel, StatusPanel
@@ -42,14 +37,14 @@
         self.cb={}
 
     def call(self, method, cb, *args):
+        id = self.callMethod(method,args)
         if cb:
-            self.cb[method] = cb
-        self.callMethod(method,args)
+            self.cb[id] = cb
 
     def onRemoteResponse(self, response, request_info):
-        if self.cb.has_key(request_info.method):
-            self.cb[request_info.method](response)
-            del self.cb[request_info.method]
+        if self.cb.has_key(request_info.id):
+            self.cb[request_info.id](response)
+            del self.cb[request_info.id]
         
     def onRemoteError(self, code, errobj, request_info):
         if code != 0:
@@ -70,142 +65,47 @@
 class BridgeCall(LiberviaJsonProxy):
     def __init__(self):
         LiberviaJsonProxy.__init__(self, "/json_api",
-                        ["getContacts", "sendMessage", "sendMblog", "getMblogNodes", "getProfileJid", "getHistory", "getPresenceStatus", "launchTarotGame"])
+                        ["getContacts", "sendMessage", "sendMblog", "getMblogNodes", "getProfileJid", "getHistory",
+                         "getPresenceStatus", "getRoomJoined", "launchTarotGame"])
 
 class BridgeSignals(LiberviaJsonProxy):
     def __init__(self):
         LiberviaJsonProxy.__init__(self, "/json_signal_api",
                         ["getSignals"])
 
-
-class UniBox(AutoCompleteTextBox):
-    """This text box is used as a main typing point, for message, microblog, etc"""
-
-    def __init__(self, host):
-        AutoCompleteTextBox.__init__(self)
-        self._popup = None
-        self._timer = Timer(notify=self._timeCb)
-        self.host = host
-
-    def addKey(self, key):
-        self.getCompletionItems().completions.append(key)
-
-    def showWarning(self, target_data):
-        type, target = target_data
-        if type == "PUBLIC":
-            msg = "This message will be PUBLIC and everybody will be able to see it, even people you don't know"
-            style = "targetPublic"
-        elif type == "GROUP":
-            msg = "This message will be published for all the people of the group <span class='warningTarget'>%s</span>" % (target or '')
-            style = "targetGroup"
-        elif type == "STATUS":
-            msg = "This will be your new status message"
-            style = "targetStatus"
-        elif type == "ONE2ONE":
-            msg = "This message will be sent to your contact <span class='warningTarget'>%s</span>" % target
-            style = "targetOne2One"
-        else:
-            print "WARNING: undetermined target for this message"
-            return
-        contents = HTML(msg)
-
-        self._popup = PopupPanel(autoHide=False, modal=False)
-        self._popup.target_data = target_data
-        self._popup.add(contents)
-        self._popup.setStyleName("warningPopup")
-        if style:
-            self._popup.addStyleName(style)
-
-        left = 0
-        top  = 0 #max(0, self.getAbsoluteTop() - contents.getOffsetHeight() - 2)   
-        self._popup.setPopupPosition(left, top)
-        self._popup.setPopupPosition(left, top)
-        self._popup.show()
-
-    def _timeCb(self, timer):
-        if self._popup:
-            self._popup.hide()
-            del self._popup
-            self._popup = None
-
-    def _getTarget(self, txt):
-        """Say who will receive the messsage
-        Return a tuple (target_type, target info)"""
-        type = None
-        target = None
-        if txt.startswith('@@: '):
-            type = "PUBLIC"
-        elif txt.startswith('@'):
-            type = "GROUP"
-            _end = txt.find(': ')
-            if _end == -1:
-                type = "STATUS"
-            else:
-                target = txt[1:_end] #only one target group is managed for the moment
-                if not target in self.host.contact_panel.getGroups():
-                    target = None
-        elif self.host.selected == None:
-            type = "STATUS"
-        elif isinstance(self.host.selected, ChatPanel):
-            type = "ONE2ONE"
-            target = str(self.host.selected.target)
-        else:
-            print self.host.selected
-            type = "UNKNOWN"
-        return (type, target)
-
-    def onKeyPress(self, sender, keycode, modifiers):
-        _txt = self.getText()
-        if not self._popup:
-            self.showWarning(self._getTarget(_txt))
-        else:
-            _target = self._getTarget(_txt)
-            if _target != self._popup.target_data:
-                self._timeCb(None) #we remove the popup
-                self.showWarning(_target)
-
-        self._timer.schedule(2000)
-
-        if keycode == KEY_ENTER and not self.visible:
-            if _txt:
-                if _txt.startswith('@'):
-                    self.host.bridge.call('sendMblog', None, self.getText())
-                elif self.host.selected == None:
-                    self.host.bridge.call('setStatus', None, _txt)
-                elif isinstance(self.host.selected, ChatPanel):
-                    _chat = self.host.selected
-                    self.host.bridge.call('sendMessage', None, str(_chat.target), _txt, '', 'chat')
-            self.setText('')
-            self._timeCb(None) #we remove the popup
-
-    def complete(self):
-        #self.visible=False #XXX: self.visible is not unset in pyjamas when ENTER is pressed and a completion is done
-        #XXX: fixed directly on pyjamas, if the patch is accepted, no need to walk around this
-        return AutoCompleteTextBox.complete(self)
-
-
 class SatWebFrontend:
     def onModuleLoad(self):
         self.whoami = None
         self.bridge = BridgeCall()
         self.bridge_signals = BridgeSignals()
         self.selected = None
-        self.uni_box = UniBox(self)
-        self.uni_box.addKey("@@: ")
+        self.uni_box = None
         self.status_panel = StatusPanel(self)
         self.contact_panel = ContactPanel(self)
         self.panel = MainPanel(self)
         self.discuss_panel = self.panel.discuss_panel
         self.tab_panel = self.panel.tab_panel 
         self.mpanels = [EmptyPanel(self), MicroblogPanel(self, accept_all=True), EmptyPanel(self)]
+        self.other_panels = [] #panels not on the main tab #FIXME: temporary, need to be changed
+        self.room_list = set() #set of rooms 
         self.discuss_panel.changePanel(0,self.mpanels[0])
         self.discuss_panel.changePanel(1,self.mpanels[1])
         self.discuss_panel.changePanel(2,self.mpanels[2])
         self._dialog = None
         RootPanel().add(self.panel)
+        self.resize()
         self._register = RegisterCall()
         self._register.call('isRegistered',self._isRegisteredCB)
 
+    def resize(self):
+        """Resize elements"""
+        Window.onResize()
+
+    def setUniBox(self, unibox):
+        """register the unibox widget"""
+        self.uni_box = unibox
+        self.uni_box.addKey("@@: ")
+
     def select(self, widget):
         """Define the selected widget"""
         if self.selected:
@@ -214,6 +114,13 @@
         if widget:
             self.selected.addStyleName('selected_widget')
 
+    def addTab(self, panel, label):
+        """Add a panel in a tab
+        @param panel: panel to add
+        @param label: label of the tab"""
+        self.tab_panel.add(panel, label)
+        self.other_panels.append(panel)
+
     def _isRegisteredCB(self, registered):
         if not registered:
             self._dialog = RegisterBox(self.logged,centered=True)
@@ -256,11 +163,17 @@
             self._presenceUpdateCb(*args)
         elif name == 'roomJoined':
             self._roomJoinedCb(*args)
+        elif name == 'roomUserJoined':
+            self._roomUserJoinedCb(*args)
+        elif name == 'roomUserLeft':
+            self._roomUserLeftCb(*args)
 
     def _getProfileJidCB(self, jid):
         self.whoami = JID(jid)
         #we can now ask our status
         self.bridge.call('getPresenceStatus', self._getPresenceStatusCB)
+        #and the rooms where we are
+        self.bridge.call('getRoomJoined', self._getRoomJoinedCB)
 
 
 
@@ -285,7 +198,7 @@
     def _newMessageCb(self, from_jid, msg, msg_type, to_jid):
         _from = JID(from_jid)
         _to = JID(to_jid)
-        for panel in self.mpanels:
+        for panel in self.mpanels + self.other_panels:
             if isinstance(panel,ChatPanel) and (panel.target.bare == _from.bare or panel.target.bare == _to.bare):
                 panel.printMessage(_from, msg)
 
@@ -294,17 +207,26 @@
         #XXX: QnD way to get our status
         if self.whoami and self.whoami.bare == _entity.bare and statuses:
             self.status_panel.changeStatus(statuses.values()[0])
-        if not self.whoami or self.whoami.bare != _entity.bare: 
+        if (not self.whoami or self.whoami.bare != _entity.bare):
             self.contact_panel.setConnected(_entity.bare, _entity.resource, show, priority, statuses)
 
-    def _roomJoinedCb(self, room_id, room_service, room_nicks, user_nick, profile):
-        print "roomJoined"
-        print room_id
+    def _roomJoinedCb(self, room_id, room_service, room_nicks, user_nick):
         _target = JID("%s@%s" % (room_id,room_service))
+        self.room_list.add(_target)
+        chat_panel = ChatPanel(self, _target, type='group')
+        chat_panel.setUserNick(user_nick)
         if room_id.startswith('sat_tarot_'): #XXX: it's not really beautiful, but it works :)
-            self.tab_panel.add(ChatPanel(self, _target), "Tarot")
+            self.addTab(chat_panel, "Tarot")
         else:
-            self.tab_panel.add(ChatPanel(self, _target), str(_target)) 
+            self.addTab(chat_panel, str(_target))
+        chat_panel.setPresents(room_nicks)
+        chat_panel.historyPrint()
+
+    def _roomUserJoinedCb(room_id, room_service, room_nicks, user_nick):
+        pass
+
+    def _roomUserLeftCb(room_id, room_service, room_nicks, user_nick):
+        pass
 
             
     def _getPresenceStatusCB(self, presence_data):
@@ -313,6 +235,10 @@
                 args = presence_data[entity][resource]
                 self._presenceUpdateCb("%s/%s" % (entity, resource), *args)
 
+    def _getRoomJoinedCB(self, room_data):
+        for room in room_data:
+            self._roomJoinedCb(*room)
+
 if __name__ == '__main__':
     pyjd.setup("http://localhost:8080/libervia.html")
     app = SatWebFrontend()