Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/ShareFavorites.py
diff options
context:
space:
mode:
Diffstat (limited to 'ShareFavorites.py')
-rw-r--r--ShareFavorites.py294
1 files changed, 294 insertions, 0 deletions
diff --git a/ShareFavorites.py b/ShareFavorites.py
new file mode 100644
index 0000000..10d65c8
--- /dev/null
+++ b/ShareFavorites.py
@@ -0,0 +1,294 @@
+# -*- coding: utf-8 -*-
+#Copyright (c) 2013 Walter Bender
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# You should have received a copy of the GNU General Public License
+# along with this library; if not, write to the Free Software
+# Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
+
+
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GdkPixbuf
+from gi.repository import GObject
+
+import subprocess
+import os
+
+from sugar3.activity import activity
+from sugar3 import profile
+from sugar3 import env
+
+from sugar3.graphics.toolbarbox import ToolbarBox
+from sugar3.activity.widgets import ActivityToolbarButton
+from sugar3.activity.widgets import StopButton
+from sugar3.graphics.alert import Alert
+
+from toolbar_utils import (button_factory, separator_factory)
+from gettext import gettext as _
+
+import logging
+_logger = logging.getLogger("share-favorites")
+
+import json
+
+import telepathy
+from dbus.service import signal
+from dbus.gobject_service import ExportedGObject
+from sugar3.presence import presenceservice
+from sugar3.presence.tubeconn import TubeConnection
+
+
+SERVICE = 'org.sugarlabs.ShareFavorites'
+IFACE = SERVICE
+PATH = '/org/sugarlabs/ShareFavorites'
+
+
+class ShareFavorites(activity.Activity):
+ ''' Share desktop favorites '''
+
+ def __init__(self, handle):
+ ''' Initialize the toolbars and the work surface '''
+ super(ShareFavorites, self).__init__(handle)
+
+ self._buddies = [profile.get_nick_name()]
+ self._colors = profile.get_color().to_string().split(',')
+ self._my_colors = self._colors[:] # Save original colors
+ self.initiating = None # sharing (True) or joining (False)
+
+ self._first_time = True
+
+ self.old_cursor = self.get_window().get_cursor()
+
+ self._setup_toolbars()
+ self._setup_canvas()
+
+ self._setup_presence_service()
+
+ def _setup_canvas(self):
+ ''' Create a canvas '''
+ self.fixed = Gtk.Fixed()
+ self.fixed.show()
+ self.set_canvas(self.fixed)
+
+ self.vbox = Gtk.VBox(False, 0)
+ self.vbox.set_size_request(Gdk.Screen.width(), Gdk.Screen.height())
+ self.fixed.put(self.vbox, 0, 0)
+ self.vbox.show()
+
+ self._canvas = Gtk.DrawingArea()
+ self._canvas.set_size_request(int(Gdk.Screen.width()),
+ int(Gdk.Screen.height()))
+ self._canvas.show()
+ self.show_all()
+ self.vbox.pack_end(self._canvas, True, True, 0)
+ self.vbox.show()
+
+ def _setup_toolbars(self):
+ ''' Setup the toolbars. '''
+ self.max_participants = 25 # sharing
+
+ toolbox = ToolbarBox()
+
+ # Activity toolbar
+ activity_button_toolbar = ActivityToolbarButton(self)
+
+ toolbox.toolbar.insert(activity_button_toolbar, 0)
+ activity_button_toolbar.show()
+
+ self.set_toolbar_box(toolbox)
+ toolbox.show()
+ self.toolbar = toolbox.toolbar
+
+ separator_factory(toolbox.toolbar, True, False)
+
+ stop_button = StopButton(self)
+ stop_button.props.accelerator = '<Ctrl>q'
+ toolbox.toolbar.insert(stop_button, -1)
+ stop_button.show()
+
+ toolbox.toolbar.show_all()
+
+ def _restore_cursor(self):
+ ''' No longer waiting, so restore standard cursor. '''
+ if not hasattr(self, 'get_window'):
+ return
+ self.get_window().set_cursor(self.old_cursor)
+
+ def _waiting_cursor(self):
+ ''' Waiting, so set watch cursor. '''
+ if not hasattr(self, 'get_window'):
+ return
+ self.old_cursor = self.get_window().get_cursor()
+ self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
+
+ def _dump(self, favorites):
+ ''' Dump favorites for sharing. '''
+ _logger.debug('dumping %s' % (json.dumps(favorites)))
+ return json.dumps(favorites)
+
+ def _load(self, data):
+ ''' Load favorites from a sharer. '''
+ favorites = json.loads(data)
+
+ # When favorites are shared, the sharer sends out list; joiners
+ # receive the list.
+ def _read_favorites(self):
+ favorites_path = os.path.join(env.get_profile_path(),
+ 'favorite_activities')
+ logging.debug('read favorities: %s' % (favorites_path))
+ fd = open(favorites_path, 'r')
+ data = fd.read()
+ fd.close()
+ return self._dump(data)
+
+ def _save_favorites(self, favorites):
+ favorites_path = os.path.join(env.get_profile_path(),
+ 'favorite_activities')
+ logging.debug('save favorities: %s' % (favorites_path))
+ fd = open(favorites_path, 'w')
+ fd.write(favorites)
+ fd.close()
+
+ def _setup_presence_service(self):
+ ''' Setup the Presence Service. '''
+ self.pservice = presenceservice.get_instance()
+
+ owner = self.pservice.get_owner()
+ self.owner = owner
+ self.buddies = [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...'''
+ if self.get_shared_activity() is None:
+ _logger.error('Failed to share or join activity ... \
+ shared_activity is null in _shared_cb()')
+ return
+
+ self.initiating = True
+ self.waiting = False
+ _logger.debug('I am sharing...')
+
+ 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)
+
+ _logger.debug('This is my activity: making a tube...')
+ id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
+ SERVICE, {})
+
+ self._share_favorites() # delete me
+
+ def _joined_cb(self, activity):
+ ''' ...or join an exisiting share. '''
+ if self.get_shared_activity() is None:
+ _logger.error('Failed to share or join activity ... \
+ shared_activity is null in _shared_cb()')
+ return
+
+ self.initiating = False
+ _logger.debug('I joined a shared activity.')
+
+ 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)
+
+ _logger.debug('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)
+
+ self.waiting = True
+ self._waiting_cursor()
+
+ 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. '''
+ _logger.error('ListTubes() failed: %s', e)
+
+ def _new_tube_cb(self, id, initiator, type, service, params, state):
+ ''' Create a new tube. '''
+ _logger.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 == 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 event_received_cb(self, text):
+ ''' Data is passed as tuples: cmd:text '''
+ dispatch_table = {'F': self._update_favorites,
+ 'f': self._share_favorites,
+ }
+ _logger.debug('<<< %s' % (text[0]))
+ dispatch_table[text[0]](text[2:])
+
+ def _new_join(self, data):
+ if self.initiating:
+ self._share_favorites()
+
+ def _update_favorites(self, data):
+ favorites = self._dump(data)
+ self._save_favorites(favorities)
+ self._restore_cursor()
+ # TODO: Update homeview
+
+ def _share_favorites(self):
+ if self.initiating:
+ _logger.debug('sharing favorites')
+ self._send_event('F:%s' % (self._read_favorites()))
+
+ def _send_event(self, text):
+ ''' Send event through the tube. '''
+ if hasattr(self, 'chattube') and self.chattube is not None:
+ _logger.debug('>>> %s' % (text[0]))
+ self.chattube.SendText(text)
+
+
+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