Web · Wiki · Activities · Blog · Lists · Chat · Meeting · Bugs · Git · Translate · Archive · People · Donate
8940fcb by Walter Bender at 2012-06-10 1
#Copyright (c) 2011-12 Walter Bender
17f4cb2 by Walter Bender at 2011-02-02 2
#Copyright (c) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
3
4
#Permission is hereby granted, free of charge, to any person obtaining a copy
5
#of this software and associated documentation files (the "Software"), to deal
6
#in the Software without restriction, including without limitation the rights
7
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
#copies of the Software, and to permit persons to whom the Software is
9
#furnished to do so, subject to the following conditions:
10
11
#The above copyright notice and this permission notice shall be included in
12
#all copies or substantial portions of the Software.
13
14
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
#THE SOFTWARE.
1d8d277 by Raul Gutierrez Segales at 2011-01-25 21
22
from dbus.service import signal
23
from dbus.gobject_service import ExportedGObject
24
import telepathy
8940fcb by Walter Bender at 2012-06-10 25
import os
e059c63 by Walter Bender at 2011-02-06 26
import gtk
27
214a4d6 by Walter Bender at 2012-06-10 28
from gettext import gettext as _
29
f5d12fa by Walter Bender at 2013-05-22 30
from TurtleArt.tautils import (data_to_string, data_from_string, get_path,
31
                               base64_to_image, debug_output, error_output)
b0ef86c by Walter Bender at 2011-02-12 32
from TurtleArt.taconstants import DEFAULT_TURTLE_COLORS
5c39670 by Raul Gutierrez Segales at 2011-01-31 33
34
try:
35
    from sugar import profile
36
    from sugar.presence import presenceservice
37
    from sugar.presence.tubeconn import TubeConnection
38
except:
39
    profile = None
40
    from collaboration import presenceservice
41
    from collaboration.tubeconn import TubeConnection
1d8d277 by Raul Gutierrez Segales at 2011-01-25 42
43
SERVICE = 'org.laptop.TurtleArtActivity'
44
IFACE = SERVICE
45
PATH = '/org/laptop/TurtleArtActivity'
46
fa5daec by Walter Bender at 2011-02-02 47
1d8d277 by Raul Gutierrez Segales at 2011-01-25 48
class Collaboration():
49
    def __init__(self, tw, activity):
50
        """ A simplistic sharing model: the sharer is the master """
51
        self._tw = tw
02d6433 by Raul Gutierrez Segales at 2011-01-31 52
        self._tw.send_event = self.send_event
36f997b by Walter Bender at 2011-03-14 53
        self._tw.remote_turtle_dictionary = {}
1d8d277 by Raul Gutierrez Segales at 2011-01-25 54
        self._activity = activity
5206ca8 by Raul Gutierrez Segales at 2011-02-06 55
        self._setup_dispatch_table()
1d8d277 by Raul Gutierrez Segales at 2011-01-25 56
57
    def setup(self):
8940fcb by Walter Bender at 2012-06-10 58
        # TODO: hand off role of master if sharer leaves
1d8d277 by Raul Gutierrez Segales at 2011-01-25 59
        self.pservice = presenceservice.get_instance()
fa5daec by Walter Bender at 2011-02-02 60
        self.initiating = None  # sharing (True) or joining (False)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 61
62
        # Add my buddy object to the list
63
        owner = self.pservice.get_owner()
64
        self.owner = owner
b79011d by Walter Bender at 2011-01-25 65
        self._tw.buddies.append(self.owner)
7f56a04 by Walter Bender at 2011-02-22 66
        self._share = ''
1d8d277 by Raul Gutierrez Segales at 2011-01-25 67
        self._activity.connect('shared', self._shared_cb)
68
        self._activity.connect('joined', self._joined_cb)
69
5206ca8 by Raul Gutierrez Segales at 2011-02-06 70
    def _setup_dispatch_table(self):
