2007-04-10 04:47:37 +02:00
|
|
|
"""Base class for Python-coded activities
|
|
|
|
|
|
|
|
This is currently the only reference for what an
|
|
|
|
activity must do to participate in the Sugar desktop.
|
|
|
|
"""
|
2007-06-24 14:43:48 +02:00
|
|
|
# Copyright (C) 2006-2007 Red Hat, Inc.
|
2006-10-15 01:08:44 +02:00
|
|
|
#
|
|
|
|
# This library is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
|
|
# License as published by the Free Software Foundation; either
|
|
|
|
# version 2 of the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This library 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
|
|
|
|
# Lesser General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
|
|
# License along with this library; if not, write to the
|
|
|
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
# Boston, MA 02111-1307, USA.
|
|
|
|
|
2007-06-04 19:35:05 +02:00
|
|
|
from gettext import gettext as _
|
2006-08-11 17:05:06 +02:00
|
|
|
import logging
|
2007-02-22 17:27:00 +01:00
|
|
|
import os
|
2007-05-10 11:01:32 +02:00
|
|
|
import time
|
2007-06-04 19:35:05 +02:00
|
|
|
import tempfile
|
2006-08-09 18:29:33 +02:00
|
|
|
|
2007-04-27 22:07:38 +02:00
|
|
|
import gtk, gobject
|
2007-06-15 18:03:17 +02:00
|
|
|
import dbus
|
2007-06-27 23:12:32 +02:00
|
|
|
|
|
|
|
from sugar import util
|
2007-04-09 20:40:56 +02:00
|
|
|
from sugar.presence import presenceservice
|
2007-02-21 20:15:39 +01:00
|
|
|
from sugar.activity.activityservice import ActivityService
|
2007-07-31 14:56:05 +02:00
|
|
|
from sugar.graphics import style
|
2007-02-27 15:05:44 +01:00
|
|
|
from sugar.graphics.window import Window
|
2007-04-27 10:51:19 +02:00
|
|
|
from sugar.graphics.toolbox import Toolbox
|
|
|
|
from sugar.graphics.toolbutton import ToolButton
|
2007-07-24 11:29:14 +02:00
|
|
|
from sugar.graphics.toolcombobox import ToolComboBox
|
2007-05-10 11:01:32 +02:00
|
|
|
from sugar.datastore import datastore
|
2007-06-01 21:21:30 +02:00
|
|
|
from sugar import wm
|
2007-05-10 11:01:32 +02:00
|
|
|
from sugar import profile
|
2007-06-29 22:11:28 +02:00
|
|
|
from sugar import _sugarext
|
2007-04-27 10:51:19 +02:00
|
|
|
|
|
|
|
class ActivityToolbar(gtk.Toolbar):
|
2007-07-24 11:29:14 +02:00
|
|
|
SHARE_PRIVATE = 0
|
|
|
|
SHARE_NEIGHBORHOOD = 1
|
|
|
|
|
2007-04-27 10:51:19 +02:00
|
|
|
def __init__(self, activity):
|
|
|
|
gtk.Toolbar.__init__(self)
|
|
|
|
|
|
|
|
self._activity = activity
|
2007-04-27 22:07:38 +02:00
|
|
|
activity.connect('shared', self._activity_shared_cb)
|
2007-05-03 05:25:15 +02:00
|
|
|
activity.connect('joined', self._activity_shared_cb)
|
2007-08-16 17:32:29 +02:00
|
|
|
activity.connect('notify::max_participants',
|
|
|
|
self._max_participants_changed_cb)
|
2007-04-27 10:51:19 +02:00
|
|
|
|
2007-05-29 15:53:58 +02:00
|
|
|
if activity.metadata:
|
2007-05-14 19:27:35 +02:00
|
|
|
self.title = gtk.Entry()
|
|
|
|
self.title.set_size_request(int(gtk.gdk.screen_width() / 6), -1)
|
2007-05-29 15:53:58 +02:00
|
|
|
self.title.set_text(activity.metadata['title'])
|
2007-06-18 20:38:20 +02:00
|
|
|
self.title.connect('changed', self._title_changed_cb)
|
2007-05-14 19:27:35 +02:00
|
|
|
self._add_widget(self.title)
|
|
|
|
|
2007-05-29 15:53:58 +02:00
|
|
|
activity.metadata.connect('updated', self._jobject_updated_cb)
|
2007-05-14 19:27:35 +02:00
|
|
|
|
|
|
|
separator = gtk.SeparatorToolItem()
|
|
|
|
separator.props.draw = False
|
|
|
|
separator.set_expand(True);
|
|
|
|
self.insert(separator, -1)
|
|
|
|
separator.show()
|
2007-04-27 22:07:38 +02:00
|
|
|
|
2007-07-24 11:29:14 +02:00
|
|
|
self.share = ToolComboBox(label_text='Share with:')
|
|
|
|
self.share.combo.connect('changed', self._share_changed_cb)
|
2007-07-25 15:05:07 +02:00
|
|
|
self.share.combo.append_item(None, _('Private'),
|
|
|
|
'theme:zoom-home-mini')
|
|
|
|
self.share.combo.append_item(None, _('My Neighborhood'),
|
|
|
|
'theme:zoom-neighborhood-mini')
|
2007-07-24 11:29:14 +02:00
|
|
|
self.insert(self.share, -1)
|
|
|
|
self.share.show()
|
|
|
|
|
2007-08-16 20:43:05 +02:00
|
|
|
self._update_share()
|
|
|
|
|
2007-07-10 15:18:08 +02:00
|
|
|
self.keep = ToolButton('document-save')
|
|
|
|
self.keep.set_tooltip(_('Keep'))
|
|
|
|
self.keep.connect('clicked', self._keep_clicked_cb)
|
|
|
|
self.insert(self.keep, -1)
|
|
|
|
self.keep.show()
|
2007-06-22 14:11:39 +02:00
|
|
|
|
2007-07-10 16:09:21 +02:00
|
|
|
self.stop = ToolButton('activity-stop')
|
2007-07-10 15:18:08 +02:00
|
|
|
self.stop.set_tooltip(_('Stop'))
|
|
|
|
self.stop.connect('clicked', self._stop_clicked_cb)
|
|
|
|
self.insert(self.stop, -1)
|
|
|
|
self.stop.show()
|
2007-05-10 11:01:32 +02:00
|
|
|
|
2007-06-18 20:38:20 +02:00
|
|
|
self._update_title_sid = None
|
|
|
|
|
2007-07-24 11:29:14 +02:00
|
|
|
def _update_share(self):
|
2007-08-16 20:43:05 +02:00
|
|
|
if self._activity.props.max_participants == 1:
|
|
|
|
self.share.hide()
|
|
|
|
|
|
|
|
if self._activity.get_shared():
|
2007-07-24 11:29:14 +02:00
|
|
|
self.share.set_sensitive(False)
|
|
|
|
self.share.combo.set_active(self.SHARE_NEIGHBORHOOD)
|
2007-08-16 17:55:52 +02:00
|
|
|
else:
|
2007-07-24 11:29:14 +02:00
|
|
|
self.share.set_sensitive(True)
|
|
|
|
self.share.combo.set_active(self.SHARE_PRIVATE)
|
|
|
|
|
|
|
|
def _share_changed_cb(self, combo):
|
|
|
|
if self.share.combo.get_active() == self.SHARE_NEIGHBORHOOD:
|
|
|
|
self._activity.share()
|
2007-05-15 11:23:46 +02:00
|
|
|
|
2007-07-10 15:18:08 +02:00
|
|
|
def _keep_clicked_cb(self, button):
|
2007-06-22 14:11:39 +02:00
|
|
|
self._activity.save()
|
|
|
|
|
2007-07-10 15:18:08 +02:00
|
|
|
def _stop_clicked_cb(self, button):
|
2007-05-15 11:23:46 +02:00
|
|
|
self._activity.close()
|
2007-06-19 15:51:56 +02:00
|
|
|
self._activity.destroy()
|
2007-05-15 11:23:46 +02:00
|
|
|
|
2007-05-10 11:01:32 +02:00
|
|
|
def _jobject_updated_cb(self, jobject):
|
|
|
|
self.title.set_text(jobject['title'])
|
|
|
|
|
2007-06-18 20:38:20 +02:00
|
|
|
def _title_changed_cb(self, entry):
|
|
|
|
if not self._update_title_sid:
|
|
|
|
self._update_title_sid = gobject.timeout_add(1000, self._update_title_cb)
|
|
|
|
|
|
|
|
def _update_title_cb(self):
|
|
|
|
self._activity.metadata['title'] = self.title.get_text()
|
|
|
|
self._activity.metadata['title_set_by_user'] = '1'
|
|
|
|
self._activity.save()
|
|
|
|
self._update_title_sid = None
|
|
|
|
return False
|
2007-05-10 11:01:32 +02:00
|
|
|
|
|
|
|
def _add_widget(self, widget, expand=False):
|
|
|
|
tool_item = gtk.ToolItem()
|
|
|
|
tool_item.set_expand(expand)
|
|
|
|
|
|
|
|
tool_item.add(widget)
|
|
|
|
widget.show()
|
|
|
|
|
|
|
|
self.insert(tool_item, -1)
|
|
|
|
tool_item.show()
|
2007-04-27 22:07:38 +02:00
|
|
|
|
|
|
|
def _activity_shared_cb(self, activity):
|
2007-07-24 11:29:14 +02:00
|
|
|
self._update_share()
|
2007-04-27 10:51:19 +02:00
|
|
|
|
2007-08-16 17:32:29 +02:00
|
|
|
def _max_participants_changed_cb(self, activity, pspec):
|
|
|
|
self._update_share()
|
|
|
|
|
2007-04-30 18:59:55 +02:00
|
|
|
class EditToolbar(gtk.Toolbar):
|
|
|
|
def __init__(self):
|
|
|
|
gtk.Toolbar.__init__(self)
|
|
|
|
|
|
|
|
self.undo = ToolButton('edit-undo')
|
|
|
|
self.insert(self.undo, -1)
|
|
|
|
self.undo.show()
|
|
|
|
|
|
|
|
self.redo = ToolButton('edit-redo')
|
|
|
|
self.insert(self.redo, -1)
|
|
|
|
self.redo.show()
|
|
|
|
|
|
|
|
separator = gtk.SeparatorToolItem()
|
|
|
|
separator.set_draw(True)
|
|
|
|
self.insert(separator, -1)
|
|
|
|
separator.show()
|
|
|
|
|
|
|
|
self.copy = ToolButton('edit-copy')
|
|
|
|
self.insert(self.copy, -1)
|
|
|
|
self.copy.show()
|
|
|
|
|
|
|
|
self.paste = ToolButton('edit-paste')
|
|
|
|
self.insert(self.paste, -1)
|
|
|
|
self.paste.show()
|
|
|
|
|
2007-04-27 10:51:19 +02:00
|
|
|
class ActivityToolbox(Toolbox):
|
|
|
|
def __init__(self, activity):
|
|
|
|
Toolbox.__init__(self)
|
|
|
|
|
2007-04-27 22:07:38 +02:00
|
|
|
self._activity_toolbar = ActivityToolbar(activity)
|
|
|
|
self.add_toolbar('Activity', self._activity_toolbar)
|
|
|
|
self._activity_toolbar.show()
|
|
|
|
|
|
|
|
def get_activity_toolbar(self):
|
|
|
|
return self._activity_toolbar
|
2006-08-09 15:53:10 +02:00
|
|
|
|
2007-02-27 15:05:44 +01:00
|
|
|
class Activity(Window, gtk.Container):
|
2006-12-04 20:12:24 +01:00
|
|
|
"""Base Activity class that all other Activities derive from."""
|
2007-02-27 15:05:44 +01:00
|
|
|
__gtype_name__ = 'SugarActivity'
|
2007-04-27 22:07:38 +02:00
|
|
|
|
|
|
|
__gsignals__ = {
|
2007-05-03 05:25:15 +02:00
|
|
|
'shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
|
|
|
|
'joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
|
2007-04-27 22:07:38 +02:00
|
|
|
}
|
|
|
|
|
2007-05-16 21:30:49 +02:00
|
|
|
__gproperties__ = {
|
2007-08-16 17:55:52 +02:00
|
|
|
'active' : (bool, None, None, False,
|
|
|
|
gobject.PARAM_READWRITE),
|
|
|
|
'max-participants': (int, None, None, 0, 1000, 0,
|
|
|
|
gobject.PARAM_READWRITE)
|
2007-05-16 21:30:49 +02:00
|
|
|
}
|
|
|
|
|
2007-05-10 11:01:32 +02:00
|
|
|
def __init__(self, handle, create_jobject=True):
|
2007-04-10 04:47:37 +02:00
|
|
|
"""Initialise the Activity
|
|
|
|
|
|
|
|
handle -- sugar.activity.activityhandle.ActivityHandle
|
|
|
|
instance providing the activity id and access to the
|
|
|
|
presence service which *may* provide sharing for this
|
|
|
|
application
|
2007-05-10 11:01:32 +02:00
|
|
|
|
|
|
|
create_jobject -- boolean
|
|
|
|
define if it should create a journal object if we are
|
|
|
|
not resuming
|
|
|
|
|
2007-04-10 04:47:37 +02:00
|
|
|
Side effects:
|
|
|
|
|
|
|
|
Sets the gdk screen DPI setting (resolution) to the
|
|
|
|
Sugar screen resolution.
|
|
|
|
|
|
|
|
Connects our "destroy" message to our _destroy_cb
|
|
|
|
method.
|
|
|
|
|
|
|
|
Creates a base gtk.Window within this window.
|
|
|
|
|
|
|
|
Creates an ActivityService (self._bus) servicing
|
|
|
|
this application.
|
|
|
|
"""
|
2007-02-27 15:05:44 +01:00
|
|
|
Window.__init__(self)
|
2006-12-04 20:12:24 +01:00
|
|
|
|
2007-06-27 23:12:32 +02:00
|
|
|
# process titles will only show 15 characters
|
|
|
|
# but they get truncated anyway so if more characters
|
|
|
|
# are supported in the future we will get a better view
|
|
|
|
# of the processes
|
|
|
|
proc_title = "%s <%s>" % (get_bundle_name(), handle.activity_id)
|
|
|
|
util.set_proc_title(proc_title)
|
|
|
|
|
2007-06-01 21:21:30 +02:00
|
|
|
self.connect('realize', self._realize_cb)
|
2007-06-19 15:51:56 +02:00
|
|
|
self.connect('delete-event', self._delete_event_cb)
|
2006-12-04 20:12:24 +01:00
|
|
|
|
2007-05-16 21:30:49 +02:00
|
|
|
self._active = False
|
2007-02-22 00:57:49 +01:00
|
|
|
self._activity_id = handle.activity_id
|
2007-04-09 20:40:56 +02:00
|
|
|
self._pservice = presenceservice.get_instance()
|
2007-05-03 05:25:15 +02:00
|
|
|
self._shared_activity = None
|
|
|
|
self._share_id = None
|
|
|
|
self._join_id = None
|
2007-06-28 12:03:12 +02:00
|
|
|
self._can_close = True
|
2007-07-06 22:43:16 +02:00
|
|
|
self._preview = None
|
2007-07-23 13:45:46 +02:00
|
|
|
self._updating_jobject = False
|
|
|
|
self._closing = False
|
2007-08-16 17:55:52 +02:00
|
|
|
self._max_participants = 0
|
2007-05-03 05:25:15 +02:00
|
|
|
|
|
|
|
shared_activity = handle.get_shared_activity()
|
|
|
|
if shared_activity:
|
|
|
|
# Join an existing instance of this activity on the network
|
|
|
|
self._shared_activity = shared_activity
|
|
|
|
self._join_id = self._shared_activity.connect("joined", self._internal_joined_cb)
|
|
|
|
if not self._shared_activity.props.joined:
|
|
|
|
self._shared_activity.join()
|
|
|
|
else:
|
2007-05-09 16:05:17 +02:00
|
|
|
self._internal_joined_cb(self._shared_activity, True, None)
|
2007-02-22 00:57:49 +01:00
|
|
|
|
2007-02-21 20:15:39 +01:00
|
|
|
self._bus = ActivityService(self)
|
2007-07-20 19:50:49 +02:00
|
|
|
self._owns_file = False
|
2006-12-04 20:12:24 +01:00
|
|
|
|
2007-05-10 11:01:32 +02:00
|
|
|
if handle.object_id:
|
2007-05-29 15:53:58 +02:00
|
|
|
self._jobject = datastore.get(handle.object_id)
|
2007-06-29 20:24:22 +02:00
|
|
|
# TODO: Don't create so many objects until we have versioning
|
|
|
|
# support in the datastore
|
|
|
|
#self._jobject.object_id = ''
|
|
|
|
#del self._jobject.metadata['ctime']
|
2007-05-29 15:53:58 +02:00
|
|
|
del self._jobject.metadata['mtime']
|
2007-05-10 11:01:32 +02:00
|
|
|
elif create_jobject:
|
|
|
|
logging.debug('Creating a jobject.')
|
2007-05-29 15:53:58 +02:00
|
|
|
self._jobject = datastore.create()
|
2007-06-04 19:35:05 +02:00
|
|
|
self._jobject.metadata['title'] = _('%s Activity') % get_bundle_name()
|
2007-06-18 20:38:20 +02:00
|
|
|
self._jobject.metadata['title_set_by_user'] = '0'
|
2007-06-03 22:12:47 +02:00
|
|
|
self._jobject.metadata['activity'] = self.get_service_name()
|
2007-07-20 13:15:11 +02:00
|
|
|
self._jobject.metadata['activity_id'] = self.get_id()
|
2007-05-29 15:53:58 +02:00
|
|
|
self._jobject.metadata['keep'] = '0'
|
2007-07-13 13:20:44 +02:00
|
|
|
#self._jobject.metadata['buddies'] = ''
|
2007-05-29 15:53:58 +02:00
|
|
|
self._jobject.metadata['preview'] = ''
|
|
|
|
self._jobject.metadata['icon-color'] = profile.get_color().to_string()
|
|
|
|
self._jobject.file_path = ''
|
|
|
|
datastore.write(self._jobject,
|
2007-05-16 06:41:45 +02:00
|
|
|
reply_handler=self._internal_jobject_create_cb,
|
|
|
|
error_handler=self._internal_jobject_error_cb)
|
2007-05-10 11:01:32 +02:00
|
|
|
else:
|
2007-05-29 15:53:58 +02:00
|
|
|
self._jobject = None
|
2007-05-10 11:01:32 +02:00
|
|
|
|
2007-05-16 21:30:49 +02:00
|
|
|
def do_set_property(self, pspec, value):
|
|
|
|
if pspec.name == 'active':
|
|
|
|
if self._active != value:
|
|
|
|
self._active = value
|
2007-05-29 15:53:58 +02:00
|
|
|
if not self._active and self._jobject:
|
2007-05-16 21:30:49 +02:00
|
|
|
self.save()
|
2007-08-16 17:55:52 +02:00
|
|
|
elif pspec.name == 'max-participants':
|
|
|
|
self._max_participants = value
|
2007-05-16 21:30:49 +02:00
|
|
|
|
|
|
|
def do_get_property(self, pspec):
|
|
|
|
if pspec.name == 'active':
|
|
|
|
return self._active
|
2007-08-16 17:32:29 +02:00
|
|
|
elif pspec.name == 'max-participants':
|
|
|
|
return self._max_participants
|
2007-05-16 21:30:49 +02:00
|
|
|
|
2007-06-03 22:12:47 +02:00
|
|
|
def get_id(self):
|
|
|
|
return self._activity_id
|
|
|
|
|
|
|
|
def get_service_name(self):
|
2007-06-29 22:11:28 +02:00
|
|
|
return _sugarext.get_prgname()
|
2007-06-03 22:12:47 +02:00
|
|
|
|
2007-05-29 15:53:58 +02:00
|
|
|
def set_canvas(self, canvas):
|
|
|
|
Window.set_canvas(self, canvas)
|
|
|
|
canvas.connect('map', self._canvas_map_cb)
|
|
|
|
|
|
|
|
def _canvas_map_cb(self, canvas):
|
|
|
|
if self._jobject and self._jobject.file_path:
|
|
|
|
self.read_file(self._jobject.file_path)
|
|
|
|
|
2007-05-16 06:41:45 +02:00
|
|
|
def _internal_jobject_create_cb(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def _internal_jobject_error_cb(self, err):
|
|
|
|
logging.debug("Error creating activity datastore object: %s" % err)
|
|
|
|
|
2007-08-13 21:14:25 +02:00
|
|
|
def get_activity_root(self):
|
|
|
|
"""
|
|
|
|
Return the appropriate location in the fs where to store activity related
|
|
|
|
data that doesn't pertain to the current execution of the activity and
|
|
|
|
thus cannot go into the DataStore.
|
|
|
|
"""
|
|
|
|
if os.environ.has_key('SUGAR_ACTIVITY_ROOT') and \
|
|
|
|
os.environ['SUGAR_ACTIVITY_ROOT']:
|
|
|
|
return os.environ['SUGAR_ACTIVITY_ROOT']
|
|
|
|
else:
|
|
|
|
return '/'
|
|
|
|
|
2007-05-29 15:53:58 +02:00
|
|
|
def read_file(self, file_path):
|
2007-05-10 11:01:32 +02:00
|
|
|
"""
|
|
|
|
Subclasses implement this method if they support resuming objects from
|
2007-05-29 15:53:58 +02:00
|
|
|
the journal. 'file_path' is the file to read from.
|
2007-05-10 11:01:32 +02:00
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2007-05-29 15:53:58 +02:00
|
|
|
def write_file(self, file_path):
|
2007-05-10 11:01:32 +02:00
|
|
|
"""
|
|
|
|
Subclasses implement this method if they support saving data to objects
|
2007-05-29 15:53:58 +02:00
|
|
|
in the journal. 'file_path' is the file to write to.
|
2007-05-10 11:01:32 +02:00
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2007-05-16 06:41:45 +02:00
|
|
|
def _internal_save_cb(self):
|
2007-07-23 13:45:46 +02:00
|
|
|
self._updating_jobject = False
|
|
|
|
if self._closing:
|
|
|
|
self._cleanup_jobject()
|
|
|
|
self.destroy()
|
2007-05-16 06:41:45 +02:00
|
|
|
|
|
|
|
def _internal_save_error_cb(self, err):
|
2007-07-23 13:45:46 +02:00
|
|
|
self._updating_jobject = False
|
|
|
|
if self._closing:
|
|
|
|
self._cleanup_jobject()
|
|
|
|
self.destroy()
|
2007-05-16 06:41:45 +02:00
|
|
|
logging.debug("Error saving activity object to datastore: %s" % err)
|
|
|
|
|
2007-07-23 13:45:46 +02:00
|
|
|
def _cleanup_jobject(self):
|
|
|
|
if self._jobject:
|
|
|
|
if self._owns_file and os.path.isfile(self._jobject.file_path):
|
|
|
|
logging.debug('_cleanup_jobject: removing %r' % self._jobject.file_path)
|
|
|
|
os.remove(self._jobject.file_path)
|
|
|
|
self._owns_file = False
|
|
|
|
self._jobject.destroy()
|
|
|
|
self._jobject = None
|
|
|
|
|
2007-06-29 20:24:22 +02:00
|
|
|
def _get_preview(self):
|
2007-06-15 18:03:17 +02:00
|
|
|
preview_pixbuf = self.get_canvas_screenshot()
|
2007-07-11 11:02:43 +02:00
|
|
|
if preview_pixbuf is None:
|
|
|
|
return None
|
2007-07-31 14:56:05 +02:00
|
|
|
preview_pixbuf = preview_pixbuf.scale_simple(style.zoom(300),
|
|
|
|
style.zoom(225),
|
2007-06-15 18:03:17 +02:00
|
|
|
gtk.gdk.INTERP_BILINEAR)
|
|
|
|
|
|
|
|
# TODO: Find a way of taking a png out of the pixbuf without saving to a temp file.
|
2007-06-29 20:24:22 +02:00
|
|
|
# Impementing gtk.gdk.Pixbuf.save_to_buffer in pygtk would solve this.
|
2007-06-15 18:03:17 +02:00
|
|
|
fd, file_path = tempfile.mkstemp('.png')
|
|
|
|
del fd
|
|
|
|
preview_pixbuf.save(file_path, 'png')
|
|
|
|
f = open(file_path)
|
|
|
|
try:
|
|
|
|
preview_data = f.read()
|
|
|
|
finally:
|
|
|
|
f.close()
|
|
|
|
os.remove(file_path)
|
|
|
|
|
|
|
|
# TODO: Take this out when the datastore accepts binary data.
|
|
|
|
import base64
|
2007-06-29 20:24:22 +02:00
|
|
|
return base64.b64encode(preview_data)
|
|
|
|
|
|
|
|
def _get_buddies(self):
|
|
|
|
return ''
|
|
|
|
|
|
|
|
def save(self):
|
|
|
|
"""Request that the activity is saved to the Journal."""
|
2007-07-23 13:45:46 +02:00
|
|
|
|
|
|
|
if self._updating_jobject:
|
|
|
|
return
|
|
|
|
|
2007-07-13 13:20:44 +02:00
|
|
|
#self.metadata['buddies'] = self._get_buddies()
|
2007-07-06 22:43:16 +02:00
|
|
|
if self._preview is None:
|
|
|
|
self.metadata['preview'] = ''
|
|
|
|
else:
|
|
|
|
self.metadata['preview'] = self._preview
|
2007-05-10 11:01:32 +02:00
|
|
|
try:
|
2007-07-20 19:50:49 +02:00
|
|
|
if self._jobject.file_path:
|
|
|
|
self.write_file(self._jobject.file_path)
|
|
|
|
else:
|
|
|
|
file_path = os.path.join(tempfile.gettempdir(), '%i' % time.time())
|
|
|
|
self.write_file(file_path)
|
|
|
|
self._owns_file = True
|
|
|
|
self._jobject.file_path = file_path
|
2007-05-10 11:01:32 +02:00
|
|
|
except NotImplementedError:
|
2007-05-29 15:53:58 +02:00
|
|
|
pass
|
2007-07-23 13:45:46 +02:00
|
|
|
self._updating_jobject = True
|
2007-05-29 15:53:58 +02:00
|
|
|
datastore.write(self._jobject,
|
2007-05-16 06:41:45 +02:00
|
|
|
reply_handler=self._internal_save_cb,
|
|
|
|
error_handler=self._internal_save_error_cb)
|
2007-05-10 11:01:32 +02:00
|
|
|
|
2007-05-03 05:25:15 +02:00
|
|
|
def _internal_joined_cb(self, activity, success, err):
|
|
|
|
"""Callback when join has finished"""
|
|
|
|
self._shared_activity.disconnect(self._join_id)
|
|
|
|
self._join_id = None
|
|
|
|
if not success:
|
|
|
|
logging.debug("Failed to join activity: %s" % err)
|
|
|
|
return
|
|
|
|
self.present()
|
|
|
|
self.emit('joined')
|
|
|
|
|
2006-12-04 20:12:24 +01:00
|
|
|
def get_shared(self):
|
|
|
|
"""Returns TRUE if the activity is shared on the mesh."""
|
2007-05-03 05:25:15 +02:00
|
|
|
if not self._shared_activity:
|
|
|
|
return False
|
|
|
|
return self._shared_activity.props.joined
|
2006-12-04 20:12:24 +01:00
|
|
|
|
2007-05-03 05:25:15 +02:00
|
|
|
def _internal_share_cb(self, ps, success, activity, err):
|
|
|
|
self._pservice.disconnect(self._share_id)
|
|
|
|
self._share_id = None
|
|
|
|
if not success:
|
|
|
|
logging.debug('Share of activity %s failed: %s.' % (self._activity_id, err))
|
|
|
|
return
|
|
|
|
logging.debug('Share of activity %s successful.' % self._activity_id)
|
2007-05-09 17:32:16 +02:00
|
|
|
self._shared_activity = activity
|
2007-04-27 22:07:38 +02:00
|
|
|
self.emit('shared')
|
2006-12-20 00:53:27 +01:00
|
|
|
|
2006-12-04 20:12:24 +01:00
|
|
|
def share(self):
|
2007-04-13 22:27:58 +02:00
|
|
|
"""Request that the activity be shared on the network."""
|
2007-05-03 21:06:00 +02:00
|
|
|
if self._shared_activity and self._shared_activity.props.joined:
|
2007-05-03 05:25:15 +02:00
|
|
|
raise RuntimeError("Activity %s already shared." % self._activity_id)
|
|
|
|
logging.debug('Requesting share of activity %s.' % self._activity_id)
|
|
|
|
self._share_id = self._pservice.connect("activity-shared", self._internal_share_cb)
|
2007-04-13 22:27:58 +02:00
|
|
|
self._pservice.share_activity(self)
|
2006-12-04 20:12:24 +01:00
|
|
|
|
2007-06-01 21:21:30 +02:00
|
|
|
def _realize_cb(self, window):
|
2007-06-03 22:12:47 +02:00
|
|
|
wm.set_bundle_id(window.window, self.get_service_name())
|
2007-06-01 21:21:30 +02:00
|
|
|
wm.set_activity_id(window.window, self._activity_id)
|
|
|
|
|
2007-06-19 15:51:56 +02:00
|
|
|
def _delete_event_cb(self, window, event):
|
2007-06-28 12:03:12 +02:00
|
|
|
if self._can_close:
|
|
|
|
self.close()
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return True
|
2007-06-19 15:51:56 +02:00
|
|
|
|
|
|
|
def close(self):
|
2007-07-23 13:45:46 +02:00
|
|
|
self._closing = True
|
|
|
|
|
2006-12-04 20:12:24 +01:00
|
|
|
if self._bus:
|
|
|
|
del self._bus
|
|
|
|
self._bus = None
|
2007-05-03 05:25:15 +02:00
|
|
|
if self._shared_activity:
|
|
|
|
self._shared_activity.leave()
|
2007-02-22 15:55:07 +01:00
|
|
|
|
2007-07-06 22:43:16 +02:00
|
|
|
self._preview = self._get_preview()
|
2007-06-19 15:51:56 +02:00
|
|
|
self.save()
|
2007-07-23 13:45:46 +02:00
|
|
|
|
|
|
|
def destroy(self):
|
|
|
|
if self._updating_jobject:
|
|
|
|
# Delay destruction
|
|
|
|
self.hide()
|
|
|
|
else:
|
|
|
|
Window.destroy(self)
|
2007-04-27 22:07:38 +02:00
|
|
|
|
2007-05-29 15:53:58 +02:00
|
|
|
def get_metadata(self):
|
|
|
|
if self._jobject:
|
|
|
|
return self._jobject.metadata
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
metadata = property(get_metadata, None)
|
|
|
|
|
2007-05-14 19:56:06 +02:00
|
|
|
def get_bundle_name():
|
|
|
|
"""Return the bundle name for the current process' bundle
|
|
|
|
"""
|
2007-06-29 22:11:28 +02:00
|
|
|
return _sugarext.get_application_name()
|
2007-05-14 19:56:06 +02:00
|
|
|
|
2007-02-22 15:55:07 +01:00
|
|
|
def get_bundle_path():
|
2007-04-10 04:47:37 +02:00
|
|
|
"""Return the bundle path for the current process' bundle
|
|
|
|
"""
|
2007-02-23 17:08:37 +01:00
|
|
|
return os.environ['SUGAR_BUNDLE_PATH']
|
2007-06-27 23:12:32 +02:00
|
|
|
|