Display icons in the chat

This commit is contained in:
Marco Pesenti Gritti 2006-05-22 02:10:30 -04:00
parent 3b2f185e5c
commit d3c5da1a66
4 changed files with 59 additions and 160 deletions

View File

@ -14,7 +14,6 @@ import gtk, gobject
from sugar.shell import activity from sugar.shell import activity
from sugar.p2p.Group import Group from sugar.p2p.Group import Group
from sugar.p2p import Buddy
from sugar.p2p.Group import LocalGroup from sugar.p2p.Group import LocalGroup
from sugar.p2p.Service import Service from sugar.p2p.Service import Service
from sugar.p2p.Stream import Stream from sugar.p2p.Stream import Stream
@ -35,7 +34,6 @@ GROUP_CHAT_SERVICE_PORT = 6200
class Chat(activity.Activity): class Chat(activity.Activity):
def __init__(self, controller): def __init__(self, controller):
Buddy.recognize_buddy_service_type(CHAT_SERVICE_TYPE)
self._controller = controller self._controller = controller
activity.Activity.__init__(self) activity.Activity.__init__(self)
self._stream_writer = None self._stream_writer = None
@ -276,12 +274,27 @@ class Chat(activity.Activity):
print "act %d: in activity_on_got_focus" % self.activity_get_id() print "act %d: in activity_on_got_focus" % self.activity_get_id()
# FIXME self._controller.notify_activate(self) # FIXME self._controller.notify_activate(self)
def _insert_buddy(self, buf, nick):
buddy = self._group.get_buddy(nick)
print buddy.get_nick_name()
pbl = gtk.gdk.PixbufLoader()
pbl.write(buddy.get_icon())
pbl.close()
pbuf = pbl.get_pixbuf()
aniter = buf.get_end_iter()
buf.insert_pixbuf(aniter, pbuf)
aniter = buf.get_end_iter()
buf.insert(aniter, nick + ": ")
def _insert_rich_message(self, nick, msg): def _insert_rich_message(self, nick, msg):
msg = Emoticons.get_instance().replace(msg) msg = Emoticons.get_instance().replace(msg)
buf = self._chat_view.get_buffer() buf = self._chat_view.get_buffer()
aniter = buf.get_end_iter()
buf.insert(aniter, nick + ": ") self._insert_buddy(buf, nick)
serializer = richtext.RichTextSerializer() serializer = richtext.RichTextSerializer()
serializer.deserialize(msg, buf) serializer.deserialize(msg, buf)
@ -297,8 +310,10 @@ class Chat(activity.Activity):
pbuf = pbl.get_pixbuf() pbuf = pbl.get_pixbuf()
buf = self._chat_view.get_buffer() buf = self._chat_view.get_buffer()
self._insert_buddy(buf, nick)
aniter = buf.get_end_iter() aniter = buf.get_end_iter()
buf.insert(aniter, nick + ": ")
buf.insert_pixbuf(aniter, pbuf) buf.insert_pixbuf(aniter, pbuf)
aniter = buf.get_end_iter() aniter = buf.get_end_iter()
buf.insert(aniter, "\n") buf.insert(aniter, "\n")
@ -374,7 +389,7 @@ class BuddyChat(Chat):
self.activity_set_can_close(True) self.activity_set_can_close(True)
self.activity_set_tab_icon_name("im") self.activity_set_tab_icon_name("im")
self.activity_show_icon(True) self.activity_show_icon(True)
self._stream_writer = self._controller.new_buddy_writer(self._buddy) self._stream_writer = self._controller.new_buddy_writer(self._buddy.get_service_name())
def recv_message(self, sender, msg): def recv_message(self, sender, msg):
Chat.recv_message(self, self._buddy, msg) Chat.recv_message(self, self._buddy, msg)
@ -418,17 +433,17 @@ class GroupChat(Chat):
def get_group(self): def get_group(self):
return self._group return self._group
def new_buddy_writer(self, buddy, threaded=False): def new_buddy_writer(self, buddy_name):
service = buddy.get_service(CHAT_SERVICE_TYPE) service = self._group.get_service(buddy_name, CHAT_SERVICE_TYPE)
return self._buddy_stream.new_writer(service, threaded=threaded) return self._buddy_stream.new_writer(service)
def _start(self): def _start(self):
self._group = LocalGroup() self._group = LocalGroup()
self._group.add_presence_listener(self._on_group_presence_event) self._group.add_presence_listener(self._on_group_presence_event)
self._group.add_service_listener(self._on_group_service_event) self._group.add_service_listener(self._on_group_service_event)
self._group.join() self._group.join()
name = self._group.get_owner().get_nick_name() name = self._group.get_owner().get_service_name()
# Group controls the Stream for incoming messages for # Group controls the Stream for incoming messages for
# specific buddy chats # specific buddy chats
@ -542,18 +557,14 @@ class GroupChat(Chat):
self._chats[buddy] = chat self._chats[buddy] = chat
chat.activity_connect_to_shell() chat.activity_connect_to_shell()
def _request_buddy_icon_cb(self, response, user_data): def _request_buddy_icon(self, buddy):
icon = response writer = self.new_buddy_writer(buddy.get_service_name())
buddy = user_data icon = writer.custom_request("get_buddy_icon")
if icon and len(icon): if icon and len(icon):
icon = base64.b64decode(icon) icon = base64.b64decode(icon)
print "Buddy icon for '%s' is size %d" % (buddy.get_nick_name(), len(icon)) print "Setting buddy icon for '%s' to %s" % (buddy.get_nick_name(), icon)
buddy.set_icon(icon) buddy.set_icon(icon)
def _request_buddy_icon(self, buddy):
writer = self.new_buddy_writer(buddy, threaded=True)
icon = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, buddy)
def _on_group_service_event(self, action, service): def _on_group_service_event(self, action, service):
if action == Group.SERVICE_ADDED: if action == Group.SERVICE_ADDED:
# Look for the olpc chat service # Look for the olpc chat service
@ -563,7 +574,6 @@ class GroupChat(Chat):
if buddy and buddy.get_address() == service.get_address(): if buddy and buddy.get_address() == service.get_address():
# Try to get the buddy's icon # Try to get the buddy's icon
if buddy.get_nick_name() != self._group.get_owner().get_nick_name(): if buddy.get_nick_name() != self._group.get_owner().get_nick_name():
print "Requesting buddy icon from '%s'." % buddy.get_nick_name()
self._request_buddy_icon(buddy) self._request_buddy_icon(buddy)
elif action == Group.SERVICE_REMOVED: elif action == Group.SERVICE_REMOVED:
pass pass
@ -641,7 +651,6 @@ if len(sys.argv) > 1 and sys.argv[1] == "--console":
ChatShell.get_instance().open_group_chat() ChatShell.get_instance().open_group_chat()
try: try:
gtk.threads_init()
gtk.main() gtk.main()
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