71
        self._processing_methods = {
70537d1 by Walter Bender at 2011-02-11 72
            't': self._turtle_request,
73
            'T': self._receive_turtle_dict,
863f605 by Walter Bender at 2012-07-20 74
            'R': self._reskin_turtle,
70537d1 by Walter Bender at 2011-02-11 75
            'f': self._move_forward,
76
            'a': self._move_in_arc,
77
            'r': self._rotate_turtle,
78
            'x': self._setxy,
79
            'W': self._draw_text,
80
            'c': self._set_pen_color,
81
            'g': self._set_pen_gray_level,
82
            's': self._set_pen_shade,
83
            'w': self._set_pen_width,
84
            'p': self._set_pen_state,
85
            'F': self._fill_polygon,
8940fcb by Walter Bender at 2012-06-10 86
            'P': self._draw_pixbuf,
c135302 by Walter Bender at 2012-06-10 87
            'B': self._paste,
8940fcb by Walter Bender at 2012-06-10 88
            'S': self._speak
f5d12fa by Walter Bender at 2013-05-22 89
        }
5206ca8 by Raul Gutierrez Segales at 2011-02-06 90
1d8d277 by Raul Gutierrez Segales at 2011-01-25 91
    def _shared_cb(self, activity):
e2b1aa8 by Walter Bender at 2013-02-23 92
        self._shared_activity = self._activity.get_shared_activity()
1d8d277 by Raul Gutierrez Segales at 2011-01-25 93
        if self._shared_activity is None:
7f56a04 by Walter Bender at 2011-02-22 94
            debug_output('Failed to share or join activity ... \
95
                _shared_activity is null in _shared_cb()',
96
                         self._tw.running_sugar)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 97
            return
98
725ac09 by Raul Gutierrez Segales at 2011-02-02 99
        self._tw.set_sharing(True)
100
1d8d277 by Raul Gutierrez Segales at 2011-01-25 101
        self.initiating = True
102
        self.waiting_for_turtles = False
36f997b by Walter Bender at 2011-03-14 103
        self._tw.remote_turtle_dictionary = self._get_dictionary()
f5d12fa by Walter Bender at 2013-05-22 104
7f56a04 by Walter Bender at 2011-02-22 105
        debug_output('I am sharing...', self._tw.running_sugar)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 106
107
        self.conn = self._shared_activity.telepathy_conn
108
        self.tubes_chan = self._shared_activity.telepathy_tubes_chan
109
        self.text_chan = self._shared_activity.telepathy_text_chan
110
111
        self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
112
            'NewTube', self._new_tube_cb)
113
7f56a04 by Walter Bender at 2011-02-22 114
        debug_output('This is my activity: making a tube...',
115
                     self._tw.running_sugar)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 116
d7b874d by Walter Bender at 2013-02-10 117
        self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
1d8d277 by Raul Gutierrez Segales at 2011-01-25 118
            SERVICE, {})
8940fcb by Walter Bender at 2012-06-10 119
        self._enable_share_button()
1d8d277 by Raul Gutierrez Segales at 2011-01-25 120
121
    def _joined_cb(self, activity):
e2b1aa8 by Walter Bender at 2013-02-23 122
        self._shared_activity = self._activity.get_shared_activity()
1d8d277 by Raul Gutierrez Segales at 2011-01-25 123
        if self._shared_activity is None:
7f56a04 by Walter Bender at 2011-02-22 124
            debug_output('Failed to share or join activity ... \
125
                _shared_activity is null in _shared_cb()',
126
                         self._tw.running_sugar)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 127
            return
128
725ac09 by Raul Gutierrez Segales at 2011-02-02 129
        self._tw.set_sharing(True)
130
1d8d277 by Raul Gutierrez Segales at 2011-01-25 131
        self.initiating = False
132
        self.conn = self._shared_activity.telepathy_conn
133
        self.tubes_chan = self._shared_activity.telepathy_tubes_chan
134
        self.text_chan = self._shared_activity.telepathy_text_chan
135
136
        # call back for "NewTube" signal
137
        self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
138
            'NewTube', self._new_tube_cb)
139
7f56a04 by Walter Bender at 2011-02-22 140
        debug_output('I am joining an activity: waiting for a tube...',
141
                     self._tw.running_sugar)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 142
        self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
143
            reply_handler=self._list_tubes_reply_cb,
144
            error_handler=self._list_tubes_error_cb)
