diff options
Diffstat (limited to 'ReflectionActivity.py')
-rw-r--r-- | ReflectionActivity.py | 150 |
1 files changed, 148 insertions, 2 deletions
diff --git a/ReflectionActivity.py b/ReflectionActivity.py index ac59374..4ee68f3 100644 --- a/ReflectionActivity.py +++ b/ReflectionActivity.py @@ -25,6 +25,13 @@ if _have_toolbox: from sugar.activity.widgets import StopButton from toolbar_utils import button_factory, label_factory, separator_factory +from utils import json_load, json_dump + +import telepathy +from dbus.service import signal +from dbus.gobject_service import ExportedGObject +from sugar.presence import presenceservice +from sugar.presence.tubeconn import TubeConnection from gettext import gettext as _ @@ -71,7 +78,7 @@ class ReflectionActivity(activity.Activity): def _setup_toolbars(self, have_toolbox): """ Setup the toolbars. """ - self.max_participants = 1 + self.max_participants = 4 if have_toolbox: toolbox = ToolbarBox() @@ -128,7 +135,7 @@ class ReflectionActivity(activity.Activity): def write_file(self, file_path): """ Write the grid status to the Journal """ - (orientation, dot_list) = self._game.save_game() + (dot_list, orientation) = self._game.save_game() self.metadata['orientation'] = orientation self.metadata['dotlist'] = '' for dot in dot_list: @@ -148,3 +155,142 @@ class ReflectionActivity(activity.Activity): for dot in dots: dot_list.append(int(dot)) self._game.restore_game(dot_list, orientation) + + # Collaboration-related methods + + def _setup_presence_service(self): + """ Setup the Presence Service. """ + self.pservice = presenceservice.get_instance() + self.initiating = None # sharing (True) or joining (False) + + owner = self.pservice.get_owner() + self.owner = owner + self._share = "" + self.connect('shared', self._shared_cb) + self.connect('joined', self._joined_cb) + + def _shared_cb(self, activity): + """ Either set up initial share...""" + self._new_tube_common(True) + + def _joined_cb(self, activity): + """ ...or join an exisiting share. """ + self._new_tube_common(False) + + def _new_tube_common(self, sharer): + """ Joining and sharing are mostly the same... """ + if self._shared_activity is None: + print("Error: Failed to share or join activity ... \ + _shared_activity is null in _shared_cb()") + return + + self.initiating = sharer + self.waiting_for_hand = not sharer + + self.conn = self._shared_activity.telepathy_conn + self.tubes_chan = self._shared_activity.telepathy_tubes_chan + self.text_chan = self._shared_activity.telepathy_text_chan + + self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( + 'NewTube', self._new_tube_cb) + + if sharer: + print('This is my activity: making a tube...') + id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( + SERVICE, {}) + else: + print('I am joining an activity: waiting for a tube...') + self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( + reply_handler=self._list_tubes_reply_cb, + error_handler=self._list_tubes_error_cb) + + def _list_tubes_reply_cb(self, tubes): + """ Reply to a list request. """ + for tube_info in tubes: + self._new_tube_cb(*tube_info) + + def _list_tubes_error_cb(self, e): + """ Log errors. """ + print('Error: ListTubes() failed: %s', e) + + def _new_tube_cb(self, id, initiator, type, service, params, state): + """ Create a new tube. """ + print('New tube: ID=%d initator=%d type=%d service=%s params=%r \ +state=%d' % (id, initiator, type, service, params, state)) + + if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE): + if state == telepathy.TUBE_STATE_LOCAL_PENDING: + self.tubes_chan[ \ + telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id) + + tube_conn = TubeConnection(self.conn, + self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, \ + group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]) + + self.chattube = ChatTube(tube_conn, self.initiating, \ + self.event_received_cb) + + def _setup_dispatch_table(self): + ''' Associate tokens with commands. ''' + self._processing_methods = { + 'n': [self._receive_new_game, 'get a new game grid'], + 'p': [self._receive_dot_click, 'get a dot click'], + } + + def event_received_cb(self, event_message): + ''' Data from a tube has arrived. ''' + if len(event_message) == 0: + return + try: + command, payload = event_message.split('|', 2) + except ValueError: + print('Could not split event message %s' % (event_message)) + return + self._processing_methods[command][0](payload) + + def start_new_game(self): + ''' Send a new orientation, grid to all players ''' + self.send_event('n|%s' % (json_dump(self._game.save_game()))) + + def _receive_new_game(self, payload): + ''' Sharer can start a new game. ''' + (dot_list, orientation) = json_load(payload) + self._game.restore_game(dot_list, orientation) + + def send_button_press(self, dot, color): + ''' Send a dot click to all the players ''' + self.send_event('p|%s' % (json_dump([dot, color]))) + + def _receive_dot_click(self, payload): + ''' When a dot is clicked, everyone should change its color. ''' + (dot, color) = json_load(payload) + self._game.remote_button_press(dot, color) + + def send_event(self, entry): + """ Send event through the tube. """ + if hasattr(self, 'chattube') and self.chattube is not None: + self.chattube.SendText(entry) + + +class ChatTube(ExportedGObject): + """ Class for setting up tube for sharing """ + + def __init__(self, tube, is_initiator, stack_received_cb): + super(ChatTube, self).__init__(tube, PATH) + self.tube = tube + self.is_initiator = is_initiator # Are we sharing or joining activity? + self.stack_received_cb = stack_received_cb + self.stack = '' + + self.tube.add_signal_receiver(self.send_stack_cb, 'SendText', IFACE, + path=PATH, sender_keyword='sender') + + def send_stack_cb(self, text, sender=None): + if sender == self.tube.get_unique_name(): + return + self.stack = text + self.stack_received_cb(text) + + @signal(dbus_interface=IFACE, signature='s') + def SendText(self, text): + self.stack = text |