diff options
author | Dan Williams <dcbw@localhost.localdomain> | 2006-09-15 20:50:06 (GMT) |
---|---|---|
committer | Dan Williams <dcbw@localhost.localdomain> | 2006-09-15 20:50:06 (GMT) |
commit | 922b7238b9db8307f6b9df9b3a4e36f9a46e81a0 (patch) | |
tree | 90aa62656494be7b5740c43549adbbcfaab49ac8 /shell/model | |
parent | b39eff33655590565aaac3d514df640f1ad3f2a8 (diff) | |
parent | e79a5f5e989fa062366295c3f236692fc3c889e5 (diff) |
Merge
Diffstat (limited to 'shell/model')
-rw-r--r-- | shell/model/BuddyInfo.py | 24 | ||||
-rw-r--r-- | shell/model/Friends.py | 65 | ||||
-rw-r--r-- | shell/model/Invites.py | 54 | ||||
-rw-r--r-- | shell/model/Makefile.am | 8 | ||||
-rw-r--r-- | shell/model/Owner.py | 99 | ||||
-rw-r--r-- | shell/model/ShellModel.py | 64 | ||||
-rw-r--r-- | shell/model/__init__.py | 0 |
7 files changed, 314 insertions, 0 deletions
diff --git a/shell/model/BuddyInfo.py b/shell/model/BuddyInfo.py new file mode 100644 index 0000000..68f0a44 --- /dev/null +++ b/shell/model/BuddyInfo.py @@ -0,0 +1,24 @@ +from sugar.presence import PresenceService +from sugar.canvas.IconColor import IconColor + +class BuddyInfo: + def __init__(self, buddy=None): + if buddy: + self.set_name(buddy.get_name()) + self.set_color(buddy.get_color()) + + def set_name(self, name): + self._name = name + + def set_color(self, color_string): + self._color = IconColor(color_string) + + def get_name(self): + return self._name + + def get_color(self): + return self._color + + def get_buddy(self): + pservice = PresenceService.get_instance() + return pservice.get_buddy_by_name(self._name) diff --git a/shell/model/Friends.py b/shell/model/Friends.py new file mode 100644 index 0000000..a11acc0 --- /dev/null +++ b/shell/model/Friends.py @@ -0,0 +1,65 @@ +import os +from ConfigParser import ConfigParser + +import gobject + +from model.BuddyInfo import BuddyInfo +from sugar import env + +class Friends(gobject.GObject): + __gsignals__ = { + 'friend-added': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([object])), + 'friend-removed': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([str])), + } + + def __init__(self): + gobject.GObject.__init__(self) + + self._friends = {} + self._path = os.path.join(env.get_profile_path(), 'friends') + + self.load() + + def has_buddy(self, buddy): + return self._friends.has_key(buddy.get_name()) + + def add_friend(self, buddy_info): + self._friends[buddy_info.get_name()] = buddy_info + self.emit('friend-added', buddy_info) + + def make_friend(self, buddy): + if not self.has_buddy(buddy): + self.add_friend(BuddyInfo(buddy)) + self.save() + + def remove(self, buddy_info): + del self._friends[buddy_info.get_name()] + self.save() + self.emit('friend-removed', buddy_info.get_name()) + + def __iter__(self): + return self._friends.values().__iter__() + + def load(self): + cp = ConfigParser() + + if cp.read([self._path]): + for name in cp.sections(): + buddy = BuddyInfo() + buddy.set_name(name) + buddy.set_color(cp.get(name, 'color')) + self.add_friend(buddy) + + def save(self): + cp = ConfigParser() + + for friend in self: + section = friend.get_name() + cp.add_section(section) + cp.set(section, 'color', friend.get_color().to_string()) + + fileobject = open(self._path, 'w') + cp.write(fileobject) + fileobject.close() diff --git a/shell/model/Invites.py b/shell/model/Invites.py new file mode 100644 index 0000000..24f9913 --- /dev/null +++ b/shell/model/Invites.py @@ -0,0 +1,54 @@ +import gobject + +import conf +from sugar.presence import PresenceService +from sugar.canvas.IconColor import IconColor + +class Invite: + def __init__(self, issuer, bundle_id, activity_id): + self._issuer = issuer + self._activity_id = activity_id + self._bundle_id = bundle_id + + def get_icon(self): + reg = conf.get_activity_registry() + return reg.get_activity(self._bundle_id).get_icon() + + def get_color(self): + pservice = PresenceService.get_instance() + buddy = pservice.get_buddy_by_name(self._issuer) + if buddy != None: + return IconColor(buddy.get_color()) + else: + return IconColor('white') + + def get_activity_id(self): + return self._activity_id + + def get_bundle_id(self): + return self._bundle_id + +class Invites(gobject.GObject): + __gsignals__ = { + 'invite-added': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([object])), + 'invite-removed': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([object])), + } + + def __init__(self): + gobject.GObject.__init__(self) + + self._list = [] + + def add_invite(self, issuer, bundle_id, activity_id): + invite = Invite(issuer, bundle_id, activity_id) + self._list.append(invite) + self.emit('invite-added', invite) + + def remove_invite(self, invite): + self._list.remove(invite) + self.emit('invite-removed', invite) + + def __iter__(self): + return self._list.__iter__() diff --git a/shell/model/Makefile.am b/shell/model/Makefile.am new file mode 100644 index 0000000..ce24668 --- /dev/null +++ b/shell/model/Makefile.am @@ -0,0 +1,8 @@ +sugardir = $(pkgdatadir)/shell/model +sugar_PYTHON = \ + __init__.py \ + BuddyInfo.py \ + Friends.py \ + Invites.py \ + Owner.py \ + ShellModel.py diff --git a/shell/model/Owner.py b/shell/model/Owner.py new file mode 100644 index 0000000..24004f0 --- /dev/null +++ b/shell/model/Owner.py @@ -0,0 +1,99 @@ +import os +import random +import base64 +import time + +import conf +from sugar import env +import logging +from sugar.p2p import Stream +from sugar.presence import PresenceService +from model.Invites import Invites + +PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp" + +class ShellOwner(object): + """Class representing the owner of this machine/instance. This class + runs in the shell and serves up the buddy icon and other stuff. It's the + server portion of the Owner, paired with the client portion in Buddy.py.""" + def __init__(self, shell): + profile = conf.get_profile() + + self._nick = profile.get_nick_name() + user_dir = profile.get_path() + + self._icon = None + for fname in os.listdir(user_dir): + if not fname.startswith("buddy-icon."): + continue + fd = open(os.path.join(user_dir, fname), "r") + self._icon = fd.read() + fd.close() + break + + self._pservice = PresenceService.get_instance() + + self._invites = Invites() + + self._shell = shell + self._shell.connect('activity-changed', self.__activity_changed_cb) + self._last_activity_update = time.time() + self._pending_activity_update_timer = None + self._pending_activity_update = None + + def get_invites(self): + return self._invites + + def announce(self): + # Create and announce our presence + color = conf.get_profile().get_color() + props = {'color':color.to_string()} + activity = self._shell.get_current_activity() + if activity is not None: + props['cur_activity':activity.get_id()] + self._last_activity_update = time.time() + self._service = self._pservice.register_service(self._nick, + PRESENCE_SERVICE_TYPE, properties=props) + logging.debug("Owner '%s' using port %d" % (self._nick, self._service.get_port())) + self._icon_stream = Stream.Stream.new_from_service(self._service) + self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon") + self._icon_stream.register_reader_handler(self._handle_invite, "invite") + + def _handle_buddy_icon_request(self): + """XMLRPC method, return the owner's icon encoded with base64.""" + if self._icon: + return base64.b64encode(self._icon) + return "" + + def _handle_invite(self, issuer, bundle_id, activity_id): + """XMLRPC method, called when the owner is invited to an activity.""" + self._invites.add_invite(issuer, bundle_id, activity_id) + return '' + + def __update_advertised_current_activity_cb(self): + self._last_activity_update = time.time() + self._pending_activity_update_timer = None + logging.debug("*** Updating current activity to %s" % self._pending_activity_update) + return False + + def __activity_changed_cb(self, shell, activity): + """Update our presence service with the latest activity, but no + more frequently than every 30 seconds""" + self._pending_activity_update = activity.get_id() + # If there's no pending update, we must not have updated it in the + # last 30 seconds (except for the initial update, hence we also check + # for the last update) + if not self._pending_activity_update_timer or time.time() - self._last_activity_update > 30: + self.__update_advertised_current_activity_cb() + return + + # If we have a pending update already, we have nothing left to do + if self._pending_activity_update_timer: + return + + # Otherwise, we start a timer to update the activity at the next + # interval, which should be 30 seconds from the last update, or if that + # is in the past already, then now + next = 30 - max(30, time.time() - self._last_activity_update) + self._pending_activity_update_timer = gobject.timeout_add(next * 1000, + self.__update_advertised_current_activity_cb) diff --git a/shell/model/ShellModel.py b/shell/model/ShellModel.py new file mode 100644 index 0000000..0820b44 --- /dev/null +++ b/shell/model/ShellModel.py @@ -0,0 +1,64 @@ +import gobject + +from sugar.presence import PresenceService +from model.Friends import Friends +from model.Owner import ShellOwner + +class ShellModel(gobject.GObject): + __gsignals__ = { + 'activity-opened': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), + 'activity-changed': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), + 'activity-closed': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])) + } + + def __init__(self): + gobject.GObject.__init__(self) + + self._hosts = {} + self._current_activity = None + + PresenceService.start() + self._pservice = PresenceService.get_instance() + + self._owner = ShellOwner(self) + self._owner.announce() + self._friends = Friends() + + def get_friends(self): + return self._friends + + def get_invites(self): + return self._owner.get_invites() + + def get_owner(self): + return self._owner + + def add_activity(self, activity_host): + self._hosts[activity_host.get_xid()] = activity_host + self.emit('activity-opened', activity_host) + + def set_current_activity(self, activity_xid): + activity_host = self._hosts[activity_xid] + if self._current_activity == activity_host: + return + + self._current_activity = activity_host + self.emit('activity-changed', activity_host) + + def remove_activity(self, activity_xid): + if self._hosts.has_key(activity_xid): + host = self._hosts[activity_xid] + self.emit('activity-closed', host) + del self._hosts[activity_xid] + + def get_activity(self, activity_id): + for host in self._hosts.values(): + if host.get_id() == activity_id: + return host + return None + + def get_current_activity(self): + return self._current_activity diff --git a/shell/model/__init__.py b/shell/model/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/shell/model/__init__.py |