145
146
        # Joiner should request current state from sharer.
147
        self.waiting_for_turtles = True
8940fcb by Walter Bender at 2012-06-10 148
        self._enable_share_button()
149
150
    def _enable_share_button(self):
151
        self._activity.share_button.set_icon('shareon')
ade7604 by Walter Bender at 2012-06-11 152
        self._activity.share_button.set_tooltip(_('Share selected blocks'))
1d8d277 by Raul Gutierrez Segales at 2011-01-25 153
154
    def _list_tubes_reply_cb(self, tubes):
155
        for tube_info in tubes:
156
            self._new_tube_cb(*tube_info)
157
158
    def _list_tubes_error_cb(self, e):
7f56a04 by Walter Bender at 2011-02-22 159
        error_output('ListTubes() failed: %s' % (e), self._tw.running_sugar)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 160
161
    def _new_tube_cb(self, id, initiator, type, service, params, state):
162
        """ Create a new tube. """
7f56a04 by Walter Bender at 2011-02-22 163
        debug_output('New tube: ID=%d initator=%d type=%d service=%s \
164
                     params=%r state=%d' % (id, initiator, type, service,
165
                     params, state), self._tw.running_sugar)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 166
167
        if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE):
168
            if state == telepathy.TUBE_STATE_LOCAL_PENDING:
f5d12fa by Walter Bender at 2013-05-22 169
                self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES]\
170
                    .AcceptDBusTube(id)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 171
f5d12fa by Walter Bender at 2013-05-22 172
            tube_conn = TubeConnection(
173
                self.conn,
174
                self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES],
175
                id,
1d8d277 by Raul Gutierrez Segales at 2011-01-25 176
                group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
177
178
            # We'll use a chat tube to send serialized stacks back and forth.
f5d12fa by Walter Bender at 2013-05-22 179
            self.chattube = ChatTube(tube_conn, self.initiating,
180
                                     self.event_received_cb)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 181
182
            # Now that we have the tube, we can ask for the turtle dictionary.
36f997b by Walter Bender at 2011-03-14 183
            if self.waiting_for_turtles:  # A joiner must wait for turtles.
7f56a04 by Walter Bender at 2011-02-22 184
                debug_output('Sending a request for the turtle dictionary',
185
                             self._tw.running_sugar)
36f997b by Walter Bender at 2011-03-14 186
                # We need to send our own nick, colors, and turtle position
1d8d277 by Raul Gutierrez Segales at 2011-01-25 187
                colors = self._get_colors()
7f56a04 by Walter Bender at 2011-02-22 188
                event = 't|' + data_to_string([self._get_nick(), colors])
189
                debug_output(event, self._tw.running_sugar)
1d8d277 by Raul Gutierrez Segales at 2011-01-25 190
                self.send_event(event)
191
5206ca8 by Raul Gutierrez Segales at 2011-02-06 192
    def event_received_cb(self, event_message):
1d8d277 by Raul Gutierrez Segales at 2011-01-25 193
        """
194
        Events are sent as a tuple, nick|cmd, where nick is a turle name
195
        and cmd is a turtle event. Everyone gets the turtle dictionary from
196
        the sharer and watches for 't' events, which indicate that a new
197
        turtle has joined.
198
        """
5206ca8 by Raul Gutierrez Segales at 2011-02-06 199
        if len(event_message) == 0:
1d8d277 by Raul Gutierrez Segales at 2011-01-25 200
            return
70537d1 by Walter Bender at 2011-02-11 201
5206ca8 by Raul Gutierrez Segales at 2011-02-06 202
       # Save active Turtle
0dda146 by Walter Bender at 2013-06-25 203
        save_active_turtle = self._tw.turtles.get_active_turtle()
70537d1 by Walter Bender at 2011-02-11 204
0c5dff2 by Walter Bender at 2011-02-10 205
        try:
7f56a04 by Walter Bender at 2011-02-22 206
            command, payload = event_message.split('|', 2)
0c5dff2 by Walter Bender at 2011-02-10 207
        except ValueError:
807ca1d by Walter Bender at 2012-06-30 208
            debug_output('Could not split event message [%s]' % event_message,
7f56a04 by Walter Bender at 2011-02-22 209
                         self._tw.running_sugar)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 210
