Mercurial > libervia-web
view libervia.py @ 26:824516b247e6
browser side: added ContactsChooser dialog
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 07 May 2011 23:52:44 +0200 |
parents | 0ce2a57b34ca |
children | 258dfaa1035f |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- """ Libervia: a Salut à Toi frontend Copyright (C) 2011 Jérôme Poisson (goffi@goffi.org) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ 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 from browser_side.jid import JID class LiberviaJsonProxy(JSONProxy): def __init__(self, *args, **kwargs): JSONProxy.__init__(self, *args, **kwargs) self.handler=self self.cb={} def call(self, method, cb, *args): if cb: self.cb[method] = cb self.callMethod(method,args) 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] def onRemoteError(self, code, errobj, request_info): if code != 0: Window.alert("Internal server error") else: if isinstance(errobj['message'],dict): Window.alert("Error %s: %s" % (errobj['message']['faultCode'], errobj['message']['faultString'])) else: Window.alert("Error: %s" % errobj['message']) class RegisterCall(LiberviaJsonProxy): def __init__(self): LiberviaJsonProxy.__init__(self, "/register_api", ["isRegistered","isConnected","connect"]) self.handler=self self.cb={} class BridgeCall(LiberviaJsonProxy): def __init__(self): LiberviaJsonProxy.__init__(self, "/json_api", ["getContacts", "sendMessage", "sendMblog", "getMblogNodes", "getProfileJid", "getHistory", "getPresenceStatus"]) class BridgeSignals(LiberviaJsonProxy): def __init__(self): LiberviaJsonProxy.__init__(self, "/json_signal_api", ["getSignals"]) class UniBox(AutoCompleteTextBox): 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.contactPanel.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.uniBox = UniBox(self) self.uniBox.addKey("@@: ") self.statusPanel = StatusPanel(self) self.contactPanel = 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.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._register = RegisterCall() self._register.call('isRegistered',self._isRegisteredCB) def select(self, widget): """Define the selected widget""" if self.selected: self.selected.removeStyleName('selected_widget') self.selected = widget if widget: self.selected.addStyleName('selected_widget') def _isRegisteredCB(self, registered): if not registered: self._dialog = RegisterBox(self.logged,centered=True) self._dialog.show() else: self._register.call('isConnected', self._isConnectedCB) def _isConnectedCB(self, connected): if not connected: self._register.call('connect',self.logged) else: self.logged() def logged(self): if self._dialog: self._dialog.hide() del self._dialog # don't work if self._dialog is None #it's time to fill the page self.bridge.call('getContacts', self._getContactsCB) self.bridge_signals.call('getSignals', self._getSignalsCB) #We want to know our own jid self.bridge.call('getProfileJid', self._getProfileJidCB) def _getContactsCB(self, contacts_data): for contact in contacts_data: jid, attributes, groups = contact self.contactPanel.addContact(jid, attributes, groups) def _getSignalsCB(self, signal_data): bridge_signals = BridgeSignals() bridge_signals.call('getSignals', self._getSignalsCB) print('Got signal ==> name: %s, params: %s' % (signal_data[0],signal_data[1])) name,args = signal_data if name == 'personalEvent': self._personalEventCb(*args) elif name == 'newMessage': self._newMessageCb(*args) elif name == 'presenceUpdate': self._presenceUpdateCb(*args) def _getProfileJidCB(self, jid): self.whoami = JID(jid) #we can now ask our status self.bridge.call('getPresenceStatus', self._getPresenceStatusCB) ## Signals callbacks ## def _personalEventCb(self, sender, event_type, data, profile): if event_type == "MICROBLOG": if not data.has_key('content'): print ("WARNING: No content found in microblog data") return if data.has_key('groups'): _groups = set(data['groups'].split() if data['groups'] else []) else: _groups=None for panel in self.mpanels: if isinstance(panel,MicroblogPanel) and (panel.isJidAccepted(sender) or _groups == None or _groups.intersection(panel.accepted_groups)): content = data['content'] author = data.get('author') timestamp = float(data.get('timestamp',0)) #XXX: int doesn't work here panel.addEntry(content, author, timestamp) def _newMessageCb(self, from_jid, msg, msg_type, to_jid): _from = JID(from_jid) _to = JID(to_jid) for panel in self.mpanels: if isinstance(panel,ChatPanel) and (panel.target.bare == _from.bare or panel.target.bare == _to.bare): panel.printMessage(_from, msg) def _presenceUpdateCb(self, entity, show, priority, statuses): _entity = JID(entity) #XXX: QnD way to only get our status if self.whoami and self.whoami.bare == _entity.bare and statuses: self.statusPanel.changeStatus(statuses.values()[0]) def _getPresenceStatusCB(self, presence_data): #XXX we are only interested in our own presence so far if self.whoami and presence_data.has_key(self.whoami.bare): myjid = self.whoami.bare if presence_data[myjid]: args = presence_data[myjid].values()[0] self._presenceUpdateCb(myjid, *args) if __name__ == '__main__': pyjd.setup("http://localhost:8080/libervia.html") app = SatWebFrontend() app.onModuleLoad() pyjd.run()