Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/JokeMachineActivity.py
diff options
context:
space:
mode:
Diffstat (limited to 'JokeMachineActivity.py')
-rw-r--r--JokeMachineActivity.py372
1 files changed, 372 insertions, 0 deletions
diff --git a/JokeMachineActivity.py b/JokeMachineActivity.py
new file mode 100644
index 0000000..d9f09be
--- /dev/null
+++ b/JokeMachineActivity.py
@@ -0,0 +1,372 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import os
+import logging
+import gtk
+
+from gettext import gettext as _
+
+import hippo
+from sugar.activity import activity
+
+from globals import Globals
+from gui.frame import Frame
+
+import pages.choose
+import pages.cover
+import pages.joke
+import pages.submit
+
+
+# Mesh
+import telepathy
+import telepathy.client
+from dbus import Interface
+from dbus.service import method, signal
+from dbus.gobject_service import ExportedGObject
+from sugar.presence.tubeconn import TubeConnection # deprecated ?! Gone from build >542 ? Ke ?
+from sugar.presence import presenceservice
+
+from mesh.activitysession import JokeMachineSession, MESH_IFACE, MESH_PATH, MESH_SERVICE
+
+# needed to unpickle state from journal
+from persistence.jokemachinestate import JokeMachineState
+
+
+
+class JokeMachineActivity(activity.Activity):
+ """Sugar activity for jokes
+
+ The Joke Machine is a fiendishly clever device cooked up by the mad
+ scientists at the worldwide workshop for sharing jokes with your friends.
+
+ If we have enough jokes we might even be able to make all the angry people
+ in our world collapse with giggles of helpless laughter!
+ """
+
+ def __init__(self, handle):
+ activity.Activity.__init__(self, handle)
+
+ # customize theme
+ gtkrc = os.path.join(Globals.pwd, 'gtkrc')
+ if os.path.exists(gtkrc):
+ logging.debug("Loading resources from %s" % gtkrc)
+ gtk.rc_add_default_file(gtkrc)
+ settings = gtk.settings_get_default()
+ #gtk.rc_reset_styles(settings)
+ gtk.rc_reparse_all_for_settings(settings, True)
+ logging.debug("Loading resources DONE")
+
+ Globals.set_activity_instance(self)
+
+ logging.debug("Starting the Joke Machine activity")
+
+ os.chdir(Globals.pwd) # required for i18n.py to work TODO -> You're not initting i8n properly dude!
+
+ # toolbox
+ self.__toolbox = activity.ActivityToolbox(self)
+ self.set_toolbox(self.__toolbox)
+
+ # main activity frame
+ self.__activity_frame = Frame()
+ vbox = gtk.VBox()
+ vbox.pack_start(self.__activity_frame)
+ vbox.show()
+ self.set_canvas(vbox)
+ self.show_all()
+
+ # Initialize mesh ##########################################################
+
+ # init Presence Service
+ self.__presence_service = presenceservice.get_instance()
+ try:
+ name, path = self.__presence_service.get_preferred_connection()
+ self.__telepathy_connection = telepathy.client.Connection(name, path)
+ self.__telepathy_initiating = None
+ except TypeError:
+ logging.debug('Presence service offline')
+
+ # Buddy object for you
+ owner = self.__presence_service.get_owner()
+ Globals.set_owner(owner)
+
+ self.__session = None # ???? self.poll_session
+ self.connect('shared', self.__do_activity_shared)
+
+
+ # Check if we're joining another instance
+ self.__is_initiator = True
+ if self._shared_activity is not None:
+ self.__is_initiator = False
+ logging.debug('shared: %s' % self._shared_activity.props.joined)
+ # We are joining the activity
+ logging.debug('Joined activity')
+ self.connect('joined', self.__do_activity_joined)
+ self._shared_activity.connect('buddy-joined', self.__do_buddy_joined)
+ self._shared_activity.connect('buddy-left', self.__do_buddy_left)
+ if self.get_shared():
+ # We've already joined
+ self.__do_activity_joined()
+ else:
+ logging.debug('Created activity')
+
+ # ##########################################################################
+
+ # set default startup page if we're the initiator
+ if self.is_initiator:
+ self.set_page(pages.choose.Choose)
+
+
+ # Mesh Callbacks #############################################################
+
+ def __setup(self):
+ '''Setup the Tubes channel
+ Called from: __do_activity_shared, __do_activity_joined.'''
+
+ if self._shared_activity is None:
+ logging.error('Failed to share or join activity')
+ return
+
+ bus_name, conn_path, channel_paths = self._shared_activity.get_channels()
+
+ # Work out what our room is called and whether we have Tubes already
+ room = None
+ tubes_chan = None
+ text_chan = None
+ for channel_path in channel_paths:
+ channel = telepathy.client.Channel(bus_name, channel_path)
+ htype, handle = channel.GetHandle()
+ if htype == telepathy.HANDLE_TYPE_ROOM:
+ # TODO - this log message throws an exception
+ #logging.debug('Found our room: it has handle# %d %s',
+ # handle,
+ # self.__telepathy_connection.InspectHandles(htype, [handle][0]))
+ logging.debug('Found our room: it has handle# %d' % handle)
+ room = handle
+ ctype = channel.GetChannelType()
+ if ctype == telepathy.CHANNEL_TYPE_TUBES:
+ logging.debug('Found our Tubes channel at %s', channel_path)
+ tubes_chan = channel
+ elif ctype == telepathy.CHANNEL_TYPE_TEXT:
+ logging.debug('Found our Text channel at %s', channel_path)
+ text_chan = channel
+
+ if room is None:
+ logging.debug('Presence service did not create a room')
+ return
+ if text_chan is None:
+ logging.debug('Presence service did not create a text channel')
+ return
+
+ # Make sure we have a Tubes channel - PS doesn't yet provide one
+ if tubes_chan is None:
+ logging.debug('Did not find our Tubes channel, requesting one...')
+ tubes_chan = self.__telepathy_connection.request_channel(telepathy.CHANNEL_TYPE_TUBES,
+ telepathy.HANDLE_TYPE_ROOM,
+ room,
+ True)
+ self.tubes_chan = tubes_chan
+ self.text_chan = text_chan
+
+ tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube', self._new_tube_cb)
+
+
+ def __do_activity_joined(self, activity):
+ pass
+ '''Callback for completion of joining the activity.'''
+ if not self._shared_activity:
+ return
+
+ # Find out who's already in the shared activity:
+ for buddy in self._shared_activity.get_joined_buddies():
+ logging.debug('Buddy %s is already in the activity' % buddy.props.nick)
+
+ logging.debug('Joined an existing shared activity')
+ self.__telepathy_initiating = False
+ self.__setup()
+
+ logging.debug('This is not my 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 _new_tube_cb(self, id, initiator, type, service, params, state):
+ '''Callback for when we have a Tube.'''
+ logging.debug('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 == MESH_SERVICE):
+ if state == telepathy.TUBE_STATE_LOCAL_PENDING:
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)
+
+ tube_conn = TubeConnection(self.__telepathy_connection,
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES],
+ id,
+ group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
+
+ logging.info('Starting a new JokeMachineSession')
+ self.__session = JokeMachineSession(tube_conn, self.__telepathy_initiating, self._get_buddy, self)
+
+
+ def _get_buddy(self, cs_handle):
+ """Get a Buddy from a channel specific handle."""
+ logging.debug('Trying to find owner of handle %u...', cs_handle)
+ group = self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]
+ my_csh = group.GetSelfHandle()
+ logging.debug('My handle in that group is %u', my_csh)
+ if my_csh == cs_handle:
+ handle = self.__telepathy_connection.GetSelfHandle()
+ logging.debug('CS handle %u belongs to me, %u', cs_handle, handle)
+ elif group.GetGroupFlags() & telepathy.CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES:
+ handle = group.GetHandleOwners([cs_handle])[0]
+ logging.debug('CS handle %u belongs to %u', cs_handle, handle)
+ else:
+ handle = cs_handle
+ logging.debug('non-CS handle %u belongs to itself', handle)
+ assert handle != 0
+
+ name, path = self.__presence_service.get_preferred_connection() # TODO - make sure this does not cause bugs
+
+ return self.__presence_service.get_buddy_by_telepathy_handle(name,
+ path,
+ handle)
+
+
+ def __do_buddy_joined(self, activity, buddy):
+ logging.debug('Buddy %s joined' % buddy.props.nick)
+
+
+ def __do_buddy_left(self, activity, buddy):
+ logging.debug('Buddy %s left' % buddy.props.nick)
+
+
+ def __do_activity_shared(self, activity):
+ '''Callback for completion of sharing of activity'''
+ logging.debug('The activity was shared')
+
+ self.__telepathy_initiating = True
+ self.__setup() # TODO - more civilized name
+
+ for buddy in self._shared_activity.get_joined_buddies():
+ logging.debug('Buddy %s is already in the activity' % buddy.props.nick)
+
+ self._shared_activity.connect('buddy-joined', self.__do_buddy_joined)
+ self._shared_activity.connect('buddy-left', self.__do_buddy_left)
+
+ logging.debug('This is my activity: making a tube...')
+ id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(MESH_SERVICE, {})
+
+
+ def _list_tubes_reply_cb(self, tubes):
+ for tube_info in tubes:
+ self._new_tube_cb(*tube_info)
+
+ def _list_tubes_error_cb(self, e):
+ logging.error('ListTubes() failed: %s', e)
+
+
+ @property
+ def tube(self):
+ logging.debug('Getting tube for activity: %r', self.__session)
+ return self.__session # TODO rename :-)
+
+ @property
+ def is_shared(self):
+ ret = self.__session is not None
+ logging.debug('Getting is_shared for activity: %r', ret)
+ return ret
+
+ @property
+ def is_initiator(self):
+ '''True if I'm the one joining an activity which was shared by someone else'''
+ ret = self.__is_initiator
+ logging.debug('Getting is_initiator for activity: %r', ret)
+ return ret
+
+ # ############################################################################
+
+
+ def refresh(self):
+ '''reload the current page'''
+ page_class = self.__activity_frame.page_class
+ logging.debug('Refreshing Page %r' % page_class)
+ self.set_page(page_class)
+
+
+ # TODO -> Make generally cleverer
+ # TODO -> Cache constructed pages if necessary for performance
+ # TODO -> Handle multiple page constructor arguments
+ def set_page(self, page_class, *args):
+ page = page_class(*args)
+ self.__activity_frame.page = page
+ return page
+
+
+
+ def read_file(self, file_path):
+ '''Callback to resume activity state from Journal'''
+ logging.debug('Reading file from datastore via Journal: %s' % file_path)
+
+ # TODO - double check -> if I'm a shared activity, don't restore me
+ # TODO - this doesn't work here - not initted yet
+ #if not self.is_initiator:
+ # logging.debug('joining a shared activity - dont restore')
+ # return
+
+ # read activity state from Journal
+ f = open(file_path, 'r')
+ pickle = f.read()
+ if len(pickle) == 0:
+ logging.debug('Activity.read_file() -> Journal has empty pickle - creating empty state')
+ activity_state = JokeMachineState().test_data()
+ else:
+ logging.debug('Unpickling state from Journal')
+ activity_state = JokeMachineState.loads(pickle)
+ f.close()
+
+ # set Globals.ActivityState
+ Globals.set_activity_state(activity_state)
+
+
+
+ def write_file(self, file_path):
+ '''Callback to persist activity state to Journal'''
+
+ # TODO - double check -> if I'm a shared activity, don't persist me
+ # TODO - this doesn't work here - not initted yet
+ #if not self.is_initiator:
+ # logging.debug('joining a shared activity - dont persist')
+ # return
+
+ if len(Globals.JokeMachineState.jokebooks) != 0:
+ logging.debug('Writing file to datastore via Journal: %s' % file_path)
+ # write activity state to journal
+ f = open(file_path, 'w')
+ pickle = Globals.JokeMachineState.dumps()
+ f.write(pickle)
+ f.close()
+ else:
+ logging.debug('nothing to persist')
+
+
+
+ def close(self):
+ '''Called on activity close'''
+ logging.info('Exiting Activity. Performing cleanup...')
+ Globals.shutdown()
+ logging.info('Done')
+ activity.Activity.close(self)