889cfbf by Walter Bender at 2012-06-30 211
        self._processing_methods[command](payload)
212
1d8d277 by Raul Gutierrez Segales at 2011-01-25 213
        # Restore active Turtle
0dda146 by Walter Bender at 2013-06-25 214
        self._tw.turtles.set_turtle(
f5d12fa by Walter Bender at 2013-05-22 215
            self._tw.turtles.get_turtle_key(save_active_turtle))
1d8d277 by Raul Gutierrez Segales at 2011-01-25 216
217
    def send_event(self, entry):
218
        """ Send event through the tube. """
219
        if hasattr(self, 'chattube') and self.chattube is not None:
220
            self.chattube.SendText(entry)
221
5206ca8 by Raul Gutierrez Segales at 2011-02-06 222
    def _turtle_request(self, payload):
36f997b by Walter Bender at 2011-03-14 223
        ''' incoming turtle from a joiner '''
5206ca8 by Raul Gutierrez Segales at 2011-02-06 224
        if payload > 0:
225
            [nick, colors] = data_from_string(payload)
36f997b by Walter Bender at 2011-03-14 226
            if nick != self._tw.nick:  # It is not me.
5206ca8 by Raul Gutierrez Segales at 2011-02-06 227
                # There may not be a turtle dictionary.
36f997b by Walter Bender at 2011-03-14 228
                if hasattr(self._tw, 'remote_turtle_dictionary'):
c66c065 by Walter Bender at 2011-03-17 229
                    # Make sure it is not a "rejoin".
230
                    if not nick in self._tw.remote_turtle_dictionary:
231
                        # Add new turtle for the joiner.
0dda146 by Walter Bender at 2013-06-25 232
                        self._tw.turtles.set_turtle(nick, colors)
c66c065 by Walter Bender at 2011-03-17 233
                        self._tw.label_remote_turtle(nick, colors)
36f997b by Walter Bender at 2011-03-14 234
                    self._tw.remote_turtle_dictionary[nick] = colors
5206ca8 by Raul Gutierrez Segales at 2011-02-06 235
                else:
36f997b by Walter Bender at 2011-03-14 236
                    self._tw.remote_turtle_dictionary = self._get_dictionary()
c66c065 by Walter Bender at 2011-03-17 237
                    # Add new turtle for the joiner.
0dda146 by Walter Bender at 2013-06-25 238
                    self._tw.turtles.set_turtle(nick, colors)
c66c065 by Walter Bender at 2011-03-17 239
                    self._tw.label_remote_turtle(nick, colors)
36f997b by Walter Bender at 2011-03-14 240
241
        # Sharer should send the updated remote turtle dictionary to everyone.
5206ca8 by Raul Gutierrez Segales at 2011-02-06 242
        if self.initiating:
36f997b by Walter Bender at 2011-03-14 243
            if not self._tw.nick in self._tw.remote_turtle_dictionary:
244
                self._tw.remote_turtle_dictionary[self._tw.nick] = \
245
                    self._get_colors()
246
            event_payload = data_to_string(self._tw.remote_turtle_dictionary)
7f56a04 by Walter Bender at 2011-02-22 247
            self.send_event('T|' + event_payload)
4e75964 by Walter Bender at 2011-10-07 248
            self.send_my_xy()  # And the sender should report her xy position.
5206ca8 by Raul Gutierrez Segales at 2011-02-06 249
250
    def _receive_turtle_dict(self, payload):
36f997b by Walter Bender at 2011-03-14 251
        ''' Any time there is a new joiner, an updated turtle dictionary is
86389de by Walter Bender at 2011-03-14 252
        circulated. Everyone must report their turtle positions so that we
253
        are in sync. '''
5206ca8 by Raul Gutierrez Segales at 2011-02-06 254
        if self.waiting_for_turtles:
255
            if len(payload) > 0:
36f997b by Walter Bender at 2011-03-14 256
                # Grab the new remote turtles dictionary.
257
                remote_turtle_dictionary = data_from_string(payload)
258
                # Add see what is new.
259
                for nick in remote_turtle_dictionary:
