Mercurial > libervia-web
diff browser_side/panels.py @ 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 | d89982865c57 |
children | ed935f763cc8 |
line wrap: on
line diff
--- 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(" ") 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('<','<').replace('>','>') _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")); +