View File

@ -2,63 +2,38 @@ import pwd
import os import os
from Service import Service from Service import Service
from sugar import env
PRESENCE_SERVICE_TYPE = "_olpc_presence._tcp" PRESENCE_SERVICE_TYPE = "_olpc_presence._tcp"
PRESENCE_SERVICE_PORT = 6000 PRESENCE_SERVICE_PORT = 6000
__buddy_service_types = [PRESENCE_SERVICE_TYPE] class BuddyBase:
def __init__(self, service, nick_name):
def recognize_buddy_service_type(stype): self._service = service
if stype not in __buddy_service_types: self._nick_name = nick_name
__buddy_service_types.append(stype)
def get_recognized_buddy_service_types():
return __buddy_service_types[:]
class Buddy(object):
def __init__(self, service):
self._services = {}
self._services[service.get_type()] = service
self._nick_name = service.get_name()
self._address = service.get_address()
def get_icon(self): def get_icon(self):
"""Return the buddies icon, if any.""" """Return the buddies icon, if any."""
return self._icon return self._icon
def get_address(self): def get_address(self):
return self._address return self._service.get_address()
def add_service(self, service): def get_service_name(self):
if service.get_name() != self._nick_name: return self._service.get_name()
return False
if service.get_address() != self._address:
return False
if self._services.has_key(service.get_type()):
return False
self._services[service.get_type()] = service
def remove_service(self, stype):
if self._services.has_key(stype):
del self._services[stype]
def get_service(self, stype):
if self._services.has_key(stype):
return self._services[stype]
return None
def get_nick_name(self): def get_nick_name(self):
return self._nick_name return self._nick_name
class Buddy(BuddyBase):
"""Normal buddy class."""
def set_icon(self, icon): def set_icon(self, icon):
"""Can only set icon for other buddies. The Owner """Can only set icon for other buddies. The Owner
takes care of setting it's own icon.""" takes care of setting it's own icon."""
self._icon = icon self._icon = icon
class Owner(Buddy): class Owner(BuddyBase):
"""Class representing the owner of this machine/instance.""" """Class representing the owner of this machine/instance."""
def __init__(self, group): def __init__(self, group):
self._group = group self._group = group
@ -67,20 +42,19 @@ class Owner(Buddy):
if not nick or not len(nick): if not nick or not len(nick):
nick = "n00b" nick = "n00b"
self._presence_service = Service(nick, PRESENCE_SERVICE_TYPE, PRESENCE_SERVICE_PORT) service = Service(nick, PRESENCE_SERVICE_TYPE, PRESENCE_SERVICE_PORT)
Buddy.__init__(self, self._presence_service) BuddyBase.__init__(self, service, nick)
for fname in os.listdir(env.get_user_dir()): sugar_dir = os.path.abspath(os.path.expanduser("~/.sugar"))
icon = None
for fname in os.listdir(sugar_dir):
if not fname.startswith("buddy-icon."): if not fname.startswith("buddy-icon."):
continue continue
fd = open(os.path.join(env.get_user_dir(), fname), "r") fd = open(os.path.join(sugar_dir, fname), "r")
self._icon = fd.read() self._icon = fd.read()
fd.close() fd.close()
break break
def set_icon(self, icon):
"""Can only set icon in constructor for now."""
pass
def register(self): def register(self):
self._presence_service.register(self._group) self._service.register(self._group)

View File

@ -1,7 +1,6 @@
import avahi import avahi
from Buddy import Buddy from Buddy import Buddy
from Buddy import get_recognized_buddy_service_types
from Buddy import Owner from Buddy import Owner
from Buddy import PRESENCE_SERVICE_TYPE from Buddy import PRESENCE_SERVICE_TYPE
from Service import Service from Service import Service
@ -62,6 +61,7 @@ class LocalGroup(Group):
self._pdiscovery.start() self._pdiscovery.start()
self._owner = Owner(self) self._owner = Owner(self)
self._add_buddy(self._owner)
def get_owner(self): def get_owner(self):
return self._owner return self._owner
@ -106,14 +106,8 @@ class LocalGroup(Group):
self._pdiscovery.resolve_service(interface, protocol, name, stype, domain, self._pdiscovery.resolve_service(interface, protocol, name, stype, domain,
self._on_service_resolved) self._on_service_resolved)
elif action == presence.ACTION_SERVICE_REMOVED: elif action == presence.ACTION_SERVICE_REMOVED:
if stype in get_recognized_buddy_service_types(): if stype == PRESENCE_SERVICE_TYPE:
buddy = self.get_buddy(name) self._remove_buddy(name)
if buddy:
buddy.remove_service(stype)
# Removal of the presence service removes the buddy too
if stype == PRESENCE_SERVICE_TYPE:
self._remove_buddy(name)
self.remove_service((name, stype))
elif stype.startswith(_OLPC_SERVICE_TYPE_PREFIX): elif stype.startswith(_OLPC_SERVICE_TYPE_PREFIX):
self.remove_service((name, stype)) self.remove_service((name, stype))
@ -125,20 +119,9 @@ class LocalGroup(Group):
for prop in avahi.txt_array_to_string_array(txt): for prop in avahi.txt_array_to_string_array(txt):
(key, value) = prop.split('=') (key, value) = prop.split('=')
if key == 'group_address': if key == 'group_address':
service.set_group_address(value) service.set_group_address(value)
# print "ServiceResolved: name=%s, stype=%s, port=%s, address=%s" % (name, stype, port, address) if stype == PRESENCE_SERVICE_TYPE:
if stype in get_recognized_buddy_service_types(): self._add_buddy(Buddy(service, name))
# Service recognized as Buddy services either create a new
# buddy if one doesn't exist yet, or get added to the existing
# buddy
buddy = self.get_buddy(name)
if buddy:
buddy.add_service(service)
else:
self._add_buddy(Buddy(service))
self.add_service(service)
elif stype.startswith(_OLPC_SERVICE_TYPE_PREFIX): elif stype.startswith(_OLPC_SERVICE_TYPE_PREFIX):
# These services aren't associated with buddies
self.add_service(service) self.add_service(service)

View File

@ -1,12 +1,6 @@
import xmlrpclib import xmlrpclib
import socket import socket
import traceback import traceback
import threading
import pygtk
pygtk.require('2.0')
import gobject
import network import network
from MostlyReliablePipe import MostlyReliablePipe from MostlyReliablePipe import MostlyReliablePipe
@ -38,7 +32,7 @@ class Stream(object):
self._callback(self._group.get_buddy(nick_name), data) self._callback(self._group.get_buddy(nick_name), data)
class UnicastStreamWriterBase(object): class UnicastStreamWriter(object):
def __init__(self, stream, service, owner_nick_name): def __init__(self, stream, service, owner_nick_name):
# set up the writer # set up the writer
if not service: if not service:
@ -48,10 +42,6 @@ class UnicastStreamWriterBase(object):
self._address = self._service.get_address() self._address = self._service.get_address()
self._port = self._service.get_port() self._port = self._service.get_port()
self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port) self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
class UnicastStreamWriter(UnicastStreamWriterBase):
def __init__(self, stream, service, owner_nick_name):
UnicastStreamWriterBase.__init__(self, stream, service, owner_nick_name)
self._writer = xmlrpclib.ServerProxy(self._xmlrpc_addr) self._writer = xmlrpclib.ServerProxy(self._xmlrpc_addr)
def write(self, data): def write(self, data):
@ -73,60 +63,6 @@ class UnicastStreamWriter(UnicastStreamWriterBase):
return None return None
class ThreadedRequest(threading.Thread):
def __init__(self, controller, addr, method, response_cb, user_data, *args):
threading.Thread.__init__(self)
self._controller = controller
self._method = method
self._args = args
self._response_cb = response_cb
self._user_data = user_data
self._writer = xmlrpclib.ServerProxy(addr)
def run(self):
response = None
try:
method = getattr(self._writer, self._method)
response = method(*self._args)
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
traceback.print_exc()
if self._response_cb:
gobject.idle_add(self._response_cb, response, self._user_data)
self._controller.notify_request_done(self)
class ThreadedUnicastStreamWriter(UnicastStreamWriterBase):
def __init__(self, stream, service, owner_nick_name):
self._requests_lock = threading.Lock()
self._requests = []
UnicastStreamWriterBase.__init__(self, stream, service, owner_nick_name)
def _add_request(self, request):
self._requests_lock.acquire()
if not request in self._requests:
self._requests.append(request)
self._requests_lock.release()
def write(self, response_cb, user_data, data):
"""Write some data to the default endpoint of this pipe on the remote server."""
request = ThreadedRequest(self, self._xmlrpc_addr, "message", response_cb,
user_data, self._owner_nick_name, data)
self._add_request(request)
request.start()
def custom_request(self, method_name, response_cb, user_data, *args):
"""Call a custom XML-RPC method on the remote server."""
request = ThreadedRequest(self, self._xmlrpc_addr, method_name, response_cb,
user_data, *args)
self._add_request(request)
request.start()
def notify_request_done(self, request):
self._requests_lock.acquire()
if request in self._requests:
self._requests.remove(request)
self._requests_lock.release()
class UnicastStream(Stream): class UnicastStream(Stream):
def __init__(self, service, group): def __init__(self, service, group):
Stream.__init__(self, service, group) Stream.__init__(self, service, group)
@ -158,11 +94,8 @@ class UnicastStream(Stream):
raise ValueError("Handler name 'message' is a reserved handler.") raise ValueError("Handler name 'message' is a reserved handler.")
self._reader.register_function(handler, name) self._reader.register_function(handler, name)
def new_writer(self, service, threaded=False): def new_writer(self, service):
if threaded: return UnicastStreamWriter(self, service, self._owner_nick_name)
return ThreadedUnicastStreamWriter(self, service, self._owner_nick_name)
else:
return UnicastStreamWriter(self, service, self._owner_nick_name)
class MulticastStream(Stream): class MulticastStream(Stream):
@ -182,5 +115,5 @@ class MulticastStream(Stream):
[ nick_name, data ] = data.split(" |**| ", 2) [ nick_name, data ] = data.split(" |**| ", 2)
self.recv(nick_name, data) self.recv(nick_name, data)
def new_writer(self, service=None, threaded=False): def new_writer(self, service=None):
return self return self