260
                    if nick == self._tw.nick:
f5d12fa by Walter Bender at 2013-05-22 261
                        debug_output('skipping my nick %s' %
262
                                     (nick), self._tw.running_sugar)
36f997b by Walter Bender at 2011-03-14 263
                    elif nick != self._tw.remote_turtle_dictionary:
264
                        # Add new the turtle.
265
                        colors = remote_turtle_dictionary[nick]
266
                        self._tw.remote_turtle_dictionary[nick] = colors
0dda146 by Walter Bender at 2013-06-25 267
                        self._tw.turtles.set_turtle(nick, colors)
36f997b by Walter Bender at 2011-03-14 268
                        # Label the remote turtle.
269
                        self._tw.label_remote_turtle(nick, colors)
f5d12fa by Walter Bender at 2013-05-22 270
                        debug_output('adding %s to remote turtle dictionary' %
271
                                     (nick), self._tw.running_sugar)
36f997b by Walter Bender at 2011-03-14 272
                    else:
f5d12fa by Walter Bender at 2013-05-22 273
                        debug_output('%s already in remote turtle dictionary' %
274
                                     (nick), self._tw.running_sugar)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 275
            self.waiting_for_turtles = False
4e75964 by Walter Bender at 2011-10-07 276
        self.send_my_xy()
86389de by Walter Bender at 2011-03-14 277
4e75964 by Walter Bender at 2011-10-07 278
    def send_my_xy(self):
279
        ''' Set xy location so joiner can sync turtle positions. Should be
280
        used to sync positions after turtle drag. '''
0dda146 by Walter Bender at 2013-06-25 281
        self._tw.turtles.set_turtle(self._get_nick())
c8f0b79 by Walter Bender at 2013-06-26 282
        if self._tw.turtles.get_active_turtle().get_pen_state():
86389de by Walter Bender at 2011-03-14 283
            self.send_event('p|%s' % (data_to_string([self._get_nick(),
284
                                                      False])))
285
            put_pen_back_down = True
286
        else:
287
            put_pen_back_down = False
0dda146 by Walter Bender at 2013-06-25 288
        self.send_event('x|%s' % (data_to_string(
c8f0b79 by Walter Bender at 2013-06-26 289
                    [self._get_nick(),
290
                     [int(self._tw.turtles.get_active_turtle().get_xy()[0]),
291
                      int(self._tw.turtles.get_active_turtle().get_xy()[1])]])))
86389de by Walter Bender at 2011-03-14 292
        if put_pen_back_down:
293
            self.send_event('p|%s' % (data_to_string([self._get_nick(),
294
                                                      True])))
0dda146 by Walter Bender at 2013-06-25 295
        self.send_event('r|%s' % (data_to_string(
c8f0b79 by Walter Bender at 2013-06-26 296
                    [self._get_nick(),
297
                     int(self._tw.turtles.get_active_turtle().get_heading())])))
4ac06b5 by Walter Bender at 2011-02-10 298
863f605 by Walter Bender at 2012-07-20 299
    def _reskin_turtle(self, payload):
300
        if len(payload) > 0:
301
            [nick, [width, height, data]] = data_from_string(payload)
302
            if nick != self._tw.nick:
303
                if self._tw.running_sugar:
304
                    tmp_path = get_path(self._tw.activity, 'instance')
305
                else:
306
                    tmp_path = '/tmp'
307
                file_name = base64_to_image(data, tmp_path)
308
                pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(file_name,
309
                                                              width, height)
0dda146 by Walter Bender at 2013-06-25 310
                self._tw.turtles.set_turtle(nick)
311
                self._tw.turtles.get_active_turtle().set_shapes([pixbuf])
863f605 by Walter Bender at 2012-07-20 312
e059c63 by Walter Bender at 2011-02-06 313
    def _draw_pixbuf(self, payload):
314
        if len(payload) > 0:
0f6ec14 by Walter Bender at 2011-02-07 315
            [nick, [a, b, x, y, w, h, width, height, data]] =\
316
                data_from_string(payload)
e059c63 by Walter Bender at 2011-02-06 317
            if nick != self._tw.nick:
4ac06b5 by Walter Bender at 2011-02-10 318
                if self._tw.running_sugar:
319
                    tmp_path = get_path(self._tw.activity, 'instance')
0f6ec14 by Walter Bender at 2011-02-07 320
                else:
321
                    tmp_path = '/tmp'
322
                file_name = base64_to_image(data, tmp_path)
323
                pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(file_name,
324
                                                              width, height)
0dda146 by Walter Bender at 2013-06-25 325
                pos = self._tw.turtles.turtle_to_screen_coordinates((x, y))
326
                self._tw.turtles.get_active_turtle().draw_pixbuf(
327
                    pixbuf, a, b, pos[0], pos[1], w, h, file_name, False)
e059c63 by Walter Bender at 2011-02-06 328
5206ca8 by Raul Gutierrez Segales at 2011-02-06 329
    def _move_forward(self, payload):
330
        if len(payload) > 0:
331
            [nick, x] = data_from_string(payload)
332
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 333
                self._tw.turtles.set_turtle(nick)
334
                self._tw.turtles.get_active_turtle().forward(x, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 335
336
    def _move_in_arc(self, payload):
337
        if len(payload) > 0:
338
            [nick, [a, r]] = data_from_string(payload)
339
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 340
                self._tw.turtles.set_turtle(nick)
341
                self._tw.turtles.get_active_turtle().arc(a, r, False)
70537d1 by Walter Bender at 2011-02-11 342
5206ca8 by Raul Gutierrez Segales at 2011-02-06 343
    def _rotate_turtle(self, payload):
344
        if len(payload) > 0:
345
            [nick, h] = data_from_string(payload)
346
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 347
                self._tw.turtles.set_turtle(nick)
348
                self._tw.turtles.get_active_turtle().set_heading(h, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 349
350
    def _setxy(self, payload):
351
        if len(payload) > 0:
352
            [nick, [x, y]] = data_from_string(payload)
353
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 354
                self._tw.turtles.set_turtle(nick)
355
                self._tw.turtles.get_active_turtle().set_xy(x, y, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 356
357
    def _draw_text(self, payload):
358
        if len(payload) > 0:
359
            [nick, [label, x, y, size, w]] = data_from_string(payload)
360
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 361
                self._tw.turtles.get_active_turtle().draw_text(
362
                    label, x, y, size, w, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 363
364
    def _set_pen_color(self, payload):
365
        if len(payload) > 0:
366
            [nick, x] = data_from_string(payload)
367
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 368
                self._tw.turtles.set_turtle(nick)
369
                self._tw.turtles.get_active_turtle().set_color(x, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 370
371
    def _set_pen_gray_level(self, payload):
372
        if len(payload) > 0:
373
            [nick, x] = data_from_string(payload)
374
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 375
                self._tw.turtles.set_turtle(nick)
376
                self._tw.turtles.get_active_turtle().set_gray(x, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 377
378
    def _set_pen_shade(self, payload):
379
        if len(payload) > 0:
380
            [nick, x] = data_from_string(payload)
381
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 382
                self._tw.turtles.set_turtle(nick)
383
                self._tw.turtles.get_active_turtle().set_shade(x, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 384
385
    def _set_pen_width(self, payload):
386
        if len(payload) > 0:
387
            [nick, x] = data_from_string(payload)
388
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 389
                self._tw.turtles.set_turtle(nick)
390
                self._tw.turtles.get_active_turtle().set_pen_size(x, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 391
392
    def _set_pen_state(self, payload):
393
        if len(payload) > 0:
394
            [nick, x] = data_from_string(payload)
395
            if nick != self._tw.nick:
0dda146 by Walter Bender at 2013-06-25 396
                self._tw.turtles.set_turtle(nick)
397
                self._tw.turtles.get_active_turtle().set_pen_state(x, False)
5206ca8 by Raul Gutierrez Segales at 2011-02-06 398
3f35b22 by Walter Bender at 2011-02-09 399
    def _fill_polygon(self, payload):
400
        if len(payload) > 0:
81adace by Walter Bender at 2011-02-10 401
            [nick, poly_points] = data_from_string(payload)
402
            shared_poly_points = []
403
            for i in range(len(poly_points)):
f5d12fa by Walter Bender at 2013-05-22 404
                shared_poly_points.append(
0dda146 by Walter Bender at 2013-06-25 405
                    (self._tw.turtles.turtle_to_screen_coordinates
f5d12fa by Walter Bender at 2013-05-22 406
                     (poly_points[i][0], poly_points[i][1])))
0dda146 by Walter Bender at 2013-06-25 407
            if nick != self._tw.nick:
408
                self._tw.turtles.set_turtle(nick)
409
                self._tw.turtles.get_active_turtle().set_poly_points(
410
                    shared_poly_points)
411
                self._tw.turtles.get_active_turtle().stop_fill(False)
3f35b22 by Walter Bender at 2011-02-09 412
8940fcb by Walter Bender at 2012-06-10 413
    def _speak(self, payload):
414
        if len(payload) > 0:
415
            [nick, language_option, text] = data_from_string(payload)
416
            if language_option == 'None':
417
                language_option = ''
418
            if text is not None:
f5d12fa by Walter Bender at 2013-05-22 419
                os.system('espeak %s "%s" --stdout | aplay' %
420
                          (language_option, str(text)))
8940fcb by Walter Bender at 2012-06-10 421
422
    def _paste(self, payload):
423
        if len(payload) > 0:
424
            [nick, text] = data_from_string(payload)
425
            if text is not None:
426
                self._tw.process_data(data_from_string(text),
427
                                      self._tw.paste_offset)
428
                self._tw.paste_offset += 20
429
1d8d277 by Raul Gutierrez Segales at 2011-01-25 430
    def _get_dictionary(self):
36f997b by Walter Bender at 2011-03-14 431
        return {self._get_nick(): self._get_colors()}
1d8d277 by Raul Gutierrez Segales at 2011-01-25 432
433
    def _get_nick(self):
b79011d by Walter Bender at 2011-01-25 434
        return self._tw.nick
1d8d277 by Raul Gutierrez Segales at 2011-01-25 435
436
    def _get_colors(self):
b6a21d3 by Walter Bender at 2011-02-07 437
        colors = None
2de8750 by Walter Bender at 2011-02-10 438
        if self._tw.running_sugar:
b6a21d3 by Walter Bender at 2011-02-07 439
            if profile.get_color() is not None:
440
                colors = profile.get_color().to_string()
5c39670 by Raul Gutierrez Segales at 2011-01-31 441
        else:
442
            colors = self._activity.get_colors()
903a461 by Walter Bender at 2011-02-06 443
        if colors is None:
b0ef86c by Walter Bender at 2011-02-12 444
            colors = '%s,%s' % (DEFAULT_TURTLE_COLORS[0],
445
                                DEFAULT_TURTLE_COLORS[1])
36f997b by Walter Bender at 2011-03-14 446
        return colors.split(',')
1d8d277 by Raul Gutierrez Segales at 2011-01-25 447
fa5daec by Walter Bender at 2011-02-02 448
1d8d277 by Raul Gutierrez Segales at 2011-01-25 449
class ChatTube(ExportedGObject):
450
451
    def __init__(self, tube, is_initiator, stack_received_cb):
452
        """Class for setting up tube for sharing."""
453
        super(ChatTube, self).__init__(tube, PATH)
454
        self.tube = tube
fa5daec by Walter Bender at 2011-02-02 455
        self.is_initiator = is_initiator  # Are we sharing or joining activity?
1d8d277 by Raul Gutierrez Segales at 2011-01-25 456
        self.stack_received_cb = stack_received_cb
457
        self.stack = ''
458
f5d12fa by Walter Bender at 2013-05-22 459
        self.tube.add_signal_receiver(self.send_stack_cb, 'SendText', IFACE,
460
                                      path=PATH, sender_keyword='sender')
1d8d277 by Raul Gutierrez Segales at 2011-01-25 461
462
    def send_stack_cb(self, text, sender=None):
463
        if sender == self.tube.get_unique_name():
464
            return
465
        self.stack = text
466
        self.stack_received_cb(text)
467
468
    @signal(dbus_interface=IFACE, signature='s')
469
    def SendText(self, text):
470
        self.stack = text